/* 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