gettimeofday: port recent C++ fix to Emacs
[gnulib.git] / tests / test-truncf2.c
index dd849ab..a8797ea 100644 (file)
@@ -1,5 +1,5 @@
 /* Test of rounding towards zero.
-   Copyright (C) 2007-2008 Free Software Foundation, Inc.
+   Copyright (C) 2007-2013 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -16,6 +16,9 @@
 
 /* Written by Bruno Haible <bruno@clisp.org>, 2007.  */
 
+/* When this test fails on some platform, build it together with the gnulib
+   module 'fprintf-posix' for optimal debugging output.  */
+
 #include <config.h>
 
 #include <math.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
-#include <stdlib.h>
 
 #include "isnanf-nolibm.h"
+#include "minus-zero.h"
+#include "macros.h"
 
-#define ASSERT(expr) \
-  do                                                                        \
-    {                                                                       \
-      if (!(expr))                                                          \
-        {                                                                   \
-          fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
-          fflush (stderr);                                                  \
-          abort ();                                                         \
-        }                                                                   \
-    }                                                                       \
-  while (0)
+/* MSVC with option -fp:strict refuses to compile constant initializers that
+   contain floating-point operations.  Pacify this compiler.  */
+#ifdef _MSC_VER
+# pragma fenv_access (off)
+#endif
 
 
 /* The reference implementation, taken from lib/trunc.c.  */
@@ -47,6 +45,9 @@
 #define MANT_DIG FLT_MANT_DIG
 #define L_(literal) literal##f
 
+/* -0.0.  See minus-zero.h.  */
+#define MINUS_ZERO minus_zerof
+
 /* 2^(MANT_DIG-1).  */
 static const DOUBLE TWO_MANT_DIG =
   /* Assume MANT_DIG <= 5 * 31.
@@ -72,29 +73,37 @@ truncf_reference (DOUBLE x)
 
   if (z > L_(0.0))
     {
+      /* For 0 < x < 1, return +0.0 even if the current rounding mode is
+         FE_DOWNWARD.  */
+      if (z < L_(1.0))
+        z = L_(0.0);
       /* Avoid rounding errors for values near 2^k, where k >= MANT_DIG-1.  */
-      if (z < TWO_MANT_DIG)
-       {
-         /* Round to the next integer (nearest or up or down, doesn't matter).  */
-         z += TWO_MANT_DIG;
-         z -= TWO_MANT_DIG;
-         /* Enforce rounding down.  */
-         if (z > y)
-           z -= L_(1.0);
-       }
+      else if (z < TWO_MANT_DIG)
+        {
+          /* Round to the next integer (nearest or up or down, doesn't matter).  */
+          z += TWO_MANT_DIG;
+          z -= TWO_MANT_DIG;
+          /* Enforce rounding down.  */
+          if (z > y)
+            z -= L_(1.0);
+        }
     }
   else if (z < L_(0.0))
     {
+      /* For -1 < x < 0, return -0.0 regardless of the current rounding
+         mode.  */
+      if (z > L_(-1.0))
+        z = MINUS_ZERO;
       /* Avoid rounding errors for values near -2^k, where k >= MANT_DIG-1.  */
-      if (z > - TWO_MANT_DIG)
-       {
-         /* Round to the next integer (nearest or up or down, doesn't matter).  */
-         z -= TWO_MANT_DIG;
-         z += TWO_MANT_DIG;
-         /* Enforce rounding up.  */
-         if (z < y)
-           z += L_(1.0);
-       }
+      else if (z > - TWO_MANT_DIG)
+        {
+          /* Round to the next integer (nearest or up or down, doesn't matter).  */
+          z -= TWO_MANT_DIG;
+          z += TWO_MANT_DIG;
+          /* Enforce rounding up.  */
+          if (z < y)
+            z += L_(1.0);
+        }
     }
   return z;
 }
@@ -114,11 +123,11 @@ correct_result_p (DOUBLE x, DOUBLE result)
   return
     (x >= 0
      ? (x < 1 ? result == L_(0.0) :
-       x - 1 < x ? result <= x && result >= x - 1 && x - result < 1 :
-       equal (result, x))
+        x - 1 < x ? result <= x && result >= x - 1 && x - result < 1 :
+        equal (result, x))
      : (x > -1 ? result == L_(0.0) :
-       x + 1 > x ? result >= x && result <= x + 1 && result - x < 1 :
-       equal (result, x)));
+        x + 1 > x ? result >= x && result <= x + 1 && result - x < 1 :
+        equal (result, x)));
 }
 
 /* Test the function for a given argument.  */
@@ -135,9 +144,11 @@ check (float x)
       return 0;
     else
       {
-       fprintf (stderr, "truncf %g(%a) = %g(%a) or %g(%a)?\n",
-                x, x, reference, reference, result, result);
-       return 1;
+#if GNULIB_TEST_FPRINTF_POSIX
+        fprintf (stderr, "truncf %g(%a) = %g(%a) or %g(%a)?\n",
+                 x, x, reference, reference, result, result);
+#endif
+        return 1;
       }
   }
 }
@@ -154,14 +165,14 @@ main ()
   for (highbits = 0; highbits < (1 << NUM_HIGHBITS); highbits++)
     for (lowbits = 0; lowbits < (1 << NUM_LOWBITS); lowbits++)
       {
-       /* Combine highbits and lowbits into a floating-point number,
-          sign-extending the lowbits to 32-NUM_HIGHBITS bits.  */
-       union { float f; uint32_t i; } janus;
-       janus.i = ((uint32_t) highbits << (32 - NUM_HIGHBITS))
-                 | ((uint32_t) ((int32_t) ((uint32_t) lowbits << (32 - NUM_LOWBITS))
-                                >> (32 - NUM_LOWBITS - NUM_HIGHBITS))
-                    >> NUM_HIGHBITS);
-       error |= check (janus.f);
+        /* Combine highbits and lowbits into a floating-point number,
+           sign-extending the lowbits to 32-NUM_HIGHBITS bits.  */
+        union { float f; uint32_t i; } janus;
+        janus.i = ((uint32_t) highbits << (32 - NUM_HIGHBITS))
+                  | ((uint32_t) ((int32_t) ((uint32_t) lowbits << (32 - NUM_LOWBITS))
+                                 >> (32 - NUM_LOWBITS - NUM_HIGHBITS))
+                     >> NUM_HIGHBITS);
+        error |= check (janus.f);
       }
   return (error ? 1 : 0);
 }