X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fround.c;h=b52bd35858a73a41761fa74e33190191afd80a5e;hb=fc5b3a7190a490a169f2d53a54b393a68fab9ec2;hp=5758fb7c79c571d9f9e7c9d137fe2aa1955cf9d9;hpb=980d2709cea1e46299cb5b4f74f7c7a95d07ef06;p=gnulib.git diff --git a/lib/round.c b/lib/round.c index 5758fb7c7..b52bd3585 100644 --- a/lib/round.c +++ b/lib/round.c @@ -1,5 +1,5 @@ /* Round toward nearest, breaking ties away from zero. - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007, 2010-2012 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 @@ -12,31 +12,38 @@ 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, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + with this program; if not, see . */ /* Written by Ben Pfaff , 2007. Based heavily on code by Bruno Haible. */ -#include +#if ! defined USE_LONG_DOUBLE +# include +#endif -#include +/* Specification. */ #include +#include + +#undef MIN + #ifdef USE_LONG_DOUBLE # define ROUND roundl # define FLOOR floorl # define CEIL ceill # define DOUBLE long double # define MANT_DIG LDBL_MANT_DIG +# define MIN LDBL_MIN # define L_(literal) literal##L -# define HAVE_FLOOR_AND_CEIL (HAVE_DECL_FLOORL && HAVE_DECL_CEILL) +# define HAVE_FLOOR_AND_CEIL HAVE_FLOORL_AND_CEILL #elif ! defined USE_FLOAT # define ROUND round # define FLOOR floor # define CEIL ceil # define DOUBLE double # define MANT_DIG DBL_MANT_DIG +# define MIN DBL_MIN # define L_(literal) literal # define HAVE_FLOOR_AND_CEIL 1 #else /* defined USE_FLOAT */ @@ -45,8 +52,22 @@ # define CEIL ceilf # define DOUBLE float # define MANT_DIG FLT_MANT_DIG +# define MIN FLT_MIN # define L_(literal) literal##f -# define HAVE_FLOOR_AND_CEIL (HAVE_DECL_FLOORF && HAVE_DECL_CEILF) +# define HAVE_FLOOR_AND_CEIL HAVE_FLOORF_AND_CEILF +#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 + +/* 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 /* If we're being included from test-round2[f].c, it already defined names for @@ -67,7 +88,7 @@ DOUBLE FLOOR_BASED_ROUND (DOUBLE x) { - if (x >= L_(0.0)) + if (x >= L_(0.0)) { DOUBLE y = FLOOR (x); if (x - y >= L_(0.5)) @@ -114,41 +135,40 @@ FLOOR_FREE_ROUND (DOUBLE x) { /* Avoid rounding error for x = 0.5 - 2^(-MANT_DIG-1). */ if (z < L_(0.5)) - z = L_(0.0); + z = L_(0.0); /* Avoid rounding errors for values near 2^k, where k >= MANT_DIG-1. */ else if (z < TWO_MANT_DIG) - { - /* Add 0.5 to the absolute value. */ - y = z += L_(0.5); - /* Round to the next integer (nearest or up or down, doesn't + { + /* Add 0.5 to the absolute value. */ + y = z += L_(0.5); + /* 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); - } + z += TWO_MANT_DIG; + z -= TWO_MANT_DIG; + /* Enforce rounding down. */ + if (z > y) + z -= L_(1.0); + } } else if (z < L_(0.0)) { /* Avoid rounding error for x = -(0.5 - 2^(-MANT_DIG-1)). */ if (z > - L_(0.5)) - z = L_(0.0); + z = MINUS_ZERO; /* Avoid rounding errors for values near -2^k, where k >= MANT_DIG-1. */ else if (z > -TWO_MANT_DIG) - { - /* Add 0.5 to the absolute value. */ - y = z -= L_(0.5); - /* Round to the next integer (nearest or up or down, doesn't + { + /* Add 0.5 to the absolute value. */ + y = z -= L_(0.5); + /* 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); - } + z -= TWO_MANT_DIG; + z += TWO_MANT_DIG; + /* Enforce rounding up. */ + if (z < y) + z += L_(1.0); + } } return z; } #endif /* FLOOR_FREE_ROUND */ -