zenith_float_num/ieee_soft/
mod.rs1mod arith;
5mod array;
6mod convert;
7mod simd;
8
9use crate::defs::Error;
10use crate::RoundingMode;
11use crate::Sign;
12use arith::{
13 add_bits, cmp_bits, div_bits, fma_bits, frexp_bits, from_i32_bits, mul_bits, next_after,
14 next_down, next_up, sqrt_bits, sub_bits, unpack, Class, BIN32, BIN64,
15};
16use core::cmp::Ordering;
17use core::num::FpCategory;
18
19pub use array::{ExactNumArray, Ieee32Array, Ieee64Array};
20pub use simd::IEEE_SIMD_LANE_WIDTH;
21
22#[derive(Clone, Copy, Debug)]
24pub struct Ieee32(u32);
25
26#[derive(Clone, Copy, Debug)]
28pub struct Ieee64(u64);
29
30macro_rules! impl_ieee {
31 ($ty:ident, $bits:ty, $fmt:ident, $as_u64:ident, $from_u64:ident) => {
32 impl $ty {
33 pub const ZERO: Self = Self(0);
35
36 #[inline]
38 pub const fn from_bits(bits: $bits) -> Self {
39 Self(bits)
40 }
41
42 #[inline]
44 pub const fn to_bits(self) -> $bits {
45 self.0
46 }
47
48 fn raw(self) -> u64 {
49 $as_u64(self.0)
50 }
51
52 pub fn from_i32(n: i32) -> Self {
54 Self($from_u64(from_i32_bits(n, $fmt)))
55 }
56
57 pub fn classify(self) -> FpCategory {
59 match unpack(self.raw(), $fmt).class {
60 Class::Nan => FpCategory::Nan,
61 Class::Inf => FpCategory::Infinite,
62 Class::Zero => FpCategory::Zero,
63 Class::Sub => FpCategory::Subnormal,
64 Class::Norm => FpCategory::Normal,
65 }
66 }
67
68 pub fn is_nan(self) -> bool {
70 unpack(self.raw(), $fmt).class == Class::Nan
71 }
72
73 pub fn is_infinite(self) -> bool {
75 unpack(self.raw(), $fmt).class == Class::Inf
76 }
77
78 pub fn is_finite(self) -> bool {
80 !self.is_nan() && !self.is_infinite()
81 }
82
83 pub fn is_zero(self) -> bool {
85 unpack(self.raw(), $fmt).class == Class::Zero
86 }
87
88 pub fn is_subnormal(self) -> bool {
90 unpack(self.raw(), $fmt).class == Class::Sub
91 }
92
93 pub fn is_sign_negative(self) -> bool {
95 unpack(self.raw(), $fmt).sign
96 }
97
98 pub fn err(self) -> Option<Error> {
100 if self.is_nan() {
101 Some(Error::InvalidArgument)
102 } else {
103 None
104 }
105 }
106
107 pub fn add(self, rhs: Self) -> Self {
109 Self($from_u64(add_bits(self.raw(), rhs.raw(), $fmt)))
110 }
111
112 pub fn sub(self, rhs: Self) -> Self {
114 Self($from_u64(sub_bits(self.raw(), rhs.raw(), $fmt)))
115 }
116
117 pub fn mul(self, rhs: Self) -> Self {
119 Self($from_u64(mul_bits(self.raw(), rhs.raw(), $fmt)))
120 }
121
122 pub fn div(self, rhs: Self) -> Self {
124 Self($from_u64(div_bits(self.raw(), rhs.raw(), $fmt)))
125 }
126
127 pub fn sqrt(self) -> Self {
129 Self($from_u64(sqrt_bits(self.raw(), $fmt)))
130 }
131
132 pub fn mul_add(self, b: Self, c: Self) -> Self {
134 Self($from_u64(fma_bits(self.raw(), b.raw(), c.raw(), $fmt)))
135 }
136
137 pub fn next_up(self) -> Self {
139 Self($from_u64(next_up(self.raw(), $fmt)))
140 }
141
142 pub fn next_down(self) -> Self {
144 Self($from_u64(next_down(self.raw(), $fmt)))
145 }
146
147 pub fn next_after(self, other: Self) -> Self {
149 Self($from_u64(next_after(self.raw(), other.raw(), $fmt)))
150 }
151
152 pub fn frexp(self) -> (Self, i32) {
154 let (m, e) = frexp_bits(self.raw(), $fmt);
155 (Self($from_u64(m)), e)
156 }
157
158 pub fn neg(self) -> Self {
160 Self($from_u64(self.raw() ^ $fmt.sign_mask()))
161 }
162
163 pub fn abs(self) -> Self {
165 Self($from_u64(self.raw() & !$fmt.sign_mask()))
166 }
167
168 pub fn copysign(self, sign: Self) -> Self {
170 let mag = self.raw() & !$fmt.sign_mask();
171 let s = sign.raw() & $fmt.sign_mask();
172 Self($from_u64(mag | s))
173 }
174
175 pub fn sign(self) -> Option<Sign> {
177 if self.is_nan() {
178 None
179 } else if unpack(self.raw(), $fmt).sign {
180 Some(Sign::Neg)
181 } else {
182 Some(Sign::Pos)
183 }
184 }
185
186 pub fn cmp(self, other: Self) -> Option<Ordering> {
188 cmp_bits(self.raw(), other.raw(), $fmt).map(|d| {
189 if d < 0 {
190 Ordering::Less
191 } else if d > 0 {
192 Ordering::Greater
193 } else {
194 Ordering::Equal
195 }
196 })
197 }
198 }
199
200 impl PartialEq for $ty {
201 fn eq(&self, other: &Self) -> bool {
202 self.cmp(*other) == Some(Ordering::Equal)
203 }
204 }
205
206 impl core::ops::Add for $ty {
207 type Output = Self;
208 fn add(self, rhs: Self) -> Self {
209 $ty::add(self, rhs)
210 }
211 }
212 impl core::ops::Sub for $ty {
213 type Output = Self;
214 fn sub(self, rhs: Self) -> Self {
215 $ty::sub(self, rhs)
216 }
217 }
218 impl core::ops::Mul for $ty {
219 type Output = Self;
220 fn mul(self, rhs: Self) -> Self {
221 $ty::mul(self, rhs)
222 }
223 }
224 impl core::ops::Div for $ty {
225 type Output = Self;
226 fn div(self, rhs: Self) -> Self {
227 $ty::div(self, rhs)
228 }
229 }
230 impl core::ops::Neg for $ty {
231 type Output = Self;
232 fn neg(self) -> Self {
233 $ty::neg(self)
234 }
235 }
236 };
237}
238
239const fn u32_as_u64(x: u32) -> u64 {
240 x as u64
241}
242const fn u64_as_u64(x: u64) -> u64 {
243 x
244}
245const fn u64_as_u32(x: u64) -> u32 {
246 x as u32
247}
248const fn u64_id(x: u64) -> u64 {
249 x
250}
251
252impl_ieee!(Ieee32, u32, BIN32, u32_as_u64, u64_as_u32);
253impl_ieee!(Ieee64, u64, BIN64, u64_as_u64, u64_id);
254
255impl Ieee32 {
256 pub const NAN: Self = Self(0x7FC0_0000);
258 pub const INFINITY: Self = Self(0x7F80_0000);
260 pub const NEG_INFINITY: Self = Self(0xFF80_0000);
262 pub const NEG_ZERO: Self = Self(0x8000_0000);
264}
265
266impl Ieee64 {
267 pub const NAN: Self = Self(0x7FF8_0000_0000_0000);
269 pub const INFINITY: Self = Self(0x7FF0_0000_0000_0000);
271 pub const NEG_INFINITY: Self = Self(0xFFF0_0000_0000_0000);
273 pub const NEG_ZERO: Self = Self(0x8000_0000_0000_0000);
275}
276
277impl Ieee32 {
278 pub fn to_exact(self, p: usize) -> crate::ExactNum {
280 convert::to_exact(self.to_bits() as u64, BIN32, p)
281 }
282
283 pub fn from_exact(x: &crate::ExactNum) -> Self {
285 Self::from_bits(convert::from_exact(x, BIN32) as u32)
286 }
287
288 pub fn map_exact<F>(self, p: usize, _rm: RoundingMode, op: F) -> Self
290 where
291 F: FnOnce(&crate::ExactNum) -> crate::ExactNum,
292 {
293 Self::from_exact(&op(&self.to_exact(p)))
294 }
295}
296
297impl Ieee64 {
298 pub fn to_exact(self, p: usize) -> crate::ExactNum {
300 convert::to_exact(self.to_bits(), BIN64, p)
301 }
302
303 pub fn from_exact(x: &crate::ExactNum) -> Self {
305 Self::from_bits(convert::from_exact(x, BIN64))
306 }
307
308 pub fn map_exact<F>(self, p: usize, _rm: RoundingMode, op: F) -> Self
310 where
311 F: FnOnce(&crate::ExactNum) -> crate::ExactNum,
312 {
313 Self::from_exact(&op(&self.to_exact(p)))
314 }
315}
316
317#[cfg(test)]
318mod tests {
319 use super::*;
320
321 const ONE32: u32 = 0x3F80_0000;
322 const TWO32: u32 = 0x4000_0000;
323 const HALF32: u32 = 0x3F00_0000;
324 const THIRD32: u32 = 0x3EAA_AAAB;
325 const THREE32: u32 = 0x4040_0000;
326 const INF32: u32 = 0x7F80_0000;
327 const QNAN32: u32 = 0x7FC0_0000;
328
329 const ONE64: u64 = 0x3FF0_0000_0000_0000;
330 const TWO64: u64 = 0x4000_0000_0000_0000;
331 const HALF64: u64 = 0x3FE0_0000_0000_0000;
332 const THIRD64: u64 = 0x3FD5_5555_5555_5555;
333 const THREE64: u64 = 0x4008_0000_0000_0000;
334 const INF64: u64 = 0x7FF0_0000_0000_0000;
335 const QNAN64: u64 = 0x7FF8_0000_0000_0000;
336 const MONE64: u64 = 0xBFF0_0000_0000_0000;
337
338 #[test]
339 fn bin32_add_mul_div_bits() {
340 let one = Ieee32::from_bits(ONE32);
341 let two = Ieee32::from_bits(TWO32);
342 let half = Ieee32::from_bits(HALF32);
343 let three = Ieee32::from_bits(THREE32);
344 assert_eq!((one + one).to_bits(), TWO32);
345 assert_eq!((one + two).to_bits(), THREE32);
346 assert_eq!((two * half).to_bits(), ONE32);
347 assert_eq!((one / Ieee32::from_i32(3)).to_bits(), THIRD32);
348 assert_eq!((three - one).to_bits(), TWO32);
349 assert!(Ieee32::from_bits(0)
350 .add(Ieee32::from_bits(0x8000_0000))
351 .is_zero());
352 assert_eq!(Ieee32::from_i32(1).to_bits(), ONE32);
353 assert_eq!(Ieee32::from_i32(-1).to_bits(), 0xBF80_0000);
354 assert_eq!(one.sqrt().to_bits(), ONE32);
355 assert!((Ieee32::from_i32(-1).sqrt()).is_nan());
356 assert_eq!((one / Ieee32::ZERO).to_bits(), INF32);
357 assert!((Ieee32::ZERO / Ieee32::ZERO).is_nan());
358 assert_eq!(Ieee32::INFINITY.to_bits(), INF32);
359 assert_eq!(Ieee32::NAN.to_bits(), QNAN32);
360 let tiny = Ieee32::from_bits(1);
361 assert!(tiny.is_subnormal());
362 assert_eq!((tiny + tiny).to_bits(), 2);
363 }
364
365 #[test]
366 fn bin64_add_mul_div_bits() {
367 let one = Ieee64::from_bits(ONE64);
368 let two = Ieee64::from_bits(TWO64);
369 let half = Ieee64::from_bits(HALF64);
370 let three = Ieee64::from_bits(THREE64);
371 assert_eq!((one + one).to_bits(), TWO64);
372 assert_eq!((one + two).to_bits(), THREE64);
373 assert_eq!((two * half).to_bits(), ONE64);
374 assert_eq!((one / Ieee64::from_i32(3)).to_bits(), THIRD64);
375 assert_eq!((three - one).to_bits(), TWO64);
376 assert_eq!(Ieee64::from_i32(1).to_bits(), ONE64);
377 assert_eq!(Ieee64::from_i32(-1).to_bits(), MONE64);
378 assert_eq!(one.sqrt().to_bits(), ONE64);
379 assert_eq!(Ieee64::from_i32(4).sqrt().to_bits(), TWO64);
380 assert_eq!(two.sqrt().to_bits(), 0x3FF6_A09E_667F_3BCD);
382 assert_eq!((one / Ieee64::ZERO).to_bits(), INF64);
383 assert_eq!(Ieee64::INFINITY.to_bits(), INF64);
384 assert_eq!(Ieee64::NAN.to_bits(), QNAN64);
385 let tiny = Ieee64::from_bits(1);
386 assert!(tiny.is_subnormal());
387 assert_eq!((tiny + tiny).to_bits(), 2);
388 assert_eq!(one.mul_add(two, one).to_bits(), THREE64);
389 assert_eq!(one.neg().to_bits(), MONE64);
390 assert_eq!(Ieee64::ZERO.cmp(Ieee64::NEG_ZERO), Some(Ordering::Equal));
391 assert_eq!(one.next_up().next_down().to_bits(), ONE64);
392 let (m, e) = two.frexp();
393 assert_eq!(e, 2);
394 assert_eq!(m.to_bits(), HALF64);
395 }
396
397 #[test]
398 fn widen_roundtrip_one() {
399 let x = Ieee64::from_bits(ONE64);
400 let e = x.to_exact(64);
401 assert_eq!(Ieee64::from_exact(&e).to_bits(), ONE64);
402 let y = Ieee32::from_bits(ONE32);
403 assert_eq!(Ieee32::from_exact(&y.to_exact(64)).to_bits(), ONE32);
404 }
405}