/* Test of rounding towards zero.
- Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007-2011 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
/* 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 "isnan.h"
-#define ASSERT(expr) \
- do \
- { \
- if (!(expr)) \
- { \
- fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
- abort (); \
- } \
- } \
- while (0)
+#include "isnand-nolibm.h"
+#include "minus-zero.h"
+#include "macros.h"
/* The reference implementation, taken from lib/trunc.c. */
#define MANT_DIG DBL_MANT_DIG
#define L_(literal) literal
+/* -0.0. See minus-zero.h. */
+#define MINUS_ZERO minus_zerod
+
/* 2^(MANT_DIG-1). */
static const DOUBLE TWO_MANT_DIG =
/* Assume MANT_DIG <= 5 * 31.
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;
}
static int
equal (DOUBLE x, DOUBLE y)
{
- return (isnan (x) ? isnan (y) : x == y);
+ return (isnand (x) ? isnand (y) : x == y);
}
/* Test whether the result for a given argument is correct. */
return
(x >= 0
? (x < 1 ? result == L_(0.0) :
- x - 1 < x ? result <= x && result > x - 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 :
- equal (result, x)));
+ x + 1 > x ? result >= x && result <= x + 1 && result - x < 1 :
+ equal (result, x)));
}
/* Test the function for a given argument. */
return 0;
else
{
- fprintf (stderr, "trunc %g(%a) = %g(%a) or %g(%a)?\n",
- x, x, reference, reference, result, result);
- return 1;
+#if GNULIB_TEST_FPRINTF_POSIX
+ fprintf (stderr, "trunc %g(%a) = %g(%a) or %g(%a)?\n",
+ x, x, reference, reference, result, result);
+#endif
+ return 1;
}
}
}
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 { 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);
+ /* Combine highbits and lowbits into a floating-point number,
+ sign-extending the lowbits to 32-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);
}