/* Comparison of integer and floating-point numbers by value.
Copyright (C) 2011 Free Software Foundation, Inc.
Written by Bruno Haible
, 2011.
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
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
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. */
#include
/* In comparison expressions like (x < y), where x is an integer value and
y is a floating-point value, the "usual arithmetic conversion are performed"
(ISO C 99 section 6.5.8.(3)), that means, the integer value x is converted
to the floating-point type of y (ISO C 99 section 6.3.1.8).
This leads to results that don't match the mathematical values. The
following examples assume IEEE 754 'float' and 'double' types.
(16777217 > 16777216.0f) => false; true by values.
(16777217 == 16777216.0f) => true; false by values.
(9007199254740993LL > 9007199254740992.0) => false; true by values.
(9007199254740993LL == 9007199254740992.0) => true; false by values.
The function in this file compares numbers by value. */
#include
#include
#include
#include "intprops.h"
#define I_TYPE long long
#define I_BITS (sizeof (I_TYPE) * CHAR_BIT - TYPE_SIGNED (I_TYPE))
#define F_TYPE double
#define FLT_RADIX_BITS (FLT_RADIX == 2 ? 1 : FLT_RADIX == 4 ? 2 : 0)
#define F_MANTISSA_BITS (DBL_MANT_DIG * FLT_RADIX_BITS)
#define COMPARE compare_longlong_double
/* Compare x, of integral type I_TYPE, and y, of floating-point type F_TYPE
and not a NaN value.
Return +1 if x is greater than y, -1 if x is less than y, and 0 if x and y
are equal. */
int
COMPARE (I_TYPE x, F_TYPE y)
{
if (I_BITS <= F_MANTISSA_BITS
|| (x <= ((I_TYPE) 1 << F_MANTISSA_BITS)
&& (!TYPE_SIGNED (I_TYPE) || x >= - ((I_TYPE) 1 << F_MANTISSA_BITS))))
{
/* x can be converted to F_TYPE without loss of precision. */
F_TYPE xf = (F_TYPE) x;
/* Verify that there is no loss of precision. */
if ((I_TYPE) xf != x)
abort ();
return (xf > y ? 1 : xf < y ? -1 : 0);
}
else
{
/* Prepare to convert y to I_TYPE. */
if (TYPE_SIGNED (I_TYPE) && x < 0)
{
if (y >= - (F_TYPE) ((I_TYPE) 1 << F_MANTISSA_BITS))
/* x < - 2^F_MANTISSA_BITS <= y. */
return -1;
/* x, y both < - 2^F_MANTISSA_BITS. */
/* NB: TYPE_MINIMUM (I_TYPE) == - 2^I_BITS = 2 * - 2^(I_BITS-1) */
if (y < (F_TYPE) 2 * - (F_TYPE) ((I_TYPE) 1 << (I_BITS - 1)))
/* x >= TYPE_MINIMUM (I_TYPE) > y. */
return 1;
}
else
{
if (y <= (F_TYPE) ((I_TYPE) 1 << F_MANTISSA_BITS))
/* x > 2^F_MANTISSA_BITS >= y. */
return 1;
/* x, y both > 2^F_MANTISSA_BITS. */
/* NB: TYPE_MAXIMUM (I_TYPE) + 1 == 2^I_BITS = 2 * 2^(I_BITS-1) */
if (y >= (F_TYPE) 2 * (F_TYPE) ((I_TYPE) 1 << (I_BITS - 1)))
/* x <= TYPE_MAXIMUM (I_TYPE) < TYPE_MAXIMUM (I_TYPE) + 1 <= y. */
return -1;
}
/* y can be converted to I_TYPE without loss of precision. */
{
I_TYPE yi = (I_TYPE) y;
/* Verify that there is no loss of precision. */
if ((F_TYPE) yi != y)
abort ();
return (x > yi ? 1 : x < yi ? -1 : 0);
}
}
}
#ifdef TEST
#include
int
main ()
{
printf ("%d\n", compare_longlong_double (9007199254740993LL, 9007199254740992.0)); /* expect 1 */
printf ("%d\n", compare_longlong_double (-9007199254740993LL, -9007199254740992.0)); /* expect -1 */
printf ("%d\n", compare_longlong_double (9223372036854775807LL, 9223372036854775808.0)); /* expect -1 */
printf ("%d\n", compare_longlong_double (-9223372036854775807LL-1, -9223372036854775808.0)); /* expect 0 */
printf ("%d\n", compare_longlong_double (-9223372036854775807LL, -9223372036854775808.0)); /* expect 1 */
return 0;
}
#endif