/* Round towards positive infinity.
- Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2010-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
#include <float.h>
+#undef MIN
+
#ifdef USE_LONG_DOUBLE
# 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.
{
/* 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);
- }
+ {
+ /* 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))
{
+ /* 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;
}