long double __truncl (long double x) { double xh, xl, hi, lo; ldbl_unpack (x, &xh, &xl); /* Return Inf, Nan, +/-0 unchanged. */ if (__builtin_expect (xh != 0.0 && __builtin_isless (__builtin_fabs (xh), __builtin_inf ()), 1)) { double orig_xh; /* Long double arithmetic, including the canonicalisation below, only works in round-to-nearest mode. */ /* Convert the high double to integer. */ orig_xh = xh; hi = ldbl_nearbyint (xh); /* Subtract integral high part from the value. */ xh -= hi; ldbl_canonicalize (&xh, &xl); /* Now convert the low double, adjusted for any remainder from the high double. */ lo = ldbl_nearbyint (xh); /* Adjust the result when the remainder is non-zero. nearbyint rounds values to the nearest integer, and values halfway between integers to the nearest even integer. floorl must round towards -Inf. */ xh -= lo; ldbl_canonicalize (&xh, &xl); if (orig_xh < 0.0) { if (xh > 0.0 || (xh == 0.0 && xl > 0.0)) lo += 1.0; } else { if (xh < 0.0 || (xh == 0.0 && xl < 0.0)) lo -= 1.0; } /* Ensure the final value is canonical. In certain cases, rounding causes hi,lo calculated so far to be non-canonical. */ xh = hi; xl = lo; ldbl_canonicalize (&xh, &xl); /* Ensure we return -0 rather than +0 when appropriate. */ if (orig_xh < 0.0) xh = -__builtin_fabs (xh); } return ldbl_pack (xh, xl); }
long double __roundl (long double x) { double xh, xl, hi, lo; ldbl_unpack (x, &xh, &xl); /* Return Inf, Nan, +/-0 unchanged. */ if (__builtin_expect (xh != 0.0 && __builtin_isless (__builtin_fabs (xh), __builtin_inf ()), 1)) { double orig_xh; /* Long double arithmetic, including the canonicalisation below, only works in round-to-nearest mode. */ /* Convert the high double to integer. */ orig_xh = xh; hi = ldbl_nearbyint (xh); /* Subtract integral high part from the value. */ xh -= hi; ldbl_canonicalize (&xh, &xl); /* Now convert the low double, adjusted for any remainder from the high double. */ lo = ldbl_nearbyint (xh); /* Adjust the result when the remainder is exactly 0.5. nearbyint rounds values halfway between integers to the nearest even integer. roundl must round away from zero. Also correct cases where nearbyint returns an incorrect value for LO. */ xh -= lo; ldbl_canonicalize (&xh, &xl); if (xh == 0.5) { if (xl > 0.0 || (xl == 0.0 && orig_xh > 0.0)) lo += 1.0; } else if (-xh == 0.5) { if (xl < 0.0 || (xl == 0.0 && orig_xh < 0.0)) lo -= 1.0; } /* Ensure the final value is canonical. In certain cases, rounding causes hi,lo calculated so far to be non-canonical. */ xh = hi; xl = lo; ldbl_canonicalize (&xh, &xl); } return ldbl_pack (xh, xl); }
long double __rintl (long double x) { double xh, xl, hi, lo; ldbl_unpack (x, &xh, &xl); /* Return Inf, Nan, +/-0 unchanged. */ if (__builtin_expect (xh != 0.0 && __builtin_isless (__builtin_fabs (xh), __builtin_inf ()), 1)) { double orig_xh; int save_round = fegetround (); /* Long double arithmetic, including the canonicalisation below, only works in round-to-nearest mode. */ fesetround (FE_TONEAREST); /* Convert the high double to integer. */ orig_xh = xh; hi = ldbl_nearbyint (xh); /* Subtract integral high part from the value. If the low double happens to be exactly 0.5 or -0.5, you might think that this subtraction could result in an incorrect conversion. For instance, subtracting an odd number would cause this function to round in the wrong direction. However, if we have a canonical long double with the low double 0.5 or -0.5, then the high double must be even. */ xh -= hi; ldbl_canonicalize (&xh, &xl); /* Now convert the low double, adjusted for any remainder from the high double. */ lo = ldbl_nearbyint (xh); xh -= lo; ldbl_canonicalize (&xh, &xl); switch (save_round) { case FE_TONEAREST: if (xl > 0.0 && xh == 0.5) lo += 1.0; else if (xl < 0.0 && -xh == 0.5) lo -= 1.0; break; case FE_TOWARDZERO: if (orig_xh < 0.0) goto do_up; /* Fall thru */ case FE_DOWNWARD: if (xh < 0.0 || (xh == 0.0 && xl < 0.0)) lo -= 1.0; break; case FE_UPWARD: do_up: if (xh > 0.0 || (xh == 0.0 && xl > 0.0)) lo += 1.0; break; } /* Ensure the final value is canonical. In certain cases, rounding causes hi,lo calculated so far to be non-canonical. */ xh = hi; xl = lo; ldbl_canonicalize (&xh, &xl); /* Ensure we return -0 rather than +0 when appropriate. */ if (orig_xh < 0.0) xh = -__builtin_fabs (xh); fesetround (save_round); } return ldbl_pack (xh, xl); }