changeset 13975:0af73906c87a

Tests for module 'ceil'. * modules/ceil-tests: New file. * tests/test-ceil1.c: New file, based on tests/test-ceill.c. * tests/test-ceil2.c: New file, based on tests/test-ceilf2.c.
author Bruno Haible <bruno@clisp.org>
date Tue, 21 Dec 2010 17:28:25 +0100
parents e0c1a15af0da
children 31894df2c5e8
files ChangeLog modules/ceil-tests tests/test-ceil1.c tests/test-ceil2.c
diffstat 4 files changed, 254 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2010-12-21  Bruno Haible  <bruno@clisp.org>
+
+	Tests for module 'ceil'.
+	* modules/ceil-tests: New file.
+	* tests/test-ceil1.c: New file, based on tests/test-ceill.c.
+	* tests/test-ceil2.c: New file, based on tests/test-ceilf2.c.
+
 2010-12-21  Bruno Haible  <bruno@clisp.org>
 
 	Tests for module 'floor'.
new file mode 100644
--- /dev/null
+++ b/modules/ceil-tests
@@ -0,0 +1,21 @@
+Files:
+tests/test-ceil1.c
+tests/test-ceil2.c
+tests/minus-zero.h
+tests/nan.h
+tests/signature.h
+tests/macros.h
+
+Depends-on:
+float
+isnand-nolibm
+stdbool
+stdint
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-ceil1 test-ceil2
+check_PROGRAMS += test-ceil1 test-ceil2
+test_ceil1_LDADD = $(LDADD) @CEIL_LIBM@
+test_ceil2_LDADD = $(LDADD) @CEIL_LIBM@
new file mode 100644
--- /dev/null
+++ b/tests/test-ceil1.c
@@ -0,0 +1,67 @@
+/* Test of rounding towards positive infinity.
+   Copyright (C) 2007-2010 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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2007.  */
+
+#include <config.h>
+
+#include <math.h>
+
+#include "signature.h"
+SIGNATURE_CHECK (ceil, double, (double));
+
+#include <float.h>
+
+#include "isnand-nolibm.h"
+#include "minus-zero.h"
+#include "nan.h"
+#include "macros.h"
+
+int
+main ()
+{
+  /* Zero.  */
+  ASSERT (ceil (0.0) == 0.0);
+  ASSERT (ceil (minus_zerod) == 0.0);
+  /* Positive numbers.  */
+  ASSERT (ceil (0.3) == 1.0);
+  ASSERT (ceil (0.7) == 1.0);
+  ASSERT (ceil (1.0) == 1.0);
+  ASSERT (ceil (1.001) == 2.0);
+  ASSERT (ceil (1.5) == 2.0);
+  ASSERT (ceil (1.999) == 2.0);
+  ASSERT (ceil (2.0) == 2.0);
+  ASSERT (ceil (65535.999) == 65536.0);
+  ASSERT (ceil (65536.0) == 65536.0);
+  ASSERT (ceil (2.341e31) == 2.341e31);
+  /* Negative numbers.  */
+  ASSERT (ceil (-0.3) == 0.0);
+  ASSERT (ceil (-0.7) == 0.0);
+  ASSERT (ceil (-1.0) == -1.0);
+  ASSERT (ceil (-1.5) == -1.0);
+  ASSERT (ceil (-1.999) == -1.0);
+  ASSERT (ceil (-2.0) == -2.0);
+  ASSERT (ceil (-65535.999) == -65535.0);
+  ASSERT (ceil (-65536.0) == -65536.0);
+  ASSERT (ceil (-2.341e31) == -2.341e31);
+  /* Infinite numbers.  */
+  ASSERT (ceil (1.0 / 0.0) == 1.0 / 0.0);
+  ASSERT (ceil (-1.0 / 0.0) == -1.0 / 0.0);
+  /* NaNs.  */
+  ASSERT (isnand (ceil (NaNd ())));
+
+  return 0;
+}
new file mode 100644
--- /dev/null
+++ b/tests/test-ceil2.c
@@ -0,0 +1,159 @@
+/* Test of rounding towards positive infinity.
+   Copyright (C) 2007-2010 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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* 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 <float.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "isnand-nolibm.h"
+#include "macros.h"
+
+
+/* The reference implementation, taken from lib/ceil.c.  */
+
+#define DOUBLE double
+#define MANT_DIG DBL_MANT_DIG
+#define L_(literal) literal
+
+/* 2^(MANT_DIG-1).  */
+static const DOUBLE TWO_MANT_DIG =
+  /* Assume MANT_DIG <= 5 * 31.
+     Use the identity
+       n = floor(n/5) + floor((n+1)/5) + ... + floor((n+4)/5).  */
+  (DOUBLE) (1U << ((MANT_DIG - 1) / 5))
+  * (DOUBLE) (1U << ((MANT_DIG - 1 + 1) / 5))
+  * (DOUBLE) (1U << ((MANT_DIG - 1 + 2) / 5))
+  * (DOUBLE) (1U << ((MANT_DIG - 1 + 3) / 5))
+  * (DOUBLE) (1U << ((MANT_DIG - 1 + 4) / 5));
+
+DOUBLE
+ceil_reference (DOUBLE x)
+{
+  /* The use of 'volatile' guarantees that excess precision bits are dropped
+     at each addition step and before the following comparison at the caller's
+     site.  It is necessary on x86 systems where double-floats are not IEEE
+     compliant by default, to avoid that the results become platform and compiler
+     option dependent.  'volatile' is a portable alternative to gcc's
+     -ffloat-store option.  */
+  volatile DOUBLE y = x;
+  volatile DOUBLE z = y;
+
+  if (z > L_(0.0))
+    {
+      /* Work around ICC's desire to optimize denormal floats to 0.  */
+      if (z < DBL_MIN)
+        return L_(1.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 up.  */
+          if (z < y)
+            z += L_(1.0);
+        }
+    }
+  else if (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 up.  */
+          if (z < y)
+            z += L_(1.0);
+        }
+    }
+  return z;
+}
+
+
+/* Test for equality.  */
+static int
+equal (DOUBLE x, DOUBLE y)
+{
+  return (isnand (x) ? isnand (y) : x == y);
+}
+
+/* Test whether the result for a given argument is correct.  */
+static bool
+correct_result_p (DOUBLE x, DOUBLE result)
+{
+  return
+    (x > 0 && x <= 1 ? result == L_(1.0) :
+     x + 1 > x ? result >= x && result <= x + 1 && result - x < 1 :
+     equal (result, x));
+}
+
+/* Test the function for a given argument.  */
+static int
+check (double x)
+{
+  /* If the reference implementation is incorrect, bail out immediately.  */
+  double reference = ceil_reference (x);
+  ASSERT (correct_result_p (x, reference));
+  /* If the actual implementation is wrong, return an error code.  */
+  {
+    double result = ceil (x);
+    if (correct_result_p (x, result))
+      return 0;
+    else
+      {
+#if GNULIB_TEST_FPRINTF_POSIX
+        fprintf (stderr, "ceil %g(%a) = %g(%a) or %g(%a)?\n",
+                 x, x, reference, reference, result, result);
+#endif
+        return 1;
+      }
+  }
+}
+
+#define NUM_HIGHBITS 12
+#define NUM_LOWBITS 4
+
+int
+main ()
+{
+  unsigned int highbits;
+  unsigned int lowbits;
+  int error = 0;
+  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 64-NUM_HIGHBITS bits.  */
+        union { double f; uint64_t i; } janus;
+        janus.i = ((uint64_t) highbits << (64 - NUM_HIGHBITS))
+                  | ((uint64_t) ((int64_t) ((uint64_t) lowbits << (64 - NUM_LOWBITS))
+                                 >> (64 - NUM_LOWBITS - NUM_HIGHBITS))
+                     >> NUM_HIGHBITS);
+        error |= check (janus.f);
+      }
+  return (error ? 1 : 0);
+}