make fma and lrint functions build without full fenv support
authorRich Felker <dalias@aerifal.cx>
Sat, 17 Mar 2012 03:58:49 +0000 (23:58 -0400)
committerRich Felker <dalias@aerifal.cx>
Sat, 17 Mar 2012 03:58:49 +0000 (23:58 -0400)
this is necessary to support archs where fenv is incomplete or
unavailable (presently arm). fma, fmal, and the lrint family should
work perfectly fine with this change; fmaf is slightly broken with
respect to rounding as it depends on non-default rounding modes to do
its work.

src/math/fma.c
src/math/fmaf.c
src/math/fmal.c
src/math/lrint.c

index c53f314..f44ecda 100644 (file)
@@ -199,27 +199,37 @@ double fma(double x, double y, double z)
         * modes other than FE_TONEAREST are painful.
         */
        if (spread < -DBL_MANT_DIG) {
+#ifdef FE_INEXACT
                feraiseexcept(FE_INEXACT);
+#endif
+#ifdef FE_UNDERFLOW
                if (!isnormal(z))
                        feraiseexcept(FE_UNDERFLOW);
+#endif
                switch (oround) {
-               case FE_TONEAREST:
+               default: /* FE_TONEAREST */
                        return (z);
+#ifdef FE_TOWARDZERO
                case FE_TOWARDZERO:
                        if (x > 0.0 ^ y < 0.0 ^ z < 0.0)
                                return (z);
                        else
                                return (nextafter(z, 0));
+#endif
+#ifdef FE_DOWNWARD
                case FE_DOWNWARD:
                        if (x > 0.0 ^ y < 0.0)
                                return (z);
                        else
                                return (nextafter(z, -INFINITY));
-               default:        /* FE_UPWARD */
+#endif
+#ifdef FE_UPWARD
+               case FE_UPWARD:
                        if (x > 0.0 ^ y < 0.0)
                                return (nextafter(z, INFINITY));
                        else
                                return (z);
+#endif
                }
        }
        if (spread <= DBL_MANT_DIG * 2)
index 0dccf10..cc427fb 100644 (file)
@@ -54,7 +54,9 @@ float fmaf(float x, float y, float z)
         * If result is inexact, and exactly halfway between two float values,
         * we need to adjust the low-order bit in the direction of the error.
         */
+#ifdef FE_TOWARDZERO
        fesetround(FE_TOWARDZERO);
+#endif
        volatile double vxy = xy;  /* XXX work around gcc CSE bug */
        double adjusted_result = vxy + z;
        fesetround(FE_TONEAREST);
index 200bd5a..3944c29 100644 (file)
@@ -194,27 +194,37 @@ long double fmal(long double x, long double y, long double z)
         * modes other than FE_TONEAREST are painful.
         */
        if (spread < -LDBL_MANT_DIG) {
+#ifdef FE_INEXACT
                feraiseexcept(FE_INEXACT);
+#endif
+#ifdef FE_UNDERFLOW
                if (!isnormal(z))
                        feraiseexcept(FE_UNDERFLOW);
+#endif
                switch (oround) {
-               case FE_TONEAREST:
+               default: /* FE_TONEAREST */
                        return (z);
+#ifdef FE_TOWARDZERO
                case FE_TOWARDZERO:
                        if (x > 0.0 ^ y < 0.0 ^ z < 0.0)
                                return (z);
                        else
                                return (nextafterl(z, 0));
+#endif
+#ifdef FE_DOWNWARD
                case FE_DOWNWARD:
                        if (x > 0.0 ^ y < 0.0)
                                return (z);
                        else
                                return (nextafterl(z, -INFINITY));
-               default:        /* FE_UPWARD */
+#endif
+#ifdef FE_UPWARD
+               case FE_UPWARD:
                        if (x > 0.0 ^ y < 0.0)
                                return (nextafterl(z, INFINITY));
                        else
                                return (z);
+#endif
                }
        }
        if (spread <= LDBL_MANT_DIG * 2)
index 98d58ad..9754fa7 100644 (file)
@@ -49,8 +49,10 @@ dtype fn(type x)
 
        feholdexcept(&env);
        d = (dtype)roundit(x);
+#if defined(FE_INVALID) && defined(FE_INEXACT)
        if (fetestexcept(FE_INVALID))
                feclearexcept(FE_INEXACT);
+#endif
        feupdateenv(&env);
        return d;
 }