1 | //! Port of LLVM's APFloat software floating-point implementation from the |
2 | //! following C++ sources (please update commit hash when backporting): |
3 | //! https://github.com/llvm/llvm-project/commit/462a31f5a5abb905869ea93cc49b096079b11aa4 |
4 | //! * `llvm/include/llvm/ADT/APFloat.h` -> `Float` and `FloatConvert` traits |
5 | //! * `llvm/lib/Support/APFloat.cpp` -> `ieee` and `ppc` modules |
6 | //! * `llvm/unittests/ADT/APFloatTest.cpp` -> `tests` directory |
7 | //! |
8 | //! The port contains no unsafe code, global state, or side-effects in general, |
9 | //! and the only allocations are in the conversion to/from decimal strings. |
10 | //! |
11 | //! Most of the API and the testcases are intact in some form or another, |
12 | //! with some ergonomic changes, such as idiomatic short names, returning |
13 | //! new values instead of mutating the receiver, and having separate method |
14 | //! variants that take a non-default rounding mode (with the suffix `_r`). |
15 | //! Comments have been preserved where possible, only slightly adapted. |
16 | //! |
17 | //! Instead of keeping a pointer to a configuration struct and inspecting it |
18 | //! dynamically on every operation, types (e.g. `ieee::Double`), traits |
19 | //! (e.g. `ieee::Semantics`) and associated constants are employed for |
20 | //! increased type safety and performance. |
21 | //! |
22 | //! On-heap bigints are replaced everywhere (except in decimal conversion), |
23 | //! with short arrays of `type Limb = u128` elements (instead of `u64`), |
24 | //! This allows fitting the largest supported significands in one integer |
25 | //! (`ieee::Quad` and `ppc::Fallback` use slightly less than 128 bits). |
26 | //! All of the functions in the `ieee::sig` module operate on slices. |
27 | //! |
28 | //! # Note |
29 | //! |
30 | //! This API is completely unstable and subject to change. |
31 | |
32 | #![no_std ] |
33 | #![deny (warnings)] |
34 | #![forbid (unsafe_code)] |
35 | |
36 | #[macro_use ] |
37 | extern crate bitflags; |
38 | |
39 | extern crate alloc; |
40 | |
41 | use core::cmp::Ordering; |
42 | use core::fmt; |
43 | use core::ops::{Add, Div, Mul, Neg, Rem, Sub}; |
44 | use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign}; |
45 | use core::str::FromStr; |
46 | |
47 | bitflags! { |
48 | /// IEEE-754R 7: Default exception handling. |
49 | /// |
50 | /// UNDERFLOW or OVERFLOW are always returned or-ed with INEXACT. |
51 | /// |
52 | /// APFloat models this behavior specified by IEEE-754: |
53 | /// "For operations producing results in floating-point format, the default |
54 | /// result of an operation that signals the invalid operation exception |
55 | /// shall be a quiet NaN." |
56 | #[must_use ] |
57 | pub struct Status: u8 { |
58 | const OK = 0x00; |
59 | const INVALID_OP = 0x01; |
60 | const DIV_BY_ZERO = 0x02; |
61 | const OVERFLOW = 0x04; |
62 | const UNDERFLOW = 0x08; |
63 | const INEXACT = 0x10; |
64 | } |
65 | } |
66 | |
67 | #[must_use ] |
68 | #[derive (Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] |
69 | pub struct StatusAnd<T> { |
70 | pub status: Status, |
71 | pub value: T, |
72 | } |
73 | |
74 | impl Status { |
75 | pub fn and<T>(self, value: T) -> StatusAnd<T> { |
76 | StatusAnd { status: self, value } |
77 | } |
78 | } |
79 | |
80 | impl<T> StatusAnd<T> { |
81 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> StatusAnd<U> { |
82 | StatusAnd { |
83 | status: self.status, |
84 | value: f(self.value), |
85 | } |
86 | } |
87 | } |
88 | |
89 | #[macro_export ] |
90 | macro_rules! unpack { |
91 | ($status:ident|=, $e:expr) => { |
92 | match $e { |
93 | $crate::StatusAnd { status, value } => { |
94 | $status |= status; |
95 | value |
96 | } |
97 | } |
98 | }; |
99 | ($status:ident=, $e:expr) => { |
100 | match $e { |
101 | $crate::StatusAnd { status, value } => { |
102 | $status = status; |
103 | value |
104 | } |
105 | } |
106 | }; |
107 | } |
108 | |
109 | /// Category of internally-represented number. |
110 | #[derive (Copy, Clone, PartialEq, Eq, Debug)] |
111 | pub enum Category { |
112 | Infinity, |
113 | NaN, |
114 | Normal, |
115 | Zero, |
116 | } |
117 | |
118 | /// IEEE-754R 4.3: Rounding-direction attributes. |
119 | #[derive (Copy, Clone, PartialEq, Eq, Debug)] |
120 | pub enum Round { |
121 | NearestTiesToEven, |
122 | TowardPositive, |
123 | TowardNegative, |
124 | TowardZero, |
125 | NearestTiesToAway, |
126 | } |
127 | |
128 | impl Neg for Round { |
129 | type Output = Round; |
130 | #[inline ] |
131 | fn neg(self) -> Round { |
132 | match self { |
133 | Round::TowardPositive => Round::TowardNegative, |
134 | Round::TowardNegative => Round::TowardPositive, |
135 | Round::NearestTiesToEven | Round::TowardZero | Round::NearestTiesToAway => self, |
136 | } |
137 | } |
138 | } |
139 | |
140 | /// A signed type to represent a floating point number's unbiased exponent. |
141 | pub type ExpInt = i32; |
142 | |
143 | // \c ilogb error results. |
144 | pub const IEK_INF: ExpInt = ExpInt::max_value(); |
145 | pub const IEK_NAN: ExpInt = ExpInt::min_value(); |
146 | pub const IEK_ZERO: ExpInt = ExpInt::min_value() + 1; |
147 | |
148 | #[derive (Copy, Clone, PartialEq, Eq, Debug)] |
149 | pub struct ParseError(pub &'static str); |
150 | |
151 | /// A self-contained host- and target-independent arbitrary-precision |
152 | /// floating-point software implementation. |
153 | /// |
154 | /// `apfloat` uses significand bignum integer arithmetic as provided by functions |
155 | /// in the `ieee::sig`. |
156 | /// |
157 | /// Written for clarity rather than speed, in particular with a view to use in |
158 | /// the front-end of a cross compiler so that target arithmetic can be correctly |
159 | /// performed on the host. Performance should nonetheless be reasonable, |
160 | /// particularly for its intended use. It may be useful as a base |
161 | /// implementation for a run-time library during development of a faster |
162 | /// target-specific one. |
163 | /// |
164 | /// All 5 rounding modes in the IEEE-754R draft are handled correctly for all |
165 | /// implemented operations. Currently implemented operations are add, subtract, |
166 | /// multiply, divide, fused-multiply-add, conversion-to-float, |
167 | /// conversion-to-integer and conversion-from-integer. New rounding modes |
168 | /// (e.g. away from zero) can be added with three or four lines of code. |
169 | /// |
170 | /// Four formats are built-in: IEEE single precision, double precision, |
171 | /// quadruple precision, and x87 80-bit extended double (when operating with |
172 | /// full extended precision). Adding a new format that obeys IEEE semantics |
173 | /// only requires adding two lines of code: a declaration and definition of the |
174 | /// format. |
175 | /// |
176 | /// All operations return the status of that operation as an exception bit-mask, |
177 | /// so multiple operations can be done consecutively with their results or-ed |
178 | /// together. The returned status can be useful for compiler diagnostics; e.g., |
179 | /// inexact, underflow and overflow can be easily diagnosed on constant folding, |
180 | /// and compiler optimizers can determine what exceptions would be raised by |
181 | /// folding operations and optimize, or perhaps not optimize, accordingly. |
182 | /// |
183 | /// At present, underflow tininess is detected after rounding; it should be |
184 | /// straight forward to add support for the before-rounding case too. |
185 | /// |
186 | /// The library reads hexadecimal floating point numbers as per C99, and |
187 | /// correctly rounds if necessary according to the specified rounding mode. |
188 | /// Syntax is required to have been validated by the caller. |
189 | /// |
190 | /// It also reads decimal floating point numbers and correctly rounds according |
191 | /// to the specified rounding mode. |
192 | /// |
193 | /// Non-zero finite numbers are represented internally as a sign bit, a 16-bit |
194 | /// signed exponent, and the significand as an array of integer limbs. After |
195 | /// normalization of a number of precision P the exponent is within the range of |
196 | /// the format, and if the number is not denormal the P-th bit of the |
197 | /// significand is set as an explicit integer bit. For denormals the most |
198 | /// significant bit is shifted right so that the exponent is maintained at the |
199 | /// format's minimum, so that the smallest denormal has just the least |
200 | /// significant bit of the significand set. The sign of zeros and infinities |
201 | /// is significant; the exponent and significand of such numbers is not stored, |
202 | /// but has a known implicit (deterministic) value: 0 for the significands, 0 |
203 | /// for zero exponent, all 1 bits for infinity exponent. For NaNs the sign and |
204 | /// significand are deterministic, although not really meaningful, and preserved |
205 | /// in non-conversion operations. The exponent is implicitly all 1 bits. |
206 | /// |
207 | /// `apfloat` does not provide any exception handling beyond default exception |
208 | /// handling. We represent Signaling NaNs via IEEE-754R 2008 6.2.1 should clause |
209 | /// by encoding Signaling NaNs with the first bit of its trailing significand as |
210 | /// 0. |
211 | /// |
212 | /// Future work |
213 | /// =========== |
214 | /// |
215 | /// Some features that may or may not be worth adding: |
216 | /// |
217 | /// Optional ability to detect underflow tininess before rounding. |
218 | /// |
219 | /// New formats: x87 in single and double precision mode (IEEE apart from |
220 | /// extended exponent range) (hard). |
221 | /// |
222 | /// New operations: sqrt, nexttoward. |
223 | /// |
224 | pub trait Float: |
225 | Copy |
226 | + Default |
227 | + FromStr<Err = ParseError> |
228 | + PartialOrd |
229 | + fmt::Display |
230 | + Neg<Output = Self> |
231 | + AddAssign |
232 | + SubAssign |
233 | + MulAssign |
234 | + DivAssign |
235 | + RemAssign |
236 | + Add<Output = StatusAnd<Self>> |
237 | + Sub<Output = StatusAnd<Self>> |
238 | + Mul<Output = StatusAnd<Self>> |
239 | + Div<Output = StatusAnd<Self>> |
240 | + Rem<Output = StatusAnd<Self>> |
241 | { |
242 | /// Total number of bits in the in-memory format. |
243 | const BITS: usize; |
244 | |
245 | /// Number of bits in the significand. This includes the integer bit. |
246 | const PRECISION: usize; |
247 | |
248 | /// The largest E such that 2^E is representable; this matches the |
249 | /// definition of IEEE 754. |
250 | const MAX_EXP: ExpInt; |
251 | |
252 | /// The smallest E such that 2^E is a normalized number; this |
253 | /// matches the definition of IEEE 754. |
254 | const MIN_EXP: ExpInt; |
255 | |
256 | /// Positive Zero. |
257 | const ZERO: Self; |
258 | |
259 | /// Positive Infinity. |
260 | const INFINITY: Self; |
261 | |
262 | /// NaN (Not a Number). |
263 | // FIXME(eddyb) provide a default when qnan becomes const fn. |
264 | const NAN: Self; |
265 | |
266 | /// Factory for QNaN values. |
267 | // FIXME(eddyb) should be const fn. |
268 | fn qnan(payload: Option<u128>) -> Self; |
269 | |
270 | /// Factory for SNaN values. |
271 | // FIXME(eddyb) should be const fn. |
272 | fn snan(payload: Option<u128>) -> Self; |
273 | |
274 | /// Largest finite number. |
275 | // FIXME(eddyb) should be const (but FloatPair::largest is nontrivial). |
276 | fn largest() -> Self; |
277 | |
278 | /// Smallest (by magnitude) finite number. |
279 | /// Might be denormalized, which implies a relative loss of precision. |
280 | const SMALLEST: Self; |
281 | |
282 | /// Smallest (by magnitude) normalized finite number. |
283 | // FIXME(eddyb) should be const (but FloatPair::smallest_normalized is nontrivial). |
284 | fn smallest_normalized() -> Self; |
285 | |
286 | // Arithmetic |
287 | |
288 | fn add_r(self, rhs: Self, round: Round) -> StatusAnd<Self>; |
289 | fn sub_r(self, rhs: Self, round: Round) -> StatusAnd<Self> { |
290 | self.add_r(-rhs, round) |
291 | } |
292 | fn mul_r(self, rhs: Self, round: Round) -> StatusAnd<Self>; |
293 | fn mul_add_r(self, multiplicand: Self, addend: Self, round: Round) -> StatusAnd<Self>; |
294 | fn mul_add(self, multiplicand: Self, addend: Self) -> StatusAnd<Self> { |
295 | self.mul_add_r(multiplicand, addend, Round::NearestTiesToEven) |
296 | } |
297 | fn div_r(self, rhs: Self, round: Round) -> StatusAnd<Self>; |
298 | /// IEEE remainder. |
299 | fn ieee_rem(self, rhs: Self) -> StatusAnd<Self>; |
300 | /// C fmod, or llvm frem. |
301 | fn c_fmod(self, rhs: Self) -> StatusAnd<Self>; |
302 | fn round_to_integral(self, round: Round) -> StatusAnd<Self>; |
303 | |
304 | /// IEEE-754R 2008 5.3.1: nextUp. |
305 | fn next_up(self) -> StatusAnd<Self>; |
306 | |
307 | /// IEEE-754R 2008 5.3.1: nextDown. |
308 | /// |
309 | /// *NOTE* since nextDown(x) = -nextUp(-x), we only implement nextUp with |
310 | /// appropriate sign switching before/after the computation. |
311 | fn next_down(self) -> StatusAnd<Self> { |
312 | (-self).next_up().map(|r| -r) |
313 | } |
314 | |
315 | fn abs(self) -> Self { |
316 | if self.is_negative() { |
317 | -self |
318 | } else { |
319 | self |
320 | } |
321 | } |
322 | fn copy_sign(self, rhs: Self) -> Self { |
323 | if self.is_negative() != rhs.is_negative() { |
324 | -self |
325 | } else { |
326 | self |
327 | } |
328 | } |
329 | |
330 | // Conversions |
331 | fn from_bits(input: u128) -> Self; |
332 | fn from_i128_r(input: i128, round: Round) -> StatusAnd<Self> { |
333 | if input < 0 { |
334 | Self::from_u128_r(input.wrapping_neg() as u128, -round).map(|r| -r) |
335 | } else { |
336 | Self::from_u128_r(input as u128, round) |
337 | } |
338 | } |
339 | fn from_i128(input: i128) -> StatusAnd<Self> { |
340 | Self::from_i128_r(input, Round::NearestTiesToEven) |
341 | } |
342 | fn from_u128_r(input: u128, round: Round) -> StatusAnd<Self>; |
343 | fn from_u128(input: u128) -> StatusAnd<Self> { |
344 | Self::from_u128_r(input, Round::NearestTiesToEven) |
345 | } |
346 | fn from_str_r(s: &str, round: Round) -> Result<StatusAnd<Self>, ParseError>; |
347 | fn to_bits(self) -> u128; |
348 | |
349 | /// Convert a floating point number to an integer according to the |
350 | /// rounding mode. In case of an invalid operation exception, |
351 | /// deterministic values are returned, namely zero for NaNs and the |
352 | /// minimal or maximal value respectively for underflow or overflow. |
353 | /// If the rounded value is in range but the floating point number is |
354 | /// not the exact integer, the C standard doesn't require an inexact |
355 | /// exception to be raised. IEEE-854 does require it so we do that. |
356 | /// |
357 | /// Note that for conversions to integer type the C standard requires |
358 | /// round-to-zero to always be used. |
359 | /// |
360 | /// The *is_exact output tells whether the result is exact, in the sense |
361 | /// that converting it back to the original floating point type produces |
362 | /// the original value. This is almost equivalent to result==Status::OK, |
363 | /// except for negative zeroes. |
364 | fn to_i128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<i128> { |
365 | let status; |
366 | if self.is_negative() { |
367 | if self.is_zero() { |
368 | // Negative zero can't be represented as an int. |
369 | *is_exact = false; |
370 | } |
371 | let r = unpack!(status=, (-self).to_u128_r(width, -round, is_exact)); |
372 | |
373 | // Check for values that don't fit in the signed integer. |
374 | if r > (1 << (width - 1)) { |
375 | // Return the most negative integer for the given width. |
376 | *is_exact = false; |
377 | Status::INVALID_OP.and(-1 << (width - 1)) |
378 | } else { |
379 | status.and(r.wrapping_neg() as i128) |
380 | } |
381 | } else { |
382 | // Positive case is simpler, can pretend it's a smaller unsigned |
383 | // integer, and `to_u128` will take care of all the edge cases. |
384 | self.to_u128_r(width - 1, round, is_exact).map(|r| r as i128) |
385 | } |
386 | } |
387 | fn to_i128(self, width: usize) -> StatusAnd<i128> { |
388 | self.to_i128_r(width, Round::TowardZero, &mut true) |
389 | } |
390 | fn to_u128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u128>; |
391 | fn to_u128(self, width: usize) -> StatusAnd<u128> { |
392 | self.to_u128_r(width, Round::TowardZero, &mut true) |
393 | } |
394 | |
395 | fn cmp_abs_normal(self, rhs: Self) -> Ordering; |
396 | |
397 | /// Bitwise comparison for equality (QNaNs compare equal, 0!=-0). |
398 | fn bitwise_eq(self, rhs: Self) -> bool; |
399 | |
400 | // IEEE-754R 5.7.2 General operations. |
401 | |
402 | /// Implements IEEE minNum semantics. Returns the smaller of the 2 arguments if |
403 | /// both are not NaN. If either argument is a NaN, returns the other argument. |
404 | fn min(self, other: Self) -> Self { |
405 | if self.is_nan() { |
406 | other |
407 | } else if other.is_nan() { |
408 | self |
409 | } else if other < self { |
410 | other |
411 | } else { |
412 | self |
413 | } |
414 | } |
415 | |
416 | /// Implements IEEE maxNum semantics. Returns the larger of the 2 arguments if |
417 | /// both are not NaN. If either argument is a NaN, returns the other argument. |
418 | fn max(self, other: Self) -> Self { |
419 | if self.is_nan() { |
420 | other |
421 | } else if other.is_nan() { |
422 | self |
423 | } else if self < other { |
424 | other |
425 | } else { |
426 | self |
427 | } |
428 | } |
429 | |
430 | /// Implements IEEE 754-2018 minimum semantics. Returns the smaller of 2 |
431 | /// arguments, propagating NaNs and treating -0 as less than +0. |
432 | fn minimum(self, other: Self) -> Self { |
433 | if self.is_nan() { |
434 | self |
435 | } else if other.is_nan() { |
436 | other |
437 | } else if self.is_zero() && other.is_zero() && self.is_negative() != other.is_negative() { |
438 | if self.is_negative() { |
439 | self |
440 | } else { |
441 | other |
442 | } |
443 | } else if other < self { |
444 | other |
445 | } else { |
446 | self |
447 | } |
448 | } |
449 | |
450 | /// Implements IEEE 754-2018 maximum semantics. Returns the larger of 2 |
451 | /// arguments, propagating NaNs and treating -0 as less than +0. |
452 | fn maximum(self, other: Self) -> Self { |
453 | if self.is_nan() { |
454 | self |
455 | } else if other.is_nan() { |
456 | other |
457 | } else if self.is_zero() && other.is_zero() && self.is_negative() != other.is_negative() { |
458 | if self.is_negative() { |
459 | other |
460 | } else { |
461 | self |
462 | } |
463 | } else if self < other { |
464 | other |
465 | } else { |
466 | self |
467 | } |
468 | } |
469 | |
470 | /// IEEE-754R isSignMinus: Returns true if and only if the current value is |
471 | /// negative. |
472 | /// |
473 | /// This applies to zeros and NaNs as well. |
474 | fn is_negative(self) -> bool; |
475 | |
476 | /// IEEE-754R isNormal: Returns true if and only if the current value is normal. |
477 | /// |
478 | /// This implies that the current value of the float is not zero, subnormal, |
479 | /// infinite, or NaN following the definition of normality from IEEE-754R. |
480 | fn is_normal(self) -> bool { |
481 | !self.is_denormal() && self.is_finite_non_zero() |
482 | } |
483 | |
484 | /// Returns true if and only if the current value is zero, subnormal, or |
485 | /// normal. |
486 | /// |
487 | /// This means that the value is not infinite or NaN. |
488 | fn is_finite(self) -> bool { |
489 | !self.is_nan() && !self.is_infinite() |
490 | } |
491 | |
492 | /// Returns true if and only if the float is plus or minus zero. |
493 | fn is_zero(self) -> bool { |
494 | self.category() == Category::Zero |
495 | } |
496 | |
497 | /// IEEE-754R isSubnormal(): Returns true if and only if the float is a |
498 | /// denormal. |
499 | fn is_denormal(self) -> bool; |
500 | |
501 | /// IEEE-754R isInfinite(): Returns true if and only if the float is infinity. |
502 | fn is_infinite(self) -> bool { |
503 | self.category() == Category::Infinity |
504 | } |
505 | |
506 | /// Returns true if and only if the float is a quiet or signaling NaN. |
507 | fn is_nan(self) -> bool { |
508 | self.category() == Category::NaN |
509 | } |
510 | |
511 | /// Returns true if and only if the float is a signaling NaN. |
512 | fn is_signaling(self) -> bool; |
513 | |
514 | // Simple Queries |
515 | |
516 | fn category(self) -> Category; |
517 | fn is_non_zero(self) -> bool { |
518 | !self.is_zero() |
519 | } |
520 | fn is_finite_non_zero(self) -> bool { |
521 | self.is_finite() && !self.is_zero() |
522 | } |
523 | fn is_pos_zero(self) -> bool { |
524 | self.is_zero() && !self.is_negative() |
525 | } |
526 | fn is_neg_zero(self) -> bool { |
527 | self.is_zero() && self.is_negative() |
528 | } |
529 | fn is_pos_infinity(self) -> bool { |
530 | self.is_infinite() && !self.is_negative() |
531 | } |
532 | fn is_neg_infinity(self) -> bool { |
533 | self.is_infinite() && self.is_negative() |
534 | } |
535 | |
536 | /// Returns true if and only if the number has the smallest possible non-zero |
537 | /// magnitude in the current semantics. |
538 | fn is_smallest(self) -> bool { |
539 | Self::SMALLEST.copy_sign(self).bitwise_eq(self) |
540 | } |
541 | |
542 | /// Returns true if this is the smallest (by magnitude) normalized finite |
543 | /// number in the given semantics. |
544 | fn is_smallest_normalized(self) -> bool { |
545 | Self::smallest_normalized().copy_sign(self).bitwise_eq(self) |
546 | } |
547 | |
548 | /// Returns true if and only if the number has the largest possible finite |
549 | /// magnitude in the current semantics. |
550 | fn is_largest(self) -> bool { |
551 | Self::largest().copy_sign(self).bitwise_eq(self) |
552 | } |
553 | |
554 | /// Returns true if and only if the number is an exact integer. |
555 | fn is_integer(self) -> bool { |
556 | // This could be made more efficient; I'm going for obviously correct. |
557 | if !self.is_finite() { |
558 | return false; |
559 | } |
560 | self.round_to_integral(Round::TowardZero).value.bitwise_eq(self) |
561 | } |
562 | |
563 | /// If this value has an exact multiplicative inverse, return it. |
564 | fn get_exact_inverse(self) -> Option<Self>; |
565 | |
566 | /// Returns the exponent of the internal representation of the Float. |
567 | /// |
568 | /// Because the radix of Float is 2, this is equivalent to floor(log2(x)). |
569 | /// For special Float values, this returns special error codes: |
570 | /// |
571 | /// NaN -> \c IEK_NAN |
572 | /// 0 -> \c IEK_ZERO |
573 | /// Inf -> \c IEK_INF |
574 | /// |
575 | fn ilogb(self) -> ExpInt; |
576 | |
577 | /// Returns: self * 2^exp for integral exponents. |
578 | fn scalbn_r(self, exp: ExpInt, round: Round) -> Self; |
579 | fn scalbn(self, exp: ExpInt) -> Self { |
580 | self.scalbn_r(exp, Round::NearestTiesToEven) |
581 | } |
582 | |
583 | /// Equivalent of C standard library function. |
584 | /// |
585 | /// While the C standard says exp is an unspecified value for infinity and nan, |
586 | /// this returns INT_MAX for infinities, and INT_MIN for NaNs (see `ilogb`). |
587 | fn frexp_r(self, exp: &mut ExpInt, round: Round) -> Self; |
588 | fn frexp(self, exp: &mut ExpInt) -> Self { |
589 | self.frexp_r(exp, Round::NearestTiesToEven) |
590 | } |
591 | } |
592 | |
593 | pub trait FloatConvert<T: Float>: Float { |
594 | /// Convert a value of one floating point type to another. |
595 | /// The return value corresponds to the IEEE754 exceptions. *loses_info |
596 | /// records whether the transformation lost information, i.e. whether |
597 | /// converting the result back to the original type will produce the |
598 | /// original value (this is almost the same as return value==Status::OK, |
599 | /// but there are edge cases where this is not so). |
600 | fn convert_r(self, round: Round, loses_info: &mut bool) -> StatusAnd<T>; |
601 | fn convert(self, loses_info: &mut bool) -> StatusAnd<T> { |
602 | self.convert_r(Round::NearestTiesToEven, loses_info) |
603 | } |
604 | } |
605 | |
606 | macro_rules! float_common_impls { |
607 | ($ty:ident<$t:tt>) => { |
608 | impl<$t> Default for $ty<$t> |
609 | where |
610 | Self: Float, |
611 | { |
612 | #[inline] |
613 | fn default() -> Self { |
614 | Self::ZERO |
615 | } |
616 | } |
617 | |
618 | impl<$t> ::core::str::FromStr for $ty<$t> |
619 | where |
620 | Self: Float, |
621 | { |
622 | type Err = ParseError; |
623 | #[inline] |
624 | fn from_str(s: &str) -> Result<Self, ParseError> { |
625 | Self::from_str_r(s, Round::NearestTiesToEven).map(|x| x.value) |
626 | } |
627 | } |
628 | |
629 | // Rounding ties to the nearest even, by default. |
630 | |
631 | impl<$t> ::core::ops::Add for $ty<$t> |
632 | where |
633 | Self: Float, |
634 | { |
635 | type Output = StatusAnd<Self>; |
636 | #[inline] |
637 | fn add(self, rhs: Self) -> StatusAnd<Self> { |
638 | self.add_r(rhs, Round::NearestTiesToEven) |
639 | } |
640 | } |
641 | |
642 | impl<$t> ::core::ops::Sub for $ty<$t> |
643 | where |
644 | Self: Float, |
645 | { |
646 | type Output = StatusAnd<Self>; |
647 | #[inline] |
648 | fn sub(self, rhs: Self) -> StatusAnd<Self> { |
649 | self.sub_r(rhs, Round::NearestTiesToEven) |
650 | } |
651 | } |
652 | |
653 | impl<$t> ::core::ops::Mul for $ty<$t> |
654 | where |
655 | Self: Float, |
656 | { |
657 | type Output = StatusAnd<Self>; |
658 | #[inline] |
659 | fn mul(self, rhs: Self) -> StatusAnd<Self> { |
660 | self.mul_r(rhs, Round::NearestTiesToEven) |
661 | } |
662 | } |
663 | |
664 | impl<$t> ::core::ops::Div for $ty<$t> |
665 | where |
666 | Self: Float, |
667 | { |
668 | type Output = StatusAnd<Self>; |
669 | #[inline] |
670 | fn div(self, rhs: Self) -> StatusAnd<Self> { |
671 | self.div_r(rhs, Round::NearestTiesToEven) |
672 | } |
673 | } |
674 | |
675 | impl<$t> ::core::ops::Rem for $ty<$t> |
676 | where |
677 | Self: Float, |
678 | { |
679 | type Output = StatusAnd<Self>; |
680 | #[inline] |
681 | fn rem(self, rhs: Self) -> StatusAnd<Self> { |
682 | self.c_fmod(rhs) |
683 | } |
684 | } |
685 | |
686 | impl<$t> ::core::ops::AddAssign for $ty<$t> |
687 | where |
688 | Self: Float, |
689 | { |
690 | #[inline] |
691 | fn add_assign(&mut self, rhs: Self) { |
692 | *self = (*self + rhs).value; |
693 | } |
694 | } |
695 | |
696 | impl<$t> ::core::ops::SubAssign for $ty<$t> |
697 | where |
698 | Self: Float, |
699 | { |
700 | #[inline] |
701 | fn sub_assign(&mut self, rhs: Self) { |
702 | *self = (*self - rhs).value; |
703 | } |
704 | } |
705 | |
706 | impl<$t> ::core::ops::MulAssign for $ty<$t> |
707 | where |
708 | Self: Float, |
709 | { |
710 | #[inline] |
711 | fn mul_assign(&mut self, rhs: Self) { |
712 | *self = (*self * rhs).value; |
713 | } |
714 | } |
715 | |
716 | impl<$t> ::core::ops::DivAssign for $ty<$t> |
717 | where |
718 | Self: Float, |
719 | { |
720 | #[inline] |
721 | fn div_assign(&mut self, rhs: Self) { |
722 | *self = (*self / rhs).value; |
723 | } |
724 | } |
725 | |
726 | impl<$t> ::core::ops::RemAssign for $ty<$t> |
727 | where |
728 | Self: Float, |
729 | { |
730 | #[inline] |
731 | fn rem_assign(&mut self, rhs: Self) { |
732 | *self = (*self % rhs).value; |
733 | } |
734 | } |
735 | }; |
736 | } |
737 | |
738 | pub mod ieee; |
739 | pub mod ppc; |
740 | |