num_order/
hash.rs
1use crate::NumHash;
11
12use core::hash::{Hash, Hasher};
13use num_modular::{FixedMersenneInt, ModularAbs, ModularInteger};
14
15type MInt = FixedMersenneInt<127, 1>;
17const M127: i128 = i128::MAX;
18const M127U: u128 = M127 as u128;
19const M127D: u128 = M127U + M127U;
20const HASH_INF: i128 = i128::MAX; const HASH_NEGINF: i128 = i128::MIN + 1; const HASH_NAN: i128 = i128::MIN; #[cfg(feature = "num-complex")]
25const PROOT: u128 = i32::MAX as u128; impl NumHash for i128 {
32 #[inline]
33 fn num_hash<H: Hasher>(&self, state: &mut H) {
34 const MINP1: i128 = i128::MIN + 1;
35 match *self {
36 i128::MAX | MINP1 => 0i128.hash(state),
37 i128::MIN => (-1i128).hash(state),
38 u => u.hash(state),
39 }
40 }
41}
42impl NumHash for u128 {
43 #[inline]
44 fn num_hash<H: Hasher>(&self, state: &mut H) {
45 match *self {
46 u128::MAX => 1i128.hash(state),
47 M127D => 0i128.hash(state),
48 u if u >= M127U => ((u - M127U) as i128).hash(state),
49 u => (u as i128).hash(state),
50 }
51 }
52}
53
54macro_rules! impl_hash_for_small_int {
56 ($($signed:ty)*) => ($(
57 impl NumHash for $signed {
58 #[inline]
59 fn num_hash<H: Hasher>(&self, state: &mut H) {
60 (&(*self as i128)).hash(state) }
62 }
63 )*);
64}
65impl_hash_for_small_int! { i8 i16 i32 i64 u8 u16 u32 u64}
66
67impl NumHash for usize {
68 #[inline]
69 fn num_hash<H: Hasher>(&self, state: &mut H) {
70 #[cfg(target_pointer_width = "32")]
71 return (&(*self as u32)).num_hash(state);
72 #[cfg(target_pointer_width = "64")]
73 return (&(*self as u64)).num_hash(state);
74 }
75}
76
77impl NumHash for isize {
78 #[inline]
79 fn num_hash<H: Hasher>(&self, state: &mut H) {
80 #[cfg(target_pointer_width = "32")]
81 return (&(*self as i32)).num_hash(state);
82 #[cfg(target_pointer_width = "64")]
83 return (&(*self as i64)).num_hash(state);
84 }
85}
86
87#[cfg(feature = "num-bigint")]
88mod _num_bigint {
89 use super::*;
90 use num_bigint::{BigInt, BigUint};
91 use num_traits::ToPrimitive;
92
93 impl NumHash for BigUint {
94 fn num_hash<H: Hasher>(&self, state: &mut H) {
95 (self % BigUint::from(M127U)).to_i128().unwrap().hash(state)
96 }
97 }
98 impl NumHash for BigInt {
99 fn num_hash<H: Hasher>(&self, state: &mut H) {
100 (self % BigInt::from(M127)).to_i128().unwrap().hash(state)
101 }
102 }
103}
104
105trait FloatHash {
107 fn fhash(&self) -> i128;
109}
110
111impl FloatHash for f32 {
112 fn fhash(&self) -> i128 {
113 let bits = self.to_bits();
114 let sign_bit = bits >> 31;
115 let mantissa_bits = bits & 0x7fffff;
116 let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
117
118 if exponent == 0xff {
119 if mantissa_bits != 0 {
121 HASH_NAN
123 } else if sign_bit > 0 {
124 HASH_NEGINF } else {
126 HASH_INF }
128 } else {
129 let mantissa = if exponent == 0 {
131 mantissa_bits << 1
132 } else {
133 mantissa_bits | 0x800000
134 };
135 exponent -= 0x7f + 23;
136
137 let mantissa = MInt::new(mantissa as u128, &M127U);
139 let pow = mantissa.convert(1 << exponent.absm(&127));
141 let v = mantissa * pow;
142 v.residue() as i128 * if sign_bit == 0 { 1 } else { -1 }
143 }
144 }
145}
146
147impl NumHash for f32 {
148 fn num_hash<H: Hasher>(&self, state: &mut H) {
149 self.fhash().num_hash(state)
150 }
151}
152
153impl FloatHash for f64 {
154 fn fhash(&self) -> i128 {
155 let bits = self.to_bits();
156 let sign_bit = bits >> 63;
157 let mantissa_bits = bits & 0xfffffffffffff;
158 let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
159
160 if exponent == 0x7ff {
161 if mantissa_bits != 0 {
163 HASH_NAN
165 } else if sign_bit > 0 {
166 HASH_NEGINF } else {
168 HASH_INF }
170 } else {
171 let mantissa = if exponent == 0 {
173 mantissa_bits << 1
174 } else {
175 mantissa_bits | 0x10000000000000
176 };
177 exponent -= 0x3ff + 52;
179
180 let mantissa = MInt::new(mantissa as u128, &M127U);
182 let pow = mantissa.convert(1 << exponent.absm(&127));
184 let v = mantissa * pow;
185 v.residue() as i128 * if sign_bit == 0 { 1 } else { -1 }
186 }
187 }
188}
189
190impl NumHash for f64 {
191 fn num_hash<H: Hasher>(&self, state: &mut H) {
192 self.fhash().num_hash(state)
193 }
194}
195
196#[cfg(feature = "num-rational")]
197mod _num_rational {
198 use super::*;
199 use core::ops::Neg;
200 use num_rational::Ratio;
201
202 macro_rules! impl_hash_for_ratio {
203 ($($int:ty)*) => ($(
204 impl NumHash for Ratio<$int> {
205 fn num_hash<H: Hasher>(&self, state: &mut H) {
206 let ub = *self.denom() as u128; let binv = if ub != M127U {
208 MInt::new(ub, &M127U).inv().unwrap()
209 } else {
210 return if self.numer() > &0 { HASH_INF.num_hash(state) } else { HASH_NEGINF.num_hash(state) }
212 };
213
214 let ua = if self.numer() < &0 { (*self.numer() as u128).wrapping_neg() } else { *self.numer() as u128 }; let ua = binv.convert(ua);
216 let ab = (ua * binv).residue() as i128;
217 if self.numer() >= &0 {
218 ab.num_hash(state)
219 } else {
220 ab.neg().num_hash(state)
221 }
222 }
223 }
224 )*);
225 }
226
227 impl_hash_for_ratio!(i8 i16 i32 i64 i128 isize);
228
229 #[cfg(feature = "num-bigint")]
230 mod _num_bigint {
231 use super::*;
232 use num_bigint::{BigInt, BigUint};
233 use num_traits::{Signed, ToPrimitive, Zero};
234
235 impl NumHash for Ratio<BigInt> {
236 fn num_hash<H: Hasher>(&self, state: &mut H) {
237 let ub = (self.denom().magnitude() % BigUint::from(M127U))
238 .to_u128()
239 .unwrap();
240 let binv = if !ub.is_zero() {
241 MInt::new(ub, &M127U).inv().unwrap()
242 } else {
243 return if self.numer().is_negative() {
245 HASH_NEGINF.num_hash(state)
246 } else {
247 HASH_INF.num_hash(state)
248 };
249 };
250
251 let ua = (self.numer().magnitude() % BigUint::from(M127U))
252 .to_u128()
253 .unwrap();
254 let ua = binv.convert(ua);
255 let ab = (ua * binv).residue() as i128;
256 if self.numer().is_negative() {
257 ab.neg().num_hash(state)
258 } else {
259 ab.num_hash(state)
260 }
261 }
262 }
263 }
264}
265
266#[cfg(feature = "num-complex")]
274mod _num_complex {
275 use super::*;
276 use num_complex::Complex;
277
278 macro_rules! impl_complex_hash_for_float {
279 ($($float:ty)*) => ($(
280 impl NumHash for Complex<$float> {
281 fn num_hash<H: Hasher>(&self, state: &mut H) {
282 let a = self.re.fhash();
283 let b = self.im.fhash();
284
285 let bterm = if b >= 0 {
286 let pb = MInt::new(b as u128, &M127U) * PROOT;
287 -((pb * pb).residue() as i128)
288 } else {
289 let pb = MInt::new((-b) as u128, &M127U) * PROOT;
290 (pb * pb).residue() as i128
291 };
292 (a + bterm).num_hash(state)
293 }
294 }
295 )*);
296 }
297 impl_complex_hash_for_float!(f32 f64);
298}