[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: modules 'round', 'roundf', 'roundl' for review
From: |
Bruno Haible |
Subject: |
Re: modules 'round', 'roundf', 'roundl' for review |
Date: |
Sun, 7 Oct 2007 06:14:42 +0200 |
User-agent: |
KMail/1.5.4 |
Ben Pfaff wrote:
> There is a huge amount of redundancy in the m4 code across all
> six modules (trunc*, round*) and perhaps others. Perhaps I
> should write a common m4 macro that just takes a parameter or two
> and avoids the redundancy. Bruno, do you think that this is a
> good idea?
It may be a good idea in a year or so. For now, we have not yet tested
these functions on various platforms. I expect that we will discover
bugs in AIX, HP-UX, BeOS etc. - and that after the workarounds are
in place, the symmetry of the macros is gone.
> +DOUBLE
> +ROUND (DOUBLE x)
> +{
> + if (x >= L_(0.0))
> + {
> + DOUBLE y = FLOOR (x);
> + if (x - y >= L_(0.5))
> + y += L_(1.0);
> + return y;
> + }
> + else
> + {
> + DOUBLE y = FLOOR (-x);
> + if (-x - y >= L_(0.5))
> + y += L_(1.0);
> + return -y;
It's less arithmetic operations if you use CEIL, knowing that
FLOOR (-x) = - CEIL(x).
I would have written the function like this:
DOUBLE
ROUND (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))
{
/* Add 0.5 to the absolute value. */
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);
}
else if (z < L_(0.0))
{
/* Add 0.5 to the absolute value. */
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);
}
return z;
}
Can you evaluate the two implementations against each other (regarding
numerical correctness, number of operations, etc.) and then choose the
best parts of each?
> diff --git a/tests/test-roundf.c b/tests/test-roundf.c
> new file mode 100644
> index 0000000..56fc1db
> --- /dev/null
> +++ b/tests/test-roundf.c
> + ASSERT (roundf (65535.999f) == 65536.0f);
> + ASSERT (roundf (65536.0f) == 65536.0f);
> + ASSERT (roundf (65536.001f) == 65536.0f);
In the usual IEEE single-float arithmetic, 65535.999f and 65536.001f
are the same as 65536.0f. You need to remove one of the mantissa digits
to make the test meaningful.
> diff --git a/tests/test-roundl.c b/tests/test-roundl.c
> new file mode 100644
> index 0000000..4e0ef4e
> --- /dev/null
> +++ b/tests/test-roundl.c
> +/* The Compaq (ex-DEC) C 6.4 compiler chokes on the expression 0.0 / 0.0. */
> +#ifdef __DECC
> +static long double
> +NaN ()
> +{
> + static long double zero = 0.0L;
> + return zero / zero;
> +}
> +#else
> +# define NaN() (0.0L / 0.0L)
> +#endif
This workaround is not needed for 'long double'.
> +int
> +main ()
> +{
Will not work on NetBSD without the use of BEGIN_LONG_DOUBLE_ROUNDING ();
(uses module 'fpucw').
Bruno
- modules 'round', 'roundf', 'roundl' for review, Ben Pfaff, 2007/10/06
- Re: modules 'round', 'roundf', 'roundl' for review,
Bruno Haible <=
- Re: modules 'round', 'roundf', 'roundl' for review, Ben Pfaff, 2007/10/07
- Re: modules 'round', 'roundf', 'roundl' for review, Bruno Haible, 2007/10/12
- 'round' modules takes 3 (was: Re: modules 'round', 'roundf', 'roundl' for review), Ben Pfaff, 2007/10/19
- Re: 'round' modules takes 3 (was: Re: modules 'round', 'roundf', 'roundl' for review), Bruno Haible, 2007/10/20
- Re: 'round' modules takes 3, Ben Pfaff, 2007/10/20
- Re: 'round' modules takes 3, Bruno Haible, 2007/10/21
- Re: 'round' modules takes 3, Bruno Haible, 2007/10/21
- Re: 'round' modules takes 3, Ben Pfaff, 2007/10/21
- Re: 'round' modules takes 3, Ben Pfaff, 2007/10/21
- Re: 'round' modules takes 3, Bruno Haible, 2007/10/23