| /* SPDX-License-Identifier: MIT */ |
| /* origin: musl src/math/rint.c */ |
| |
| use crate::support::{Float, FpResult, Status}; |
| |
| /// IEEE 754-2019 `roundToIntegralExact`, which respects rounding mode and raises inexact if |
| /// applicable. |
| #[inline] |
| pub fn rint_status<F: Float>(x: F) -> FpResult<F> { |
| let toint = F::ONE / F::EPSILON; |
| let e = x.ex(); |
| let positive = x.is_sign_positive(); |
| |
| // On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise, |
| // the excess precission from x87 would cause an incorrect final result. |
| let force = |x| { |
| if cfg!(x86_no_sse2) && (F::BITS == 32 || F::BITS == 64) { |
| force_eval!(x) |
| } else { |
| x |
| } |
| }; |
| |
| let res = if e >= F::EXP_BIAS + F::SIG_BITS { |
| // No fractional part; exact result can be returned. |
| x |
| } else { |
| // Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode. For |
| // Rust this is always nearest, but ideally it would take `round` into account. |
| let y = if positive { |
| force(force(x) + toint) - toint |
| } else { |
| force(force(x) - toint) + toint |
| }; |
| |
| if y == F::ZERO { |
| // A zero result takes the sign of the input. |
| if positive { F::ZERO } else { F::NEG_ZERO } |
| } else { |
| y |
| } |
| }; |
| |
| let status = if res == x { |
| Status::OK |
| } else { |
| Status::INEXACT |
| }; |
| FpResult::new(res, status) |
| } |