summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2010-12-22 16:07:08 +0100
committerBruno Haible <bruno@clisp.org>2010-12-22 16:07:08 +0100
commit3be902cd0bdb566284ceb3f6fae538391da1faed (patch)
tree2f7150676756947767ef52c432e108b7fd6e767c
parent9ca8092d849ed03418229af9a2aefdf784fd4db9 (diff)
downloadgnulib-3be902cd0bdb566284ceb3f6fae538391da1faed.tar.gz
ceil: Implement result sign according to IEEE 754.
* lib/ceil.c (MIN, MINUS_ZERO): New macros. (FUNC): Return -0.0 for -1 < x < 0. * tests/test-ceil2.c: Include minus-zero.h. (MINUS_ZERO): New macro. (ceil_reference): Keep in sync with lib/ceil.c. * tests/test-ceilf2.c: Include minus-zero.h. (MINUS_ZERO): New macro. (ceilf_reference): Keep in sync with lib/ceil.c. * tests/test-ceilf-ieee.c (main): Test also values between -1 and 1. * tests/test-ceil-ieee.c (main): Likewise. * tests/test-ceill-ieee.c (main): Likewise.
-rw-r--r--ChangeLog13
-rw-r--r--lib/ceil.c18
-rw-r--r--tests/test-ceil-ieee.c11
-rw-r--r--tests/test-ceil2.c10
-rw-r--r--tests/test-ceilf-ieee.c11
-rw-r--r--tests/test-ceilf2.c10
-rw-r--r--tests/test-ceill-ieee.c11
7 files changed, 80 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index de2decf06f..3c1cb7749f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
2010-12-22 Bruno Haible <bruno@clisp.org>
+ ceil: Implement result sign according to IEEE 754.
+ * lib/ceil.c (MIN, MINUS_ZERO): New macros.
+ (FUNC): Return -0.0 for -1 < x < 0.
+ * tests/test-ceil2.c: Include minus-zero.h.
+ (MINUS_ZERO): New macro.
+ (ceil_reference): Keep in sync with lib/ceil.c.
+ * tests/test-ceilf2.c: Include minus-zero.h.
+ (MINUS_ZERO): New macro.
+ (ceilf_reference): Keep in sync with lib/ceil.c.
+ * tests/test-ceilf-ieee.c (main): Test also values between -1 and 1.
+ * tests/test-ceil-ieee.c (main): Likewise.
+ * tests/test-ceill-ieee.c (main): Likewise.
+
floor: Implement result sign according to IEEE 754.
* lib/floor.c (FUNC): Return +0.0 for 0 < x < 1.
* tests/test-floor2.c (floor_reference): Keep in sync with lib/floor.c.
diff --git a/lib/ceil.c b/lib/ceil.c
index 866804b18b..2ed16540ae 100644
--- a/lib/ceil.c
+++ b/lib/ceil.c
@@ -1,5 +1,5 @@
/* Round towards positive infinity.
- Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc.
+ 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
@@ -27,19 +27,29 @@
# define FUNC ceill
# define DOUBLE long double
# define MANT_DIG LDBL_MANT_DIG
+# define MIN LDBL_MIN
# define L_(literal) literal##L
#elif ! defined USE_FLOAT
# define FUNC ceil
# define DOUBLE double
# define MANT_DIG DBL_MANT_DIG
+# define MIN DBL_MIN
# define L_(literal) literal
#else /* defined USE_FLOAT */
# define FUNC ceilf
# define DOUBLE float
# define MANT_DIG FLT_MANT_DIG
+# define MIN FLT_MIN
# define L_(literal) literal##f
#endif
+/* -0.0. See minus-zero.h. */
+#if defined __hpux || defined __sgi || defined __ICC
+# define MINUS_ZERO (-MIN * MIN)
+#else
+# define MINUS_ZERO L_(-0.0)
+#endif
+
/* 2^(MANT_DIG-1). */
static const DOUBLE TWO_MANT_DIG =
/* Assume MANT_DIG <= 5 * 31.
@@ -78,8 +88,12 @@ FUNC (DOUBLE x)
}
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)
+ else if (z > - TWO_MANT_DIG)
{
/* Round to the next integer (nearest or up or down, doesn't matter). */
z -= TWO_MANT_DIG;
diff --git a/tests/test-ceil-ieee.c b/tests/test-ceil-ieee.c
index 06cfeff9e0..14ca3347f2 100644
--- a/tests/test-ceil-ieee.c
+++ b/tests/test-ceil-ieee.c
@@ -24,9 +24,20 @@
int
main ()
{
+ /* See IEEE 754, section 6.3:
+ "the sign of the result of the round floating-point number to
+ integral value operation is the sign of the operand. These rules
+ shall apply even when operands or results are zero or infinite." */
+
/* Zero. */
ASSERT (!signbit (ceil (0.0)));
ASSERT (!!signbit (ceil (minus_zerod)) == !!signbit (minus_zerod));
+ /* Positive numbers. */
+ ASSERT (!signbit (ceil (0.3)));
+ ASSERT (!signbit (ceil (0.7)));
+ /* Negative numbers. */
+ ASSERT (!!signbit (ceil (-0.3)) == !!signbit (minus_zerod));
+ ASSERT (!!signbit (ceil (-0.7)) == !!signbit (minus_zerod));
return 0;
}
diff --git a/tests/test-ceil2.c b/tests/test-ceil2.c
index c26ccc340a..74f8014c4d 100644
--- a/tests/test-ceil2.c
+++ b/tests/test-ceil2.c
@@ -29,6 +29,7 @@
#include <stdio.h>
#include "isnand-nolibm.h"
+#include "minus-zero.h"
#include "macros.h"
@@ -38,6 +39,9 @@
#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.
@@ -79,8 +83,12 @@ ceil_reference (DOUBLE x)
}
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)
+ else if (z > - TWO_MANT_DIG)
{
/* Round to the next integer (nearest or up or down, doesn't matter). */
z -= TWO_MANT_DIG;
diff --git a/tests/test-ceilf-ieee.c b/tests/test-ceilf-ieee.c
index 475e4f416c..15a9fbf49f 100644
--- a/tests/test-ceilf-ieee.c
+++ b/tests/test-ceilf-ieee.c
@@ -37,9 +37,20 @@ main (int argc, char **argv _GL_UNUSED)
{
float (*my_ceilf) (float) = argc ? ceilf : dummy;
+ /* See IEEE 754, section 6.3:
+ "the sign of the result of the round floating-point number to
+ integral value operation is the sign of the operand. These rules
+ shall apply even when operands or results are zero or infinite." */
+
/* Zero. */
ASSERT (!signbit (my_ceilf (0.0f)));
ASSERT (!!signbit (my_ceilf (minus_zerof)) == !!signbit (minus_zerof));
+ /* Positive numbers. */
+ ASSERT (!signbit (my_ceilf (0.3f)));
+ ASSERT (!signbit (my_ceilf (0.7f)));
+ /* Negative numbers. */
+ ASSERT (!!signbit (my_ceilf (-0.3f)) == !!signbit (minus_zerof));
+ ASSERT (!!signbit (my_ceilf (-0.7f)) == !!signbit (minus_zerof));
return 0;
}
diff --git a/tests/test-ceilf2.c b/tests/test-ceilf2.c
index 3455cbf3e9..b0893416b5 100644
--- a/tests/test-ceilf2.c
+++ b/tests/test-ceilf2.c
@@ -29,6 +29,7 @@
#include <stdio.h>
#include "isnanf-nolibm.h"
+#include "minus-zero.h"
#include "macros.h"
@@ -38,6 +39,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.
@@ -79,8 +83,12 @@ ceilf_reference (DOUBLE x)
}
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)
+ else if (z > - TWO_MANT_DIG)
{
/* Round to the next integer (nearest or up or down, doesn't matter). */
z -= TWO_MANT_DIG;
diff --git a/tests/test-ceill-ieee.c b/tests/test-ceill-ieee.c
index e7b541c831..0e06c0022d 100644
--- a/tests/test-ceill-ieee.c
+++ b/tests/test-ceill-ieee.c
@@ -29,9 +29,20 @@ main ()
BEGIN_LONG_DOUBLE_ROUNDING ();
+ /* See IEEE 754, section 6.3:
+ "the sign of the result of the round floating-point number to
+ integral value operation is the sign of the operand. These rules
+ shall apply even when operands or results are zero or infinite." */
+
/* Zero. */
ASSERT (!signbit (ceill (0.0L)));
ASSERT (!!signbit (ceill (minus_zerol)) == !!signbit (minus_zerol));
+ /* Positive numbers. */
+ ASSERT (!signbit (ceill (0.3L)));
+ ASSERT (!signbit (ceill (0.7L)));
+ /* Negative numbers. */
+ ASSERT (!!signbit (ceill (-0.3L)) == !!signbit (minus_zerol));
+ ASSERT (!!signbit (ceill (-0.7L)) == !!signbit (minus_zerol));
return 0;
}