diff --git a/libc/src/__support/FPUtil/FEnvImpl.h b/libc/src/__support/FPUtil/FEnvImpl.h --- a/libc/src/__support/FPUtil/FEnvImpl.h +++ b/libc/src/__support/FPUtil/FEnvImpl.h @@ -80,6 +80,65 @@ libc_errno = err; } +// Quick free-standing test whether fegetround() == FE_UPWARD. +// Using the following observation: +// 1.0f + 2^-25 = 1.0f for FE_TONEAREST, FE_DOWNWARD, FE_TOWARDZERO +// = 0x1.000002f for FE_UPWARD. +LIBC_INLINE bool fenv_is_round_up() { + volatile float x = 0x1.0p-25f; + return (1.0f + x != 1.0f); +} + +// Quick free-standing test whether fegetround() == FE_DOWNWARD. +// Using the following observation: +// -1.0f - 2^-25 = -1.0f for FE_TONEAREST, FE_UPWARD, FE_TOWARDZERO +// = -0x1.000002f for FE_DOWNWARD. +LIBC_INLINE bool fenv_is_round_down() { + volatile float x = 0x1.0p-25f; + return (-1.0f - x != -1.0f); +} + +// Quick free-standing test whether fegetround() == FE_TONEAREST. +// Using the following observation: +// 1.5f + 2^-24 = 1.5f for FE_TONEAREST, FE_DOWNWARD, FE_TOWARDZERO +// = 0x1.100002p0f for FE_UPWARD, +// 1.5f - 2^-24 = 1.5f for FE_TONEAREST, FE_UPWARD +// = 0x1.0ffffep-1f for FE_DOWNWARD, FE_TOWARDZERO +LIBC_INLINE bool fenv_is_round_to_nearest() { + static volatile float x = 0x1.0p-24f; + float y = x; + return (1.5f + y == 1.5f - y); +} + +// Quick free-standing test whether fegetround() == FE_TOWARDZERO. +// Using the following observation: +// 1.0f + 2^-23 + 2^-24 = 0x1.000002p0f for FE_DOWNWARD, FE_TOWARDZERO +// = 0x1.000004p0f for FE_TONEAREST, FE_UPWARD, +// -1.0f - 2^-24 = -1.0f for FE_TONEAREST, FE_UPWARD, FE_TOWARDZERO +// = -0x1.000002p0f for FE_DOWNWARD +// So: +// (0x1.000002p0f + 2^-24) + (-1.0f - 2^-24) = 2^-23 for FE_TOWARDZERO +// = 2^-22 for FE_TONEAREST, FE_UPWARD +// = 0 for FE_DOWNWARD +LIBC_INLINE bool fenv_is_round_to_zero() { + static volatile float x = 0x1.0p-24f; + float y = x; + return ((0x1.000002p0f + y) + (-1.0f - y) == 0x1.0p-23f); +} + +// Quick free standing get rounding mode based on the above observations. +LIBC_INLINE int quick_get_round() { + static volatile float x = 0x1.0p-24f; + float y = x; + float z = (0x1.000002p0f + y) + (-1.0f - y); + + if (z == 0.0f) + return FE_DOWNWARD; + if (z == 0x1.0p-23f) + return FE_TOWARDZERO; + return (2.0f + y == 2.0f) ? FE_TONEAREST : FE_UPWARD; +} + } // namespace __llvm_libc::fputil #endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_FENVIMPL_H diff --git a/libc/src/__support/FPUtil/Hypot.h b/libc/src/__support/FPUtil/Hypot.h --- a/libc/src/__support/FPUtil/Hypot.h +++ b/libc/src/__support/FPUtil/Hypot.h @@ -190,7 +190,7 @@ sum >>= 2; ++out_exp; if (out_exp >= FPBits_t::MAX_EXPONENT) { - if (int round_mode = get_round(); + if (int round_mode = quick_get_round(); round_mode == FE_TONEAREST || round_mode == FE_UPWARD) return T(FPBits_t::inf()); return T(FPBits_t(FPBits_t::MAX_NORMAL)); @@ -231,7 +231,7 @@ y_new >>= 1; // Round to the nearest, tie to even. - int round_mode = get_round(); + int round_mode = quick_get_round(); switch (round_mode) { case FE_TONEAREST: // Round to nearest, ties to even diff --git a/libc/src/__support/FPUtil/NearestIntegerOperations.h b/libc/src/__support/FPUtil/NearestIntegerOperations.h --- a/libc/src/__support/FPUtil/NearestIntegerOperations.h +++ b/libc/src/__support/FPUtil/NearestIntegerOperations.h @@ -162,7 +162,7 @@ bool is_neg = bits.get_sign(); int exponent = bits.get_exponent(); - int rounding_mode = get_round(); + int rounding_mode = quick_get_round(); // If the exponent is greater than the most negative mantissa // exponent, then x is already an integer. diff --git a/libc/src/__support/FPUtil/except_value_utils.h b/libc/src/__support/FPUtil/except_value_utils.h --- a/libc/src/__support/FPUtil/except_value_utils.h +++ b/libc/src/__support/FPUtil/except_value_utils.h @@ -52,7 +52,7 @@ for (size_t i = 0; i < N; ++i) { if (LIBC_UNLIKELY(x_bits == values[i].input)) { UIntType out_bits = values[i].rnd_towardzero_result; - switch (fputil::get_round()) { + switch (fputil::quick_get_round()) { case FE_UPWARD: out_bits += values[i].rnd_upward_offset; break; @@ -74,7 +74,7 @@ for (size_t i = 0; i < N; ++i) { if (LIBC_UNLIKELY(x_abs == values[i].input)) { UIntType out_bits = values[i].rnd_towardzero_result; - switch (fputil::get_round()) { + switch (fputil::quick_get_round()) { case FE_UPWARD: out_bits += sign ? values[i].rnd_downward_offset : values[i].rnd_upward_offset; diff --git a/libc/src/__support/FPUtil/generic/FMA.h b/libc/src/__support/FPUtil/generic/FMA.h --- a/libc/src/__support/FPUtil/generic/FMA.h +++ b/libc/src/__support/FPUtil/generic/FMA.h @@ -254,7 +254,7 @@ } // Finalize the result. - int round_mode = fputil::get_round(); + int round_mode = fputil::quick_get_round(); if (LIBC_UNLIKELY(r_exp >= FPBits::MAX_EXPONENT)) { if ((round_mode == FE_TOWARDZERO) || (round_mode == FE_UPWARD && prod_sign) || diff --git a/libc/src/__support/FPUtil/generic/sqrt.h b/libc/src/__support/FPUtil/generic/sqrt.h --- a/libc/src/__support/FPUtil/generic/sqrt.h +++ b/libc/src/__support/FPUtil/generic/sqrt.h @@ -150,7 +150,7 @@ y = (y - ONE) | (static_cast(x_exp) << MantissaWidth::VALUE); - switch (get_round()) { + switch (quick_get_round()) { case FE_TONEAREST: // Round to nearest, ties to even if (rb && (lsb || (r != 0))) diff --git a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h --- a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h +++ b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h @@ -114,7 +114,7 @@ y |= (static_cast(x_exp) << (MantissaWidth::VALUE + 1)); - switch (get_round()) { + switch (quick_get_round()) { case FE_TONEAREST: // Round to nearest, ties to even if (rb && (lsb || (r != 0))) diff --git a/libc/src/__support/str_to_float.h b/libc/src/__support/str_to_float.h --- a/libc/src/__support/str_to_float.h +++ b/libc/src/__support/str_to_float.h @@ -1120,7 +1120,7 @@ RoundDirection round_direction = RoundDirection::Nearest; - switch (fputil::get_round()) { + switch (fputil::quick_get_round()) { case FE_TONEAREST: round_direction = RoundDirection::Nearest; break; diff --git a/libc/src/math/generic/atanf.cpp b/libc/src/math/generic/atanf.cpp --- a/libc/src/math/generic/atanf.cpp +++ b/libc/src/math/generic/atanf.cpp @@ -28,7 +28,7 @@ } // |x| == 0.06905200332403183 if (LIBC_UNLIKELY(xbits.uintval() == 0x3d8d6b23U)) { - if (fputil::get_round() == FE_TONEAREST) { + if (fputil::fenv_is_round_to_nearest()) { // 0.06894256919622421 FPBits br(0x3d8d31c3U); br.set_sign(sign); @@ -38,7 +38,7 @@ // |x| == 1.8670953512191772 if (LIBC_UNLIKELY(xbits.uintval() == 0x3feefcfbU)) { - int rounding_mode = fputil::get_round(); + int rounding_mode = fputil::quick_get_round(); if (sign) { if (rounding_mode == FE_DOWNWARD) { // -1.0790828466415405 diff --git a/libc/src/math/generic/coshf.cpp b/libc/src/math/generic/coshf.cpp --- a/libc/src/math/generic/coshf.cpp +++ b/libc/src/math/generic/coshf.cpp @@ -32,7 +32,7 @@ if (xbits.is_inf_or_nan()) return x + FPBits::inf().get_val(); - int rounding = fputil::get_round(); + int rounding = fputil::quick_get_round(); if (LIBC_UNLIKELY(rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)) return FPBits(FPBits::MAX_NORMAL).get_val(); diff --git a/libc/src/math/generic/exp10f.cpp b/libc/src/math/generic/exp10f.cpp --- a/libc/src/math/generic/exp10f.cpp +++ b/libc/src/math/generic/exp10f.cpp @@ -38,7 +38,7 @@ // exp(nan) = nan if (xbits.is_nan()) return x; - if (fputil::get_round() == FE_UPWARD) + if (fputil::fenv_is_round_up()) return static_cast(FPBits(FPBits::MIN_SUBNORMAL)); fputil::set_errno_if_required(ERANGE); fputil::raise_except_if_required(FE_UNDERFLOW); @@ -48,7 +48,7 @@ if (!xbits.get_sign() && (x_u >= 0x421a'209bU)) { // x is finite if (x_u < 0x7f80'0000U) { - int rounding = fputil::get_round(); + int rounding = fputil::quick_get_round(); if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) return static_cast(FPBits(FPBits::MAX_NORMAL)); @@ -63,7 +63,7 @@ // When |x| <= log10(2)*2^-6 if (LIBC_UNLIKELY(x_abs <= 0x3b9a'209bU)) { if (LIBC_UNLIKELY(x_u == 0xb25e'5bd9U)) { // x = -0x1.bcb7b2p-27f - if (fputil::get_round() == FE_TONEAREST) + if (fputil::fenv_is_round_to_nearest()) return 0x1.fffffep-1f; } // |x| < 2^-25 @@ -77,7 +77,7 @@ // Exceptional value. if (LIBC_UNLIKELY(x_u == 0x3d14'd956U)) { // x = 0x1.29b2acp-5f - if (fputil::get_round() == FE_UPWARD) + if (fputil::fenv_is_round_up()) return 0x1.1657c4p+0f; } diff --git a/libc/src/math/generic/exp2f.cpp b/libc/src/math/generic/exp2f.cpp --- a/libc/src/math/generic/exp2f.cpp +++ b/libc/src/math/generic/exp2f.cpp @@ -44,7 +44,7 @@ if (!xbits.get_sign()) { // x is finite if (x_u < 0x7f80'0000U) { - int rounding = fputil::get_round(); + int rounding = fputil::quick_get_round(); if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) return static_cast(FPBits(FPBits::MAX_NORMAL)); @@ -62,7 +62,7 @@ // exp(nan) = nan if (xbits.is_nan()) return x; - if (fputil::get_round() == FE_UPWARD) + if (fputil::fenv_is_round_up()) return FPBits(FPBits::MIN_SUBNORMAL).get_val(); if (x != 0.0f) { fputil::set_errno_if_required(ERANGE); @@ -75,10 +75,10 @@ // Check exceptional values. if (LIBC_UNLIKELY((x_u & EXVAL_MASK) == EXVAL_MASK)) { if (LIBC_UNLIKELY(x_u == EXVAL1)) { // x = 0x1.853a6ep-9f - if (fputil::get_round() == FE_TONEAREST) + if (fputil::fenv_is_round_to_nearest()) return 0x1.00870ap+0f; } else if (LIBC_UNLIKELY(x_u == EXVAL2)) { // x = -0x1.e7526ep-6f - if (fputil::get_round() == FE_TONEAREST) + if (fputil::fenv_is_round_to_nearest()) return 0x1.f58d62p-1f; } } diff --git a/libc/src/math/generic/expf.cpp b/libc/src/math/generic/expf.cpp --- a/libc/src/math/generic/expf.cpp +++ b/libc/src/math/generic/expf.cpp @@ -48,7 +48,7 @@ // exp(nan) = nan if (xbits.is_nan()) return x; - if (fputil::get_round() == FE_UPWARD) + if (fputil::fenv_is_round_up()) return static_cast(FPBits(FPBits::MIN_SUBNORMAL)); fputil::set_errno_if_required(ERANGE); fputil::raise_except_if_required(FE_UNDERFLOW); @@ -58,7 +58,7 @@ if (!xbits.get_sign() && (xbits.uintval() >= 0x42b2'0000)) { // x is finite if (xbits.uintval() < 0x7f80'0000U) { - int rounding = fputil::get_round(); + int rounding = fputil::quick_get_round(); if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) return static_cast(FPBits(FPBits::MAX_NORMAL)); diff --git a/libc/src/math/generic/expm1f.cpp b/libc/src/math/generic/expm1f.cpp --- a/libc/src/math/generic/expm1f.cpp +++ b/libc/src/math/generic/expm1f.cpp @@ -32,7 +32,7 @@ // Exceptional value if (LIBC_UNLIKELY(x_u == 0x3e35'bec5U)) { // x = 0x1.6b7d8ap-3f - int round_mode = fputil::get_round(); + int round_mode = fputil::quick_get_round(); if (round_mode == FE_TONEAREST || round_mode == FE_UPWARD) return 0x1.8dbe64p-3f; return 0x1.8dbe62p-3f; @@ -40,7 +40,7 @@ #if !defined(LIBC_TARGET_CPU_HAS_FMA) if (LIBC_UNLIKELY(x_u == 0xbdc1'c6cbU)) { // x = -0x1.838d96p-4f - int round_mode = fputil::get_round(); + int round_mode = fputil::quick_get_round(); if (round_mode == FE_TONEAREST || round_mode == FE_DOWNWARD) return -0x1.71c884p-4f; return -0x1.71c882p-4f; @@ -57,7 +57,7 @@ // exp(nan) = nan if (xbits.is_nan()) return x; - int round_mode = fputil::get_round(); + int round_mode = fputil::quick_get_round(); if (round_mode == FE_UPWARD || round_mode == FE_TOWARDZERO) return -0x1.ffff'fep-1f; // -1.0f + 0x1.0p-24f return -1.0f; @@ -65,7 +65,7 @@ // x >= 89 or nan if (xbits.uintval() >= 0x42b2'0000) { if (xbits.uintval() < 0x7f80'0000U) { - int rounding = fputil::get_round(); + int rounding = fputil::quick_get_round(); if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) return static_cast(FPBits(FPBits::MAX_NORMAL)); diff --git a/libc/src/math/generic/sincosf.cpp b/libc/src/math/generic/sincosf.cpp --- a/libc/src/math/generic/sincosf.cpp +++ b/libc/src/math/generic/sincosf.cpp @@ -159,7 +159,7 @@ uint32_t s = EXCEPT_OUTPUTS_SIN[i][0]; // FE_TOWARDZERO uint32_t c = EXCEPT_OUTPUTS_COS[i][0]; // FE_TOWARDZERO bool x_sign = x < 0; - switch (fputil::get_round()) { + switch (fputil::quick_get_round()) { case FE_UPWARD: s += x_sign ? EXCEPT_OUTPUTS_SIN[i][2] : EXCEPT_OUTPUTS_SIN[i][1]; c += EXCEPT_OUTPUTS_COS[i][1]; diff --git a/libc/src/math/generic/sinf.cpp b/libc/src/math/generic/sinf.cpp --- a/libc/src/math/generic/sinf.cpp +++ b/libc/src/math/generic/sinf.cpp @@ -126,7 +126,7 @@ if (LIBC_UNLIKELY(x_abs == 0x4619'9998U)) { // x = 0x1.33333p13 float r = -0x1.63f4bap-2f; - int rounding = fputil::get_round(); + int rounding = fputil::quick_get_round(); bool sign = xbits.get_sign(); if ((rounding == FE_DOWNWARD && !sign) || (rounding == FE_UPWARD && sign)) r = -0x1.63f4bcp-2f; diff --git a/libc/src/math/generic/sinhf.cpp b/libc/src/math/generic/sinhf.cpp --- a/libc/src/math/generic/sinhf.cpp +++ b/libc/src/math/generic/sinhf.cpp @@ -33,7 +33,7 @@ if (xbits.is_inf()) return x; - int rounding = fputil::get_round(); + int rounding = fputil::quick_get_round(); if (sign) { if (LIBC_UNLIKELY(rounding == FE_UPWARD || rounding == FE_TOWARDZERO)) return FPBits(FPBits::MAX_NORMAL | FPBits::FloatProp::SIGN_MASK) @@ -53,7 +53,7 @@ if (LIBC_UNLIKELY(x_abs <= 0x3da0'0000U)) { // |x| = 0.0005589424981735646724700927734375 if (LIBC_UNLIKELY(x_abs == 0x3a12'85ffU)) { - if (fputil::get_round() == FE_TONEAREST) + if (fputil::fenv_is_round_to_nearest()) return x; } diff --git a/libc/src/math/generic/tanhf.cpp b/libc/src/math/generic/tanhf.cpp --- a/libc/src/math/generic/tanhf.cpp +++ b/libc/src/math/generic/tanhf.cpp @@ -52,7 +52,7 @@ } if (LIBC_UNLIKELY(xbits.bits == 0x4058'e0a3U)) { - if (fputil::get_round() == FE_DOWNWARD) + if (fputil::fenv_is_round_down()) return FPBits(0x3f7f'6ad9U).get_val(); } diff --git a/libc/src/stdio/printf_core/float_dec_converter.h b/libc/src/stdio/printf_core/float_dec_converter.h --- a/libc/src/stdio/printf_core/float_dec_converter.h +++ b/libc/src/stdio/printf_core/float_dec_converter.h @@ -600,7 +600,7 @@ (requiredTwos < 60 && multiple_of_power_of_2(float_bits.get_explicit_mantissa(), static_cast(requiredTwos))); - switch (fputil::get_round()) { + switch (fputil::quick_get_round()) { case FE_TONEAREST: // Round to nearest, if it's exactly halfway then round to even. if (last_digit != 5) { @@ -774,7 +774,7 @@ (requiredTwos < 60 && multiple_of_power_of_2(float_bits.get_explicit_mantissa(), static_cast(requiredTwos))); - switch (fputil::get_round()) { + switch (fputil::quick_get_round()) { case FE_TONEAREST: // Round to nearest, if it's exactly halfway then round to even. if (last_digit != 5) { @@ -1022,7 +1022,7 @@ (requiredTwos < 60 && multiple_of_power_of_2(float_bits.get_explicit_mantissa(), static_cast(requiredTwos))); - switch (fputil::get_round()) { + switch (fputil::quick_get_round()) { case FE_TONEAREST: // Round to nearest, if it's exactly halfway then round to even. if (last_digit != 5) { diff --git a/libc/src/stdio/printf_core/float_hex_converter.h b/libc/src/stdio/printf_core/float_hex_converter.h --- a/libc/src/stdio/printf_core/float_hex_converter.h +++ b/libc/src/stdio/printf_core/float_hex_converter.h @@ -113,7 +113,7 @@ mantissa >>= shift_amount; - switch (fputil::get_round()) { + switch (fputil::quick_get_round()) { case FE_TONEAREST: // Round to nearest, if it's exactly halfway then round to even. if (truncated_bits > halfway_const) diff --git a/libc/test/src/__support/FPUtil/CMakeLists.txt b/libc/test/src/__support/FPUtil/CMakeLists.txt --- a/libc/test/src/__support/FPUtil/CMakeLists.txt +++ b/libc/test/src/__support/FPUtil/CMakeLists.txt @@ -20,3 +20,13 @@ DEPENDS libc.src.__support.FPUtil.fp_bits ) + +add_fp_unittest( + fenvimpl_test + SUITE + libc-fputil-tests + SRCS + fenvimpl_test.cpp + DEPENDS + libc.src.__support.FPUtil.fenv_impl +) diff --git a/libc/test/src/__support/FPUtil/fenvimpl_test.cpp b/libc/test/src/__support/FPUtil/fenvimpl_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/__support/FPUtil/fenvimpl_test.cpp @@ -0,0 +1,116 @@ +//===-- Unittests for the FEnvImpl ----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/__support/FPUtil/FEnvImpl.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +#include + +using __llvm_libc::testing::mpfr::ForceRoundingMode; +using __llvm_libc::testing::mpfr::RoundingMode; + +TEST(LlvmLibcFEnvImplTest, QuickRoundingUpTest) { + using __llvm_libc::fputil::fenv_is_round_up; + { + ForceRoundingMode __r(RoundingMode::Upward); + ASSERT_TRUE(fenv_is_round_up()); + } + { + ForceRoundingMode __r(RoundingMode::Downward); + ASSERT_FALSE(fenv_is_round_up()); + } + { + ForceRoundingMode __r(RoundingMode::Nearest); + ASSERT_FALSE(fenv_is_round_up()); + } + { + ForceRoundingMode __r(RoundingMode::TowardZero); + ASSERT_FALSE(fenv_is_round_up()); + } +} + +TEST(LlvmLibcFEnvImplTest, QuickRoundingDownTest) { + using __llvm_libc::fputil::fenv_is_round_down; + { + ForceRoundingMode __r(RoundingMode::Upward); + ASSERT_FALSE(fenv_is_round_down()); + } + { + ForceRoundingMode __r(RoundingMode::Downward); + ASSERT_TRUE(fenv_is_round_down()); + } + { + ForceRoundingMode __r(RoundingMode::Nearest); + ASSERT_FALSE(fenv_is_round_down()); + } + { + ForceRoundingMode __r(RoundingMode::TowardZero); + ASSERT_FALSE(fenv_is_round_down()); + } +} + +TEST(LlvmLibcFEnvImplTest, QuickRoundingNearestTest) { + using __llvm_libc::fputil::fenv_is_round_to_nearest; + { + ForceRoundingMode __r(RoundingMode::Upward); + ASSERT_FALSE(fenv_is_round_to_nearest()); + } + { + ForceRoundingMode __r(RoundingMode::Downward); + ASSERT_FALSE(fenv_is_round_to_nearest()); + } + { + ForceRoundingMode __r(RoundingMode::Nearest); + ASSERT_TRUE(fenv_is_round_to_nearest()); + } + { + ForceRoundingMode __r(RoundingMode::TowardZero); + ASSERT_FALSE(fenv_is_round_to_nearest()); + } +} + +TEST(LlvmLibcFEnvImplTest, QuickRoundingTowardZeroTest) { + using __llvm_libc::fputil::fenv_is_round_to_zero; + { + ForceRoundingMode __r(RoundingMode::Upward); + ASSERT_FALSE(fenv_is_round_to_zero()); + } + { + ForceRoundingMode __r(RoundingMode::Downward); + ASSERT_FALSE(fenv_is_round_to_zero()); + } + { + ForceRoundingMode __r(RoundingMode::Nearest); + ASSERT_FALSE(fenv_is_round_to_zero()); + } + { + ForceRoundingMode __r(RoundingMode::TowardZero); + ASSERT_TRUE(fenv_is_round_to_zero()); + } +} + +TEST(LlvmLibcFEnvImplTest, QuickGetRoundTest) { + using __llvm_libc::fputil::quick_get_round; + { + ForceRoundingMode __r(RoundingMode::Upward); + ASSERT_EQ(quick_get_round(), FE_UPWARD); + } + { + ForceRoundingMode __r(RoundingMode::Downward); + ASSERT_EQ(quick_get_round(), FE_DOWNWARD); + } + { + ForceRoundingMode __r(RoundingMode::Nearest); + ASSERT_EQ(quick_get_round(), FE_TONEAREST); + } + { + ForceRoundingMode __r(RoundingMode::TowardZero); + ASSERT_EQ(quick_get_round(), FE_TOWARDZERO); + } +}