// "To nearest, ties away from zero". // 1.0f + 2^-24 = 0x1.000004p0f for FE_UPWARD, FE_TONEARESTFROMZERO // = 0x1.000002p0f for FE_DOWNWARD, FE_TOWARDZERO, FE_TONEAREST // -1.0f - 2^-24 = -0x1.000004p0f for FE_DOWNWARD, FE_TONEARESTFROMZERO // = -0x1.000002p0f for FE_UPWARD, FE_TOWARDZERO, FE_TONEAREST
// Volatile to prevent compile-time evaluation. volatilefloat x = 0x1.0p-24f; float y, z;
android::base::DoNotOptimize(y = 1.0f + x);
android::base::DoNotOptimize(z = -1.0f - x);
EXPECT_EQ(y, 0x1.000002p0f);
EXPECT_EQ(z, -0x1.000002p0f); #else // To be clear: arm64 and x86-64 do support this rounding mode for _some_ instructions. // What they don't have is a way to set this as the _default_ rounding mode.
GTEST_SKIP() << "no hardware FE_TONEARESTFROMZERO default rounding mode"; #endif
}
// fegetenv (unlike feholdexcept) leaves the current state untouched...
fenv_t state;
ASSERT_EQ(0, fegetenv(&state));
ASSERT_EQ(FE_OVERFLOW, fetestexcept(FE_ALL_EXCEPT));
// Dividing by zero sets the appropriate flag...
DivideByZero();
ASSERT_EQ(FE_DIVBYZERO | FE_OVERFLOW, fetestexcept(FE_ALL_EXCEPT));
// And fesetenv (unlike feupdateenv) clobbers that to return to where // we started.
ASSERT_EQ(0, fesetenv(&state));
ASSERT_EQ(FE_OVERFLOW, fetestexcept(FE_ALL_EXCEPT));
}
TEST(fenv, fegetenv_fesetenv_rounding_mode) { // Test that fegetenv()/fesetenv() includes the rounding mode.
fesetround(FE_DOWNWARD);
ASSERT_EQ(FE_DOWNWARD, fegetround());
// Dividing by zero sets the appropriate flag...
DivideByZero();
ASSERT_EQ(FE_DIVBYZERO, fetestexcept(FE_ALL_EXCEPT));
// And feupdateenv (unlike fesetenv) merges what we started with // (FE_OVERFLOW) with what we now have (FE_DIVBYZERO).
ASSERT_EQ(0, feupdateenv(&state));
ASSERT_EQ(FE_DIVBYZERO | FE_OVERFLOW, fetestexcept(FE_ALL_EXCEPT));
}
TEST(fenv, fegetexceptflag_fesetexceptflag) { // Set three flags.
feclearexcept(FE_ALL_EXCEPT);
ASSERT_EQ(0, feraiseexcept(FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW));
ASSERT_EQ(FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW, fetestexcept(FE_ALL_EXCEPT));
// Check we can restore all.
feclearexcept(FE_ALL_EXCEPT);
ASSERT_EQ(0, fesetexceptflag(&all, FE_ALL_EXCEPT));
ASSERT_EQ(FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW, fetestexcept(FE_ALL_EXCEPT));
// Check that `two` only stored a subset.
feclearexcept(FE_ALL_EXCEPT);
ASSERT_EQ(0, fesetexceptflag(&two, FE_ALL_EXCEPT));
ASSERT_EQ(FE_OVERFLOW | FE_UNDERFLOW, fetestexcept(FE_ALL_EXCEPT));
// Check that we can restore a single flag.
feclearexcept(FE_ALL_EXCEPT);
ASSERT_EQ(0, fesetexceptflag(&all, FE_DIVBYZERO));
ASSERT_EQ(FE_DIVBYZERO, fetestexcept(FE_ALL_EXCEPT));
// Check that we can restore a subset of flags.
feclearexcept(FE_ALL_EXCEPT);
ASSERT_EQ(0, fesetexceptflag(&all, FE_OVERFLOW | FE_UNDERFLOW));
ASSERT_EQ(FE_OVERFLOW | FE_UNDERFLOW, fetestexcept(FE_ALL_EXCEPT));
}
TEST(fenv, feenableexcept_fegetexcept) { #if !defined(ANDROID_HOST_MUSL) #ifdefined(__aarch64__) || defined(__arm__) || defined(__riscv) // ARM and RISC-V don't support hardware trapping of floating point // exceptions. ARM used to if you go back far enough, but it was // removed in the Cortex-A8 between r3p1 and r3p2. RISC-V never has.
ASSERT_EQ(-1, feenableexcept(FE_INVALID));
ASSERT_EQ(0, fegetexcept());
ASSERT_EQ(-1, feenableexcept(FE_DIVBYZERO));
ASSERT_EQ(0, fegetexcept());
ASSERT_EQ(-1, feenableexcept(FE_OVERFLOW));
ASSERT_EQ(0, fegetexcept());
ASSERT_EQ(-1, feenableexcept(FE_UNDERFLOW));
ASSERT_EQ(0, fegetexcept());
ASSERT_EQ(-1, feenableexcept(FE_INEXACT));
ASSERT_EQ(0, fegetexcept()); #ifdefined(_FE_DENORMAL) // riscv64 doesn't support this.
ASSERT_EQ(-1, feenableexcept(FE_DENORMAL));
ASSERT_EQ(0, fegetexcept()); #endif #else // We can't recover from SIGFPE, so sacrifice a child...
pid_t pid = fork();
ASSERT_NE(-1, pid) << strerror(errno);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.