/* ** ===================================================================== ** Demonstrate rounding behavior near the underflow limit. ** ** On AMD64, the output for the 32-bit version is ** ** u i s e x y x*y ** 0 0 1 0x1.0p-01 0x1.800000p+0 0x1.000000p-127 0x1.800000p-127 ** 0 0 1 0x1.0p-02 0x1.400000p+0 0x1.800000p-127 0x1.e00000p-127 ** 0 0 1 0x1.0p-03 0x1.200000p+0 0x1.c00000p-127 0x1.f80000p-127 ** 0 0 1 0x1.0p-04 0x1.100000p+0 0x1.e00000p-127 0x1.fe0000p-127 ** 0 0 1 0x1.0p-05 0x1.080000p+0 0x1.f00000p-127 0x1.ff8000p-127 ** 0 0 1 0x1.0p-06 0x1.040000p+0 0x1.f80000p-127 0x1.ffe000p-127 ** 0 0 1 0x1.0p-07 0x1.020000p+0 0x1.fc0000p-127 0x1.fff800p-127 ** 0 0 1 0x1.0p-08 0x1.010000p+0 0x1.fe0000p-127 0x1.fffe00p-127 ** 0 0 1 0x1.0p-09 0x1.008000p+0 0x1.ff0000p-127 0x1.ffff80p-127 ** 0 0 1 0x1.0p-10 0x1.004000p+0 0x1.ff8000p-127 0x1.ffffe0p-127 ** 0 0 1 0x1.0p-11 0x1.002000p+0 0x1.ffc000p-127 0x1.fffff8p-127 ** 1 1 0 0x1.0p-12 0x1.001000p+0 0x1.ffe000p-127 0x1.000000p-126 ** 0 1 0 0x1.0p-13 0x1.000800p+0 0x1.fff000p-127 0x1.000000p-126 ** 0 1 0 0x1.0p-14 0x1.000400p+0 0x1.fff800p-127 0x1.000000p-126 ** 0 1 0 0x1.0p-15 0x1.000200p+0 0x1.fffc00p-127 0x1.000000p-126 ** 0 1 0 0x1.0p-16 0x1.000100p+0 0x1.fffe00p-127 0x1.000000p-126 ** 0 1 0 0x1.0p-17 0x1.000080p+0 0x1.ffff00p-127 0x1.000000p-126 ** 0 1 0 0x1.0p-18 0x1.000040p+0 0x1.ffff80p-127 0x1.000000p-126 ** 0 1 0 0x1.0p-19 0x1.000020p+0 0x1.ffffc0p-127 0x1.000000p-126 ** 0 1 0 0x1.0p-20 0x1.000010p+0 0x1.ffffe0p-127 0x1.000000p-126 ** 0 1 0 0x1.0p-21 0x1.000008p+0 0x1.fffff0p-127 0x1.000000p-126 ** 0 1 0 0x1.0p-22 0x1.000004p+0 0x1.fffff8p-127 0x1.000000p-126 ** 0 1 0 0x1.0p-23 0x1.000002p+0 0x1.fffffcp-127 0x1.000000p-126 ** ** On SPARC64, the output differs in the u value in lines 13--23: ** ** u i s e x y x*y ** 0 0 1 0x1.0p-01 0x1.800000p+0 0x1.000000p-127 0x1.800000p-127 ** 0 0 1 0x1.0p-02 0x1.400000p+0 0x1.800000p-127 0x1.e00000p-127 ** 0 0 1 0x1.0p-03 0x1.200000p+0 0x1.c00000p-127 0x1.f80000p-127 ** 0 0 1 0x1.0p-04 0x1.100000p+0 0x1.e00000p-127 0x1.fe0000p-127 ** 0 0 1 0x1.0p-05 0x1.080000p+0 0x1.f00000p-127 0x1.ff8000p-127 ** 0 0 1 0x1.0p-06 0x1.040000p+0 0x1.f80000p-127 0x1.ffe000p-127 ** 0 0 1 0x1.0p-07 0x1.020000p+0 0x1.fc0000p-127 0x1.fff800p-127 ** 0 0 1 0x1.0p-08 0x1.010000p+0 0x1.fe0000p-127 0x1.fffe00p-127 ** 0 0 1 0x1.0p-09 0x1.008000p+0 0x1.ff0000p-127 0x1.ffff80p-127 ** 0 0 1 0x1.0p-10 0x1.004000p+0 0x1.ff8000p-127 0x1.ffffe0p-127 ** 0 0 1 0x1.0p-11 0x1.002000p+0 0x1.ffc000p-127 0x1.fffff8p-127 ** 1 1 0 0x1.0p-12 0x1.001000p+0 0x1.ffe000p-127 0x1.000000p-126 ** 1 1 0 0x1.0p-13 0x1.000800p+0 0x1.fff000p-127 0x1.000000p-126 ** 1 1 0 0x1.0p-14 0x1.000400p+0 0x1.fff800p-127 0x1.000000p-126 ** 1 1 0 0x1.0p-15 0x1.000200p+0 0x1.fffc00p-127 0x1.000000p-126 ** 1 1 0 0x1.0p-16 0x1.000100p+0 0x1.fffe00p-127 0x1.000000p-126 ** 1 1 0 0x1.0p-17 0x1.000080p+0 0x1.ffff00p-127 0x1.000000p-126 ** 1 1 0 0x1.0p-18 0x1.000040p+0 0x1.ffff80p-127 0x1.000000p-126 ** 1 1 0 0x1.0p-19 0x1.000020p+0 0x1.ffffc0p-127 0x1.000000p-126 ** 1 1 0 0x1.0p-20 0x1.000010p+0 0x1.ffffe0p-127 0x1.000000p-126 ** 1 1 0 0x1.0p-21 0x1.000008p+0 0x1.fffff0p-127 0x1.000000p-126 ** 1 1 0 0x1.0p-22 0x1.000004p+0 0x1.fffff8p-127 0x1.000000p-126 ** 1 1 0 0x1.0p-23 0x1.000002p+0 0x1.fffffcp-127 0x1.000000p-126 ** ** Thus, AMD64 detects underflow AFTER rounding, whereas SPARC64 ** detects underflow BEFORE rounding. ** ** MMIX does not recognize the %a format, and has no exception ** handling. For this file for MMIX, I get on a CentOS 6 system: ** ** % /usr/local/bin/mmix-gcc ufl32-mmix.c && mmix a.out ** MINNORMAL = 1.18e-38 ** ** u i s e x y x*y ** 0 0 1 0.5 1.5 5.87747175e-39 8.81620763e-39 ** 0 0 1 0.25 1.25 8.81620763e-39 1.10202595e-38 ** 0 0 1 0.125 1.125 1.02855756e-38 1.15712725e-38 ** 0 0 1 0.0625 1.0625 1.10202595e-38 1.17090258e-38 ** 0 0 1 0.0312 1.03125 1.13876015e-38 1.17434641e-38 ** 0 0 1 0.0156 1.015625 1.15712725e-38 1.17520736e-38 ** 0 0 1 0.00781 1.0078125 1.1663108e-38 1.1754226e-38 ** 0 0 1 0.00391 1.00390625 1.17090258e-38 1.17547641e-38 ** 0 0 1 0.00195 1.00195312 1.17319846e-38 1.17548987e-38 ** 0 0 1 0.000977 1.00097656 1.17434641e-38 1.17549323e-38 ** 0 0 1 0.000488 1.00048828 1.17492038e-38 1.17549407e-38 ** 0 0 0 0.000244 1.00024414 1.17520736e-38 1.17549435e-38 ** 0 0 0 0.000122 1.00012207 1.17535086e-38 1.17549435e-38 ** 0 0 0 6.1e-05 1.00006104 1.1754226e-38 1.17549435e-38 ** 0 0 0 3.05e-05 1.00003052 1.17545848e-38 1.17549435e-38 ** 0 0 0 1.53e-05 1.00001526 1.17547641e-38 1.17549435e-38 ** 0 0 0 7.63e-06 1.00000763 1.17548538e-38 1.17549435e-38 ** 0 0 0 3.81e-06 1.00000381 1.17548987e-38 1.17549435e-38 ** 0 0 0 1.91e-06 1.00000191 1.17549211e-38 1.17549435e-38 ** 0 0 0 9.54e-07 1.00000095 1.17549323e-38 1.17549435e-38 ** 0 0 0 4.77e-07 1.00000048 1.17549379e-38 1.17549435e-38 ** 0 0 0 2.38e-07 1.00000024 1.17549407e-38 1.17549435e-38 ** 0 0 0 1.19e-07 1.00000012 1.17549421e-38 1.17549435e-38 ** ** [03-Aug-2021] ** ===================================================================== */ #if !defined(__MMIX__) #include #endif #include #include #include static const float MINNORMAL = +0x1.0p-126F; /* There are no FE_* flags in MMIX */ #define FE_INEXACT 1 #define FE_UNDERFLOW 2 int feclearexcept(int excepts) { /* DUMMY: not available in MMIX */ return (0); } int fetestexcept(int excepts) { /* DUMMY: not available in MMIX */ return (0); } int issubnormalf(float x) { return (((-MINNORMAL < x) && (x < MINNORMAL)) && (x != 0.0F)); } int main(void) { int i, s, u; volatile float e, w, x, y, z; // (void)printf("MINNORMAL = %.1a\n\n", (double)MINNORMAL); (void)printf("MINNORMAL = %.3g\n\n", (double)MINNORMAL); (void)printf("u i s e x y x*y\n"); for (e = 0.5F; (w = 1.0F + e, w != 1.0F); e *= 0.5F) { x = 1.0F + e; y = (1.0F - e) * MINNORMAL; (void)feclearexcept(FE_UNDERFLOW | FE_INEXACT); z = x * y; u = (fetestexcept(FE_UNDERFLOW) != 0); i = (fetestexcept(FE_INEXACT) != 0); s = issubnormalf(z); // (void)printf("%d %d %d %.1a %.6a %.6a %.6a\n", u, i, s, e, x, y, z); (void)printf("%d %d %d %.3g %.9g %.9g %.9g\n", u, i, s, e, x, y, z); } return (EXIT_SUCCESS); }