2015-11-12 190 views
1

可以将两个浮点值(IEEE 754 binary64)作为整数进行比较吗?例如。比较浮点数整数

long long a = * (long long *) ptr_to_double1, 
      b = * (long long *) ptr_to_double2; 
if (a < b) {...} 

假设long longdouble大小是相同的。

+0

对于这样的语法问题,这是非常有帮助的知道你使用计划的语言和版本。这是C++,C,C#,Python等吗? – GKnight

+0

对不起,我忘了提,C. – gordon

+1

你为什么要这样做? –

回答

2

编号两个浮点值(IEEE 754二进制64)不能比较简单作为整数与if (a < b)

IEEE 754 binary64

double的值的顺序是不一样的顺序整数(除非你是一个难得的符号 - 幅度机器上)。认为积极与消极的数字。

double具有像0.0-0.0具有相同值,但不同的位模式值。

double具有“非数字”,它们不像它们的二进制等价整数表示那样进行比较。

如果double的值都是x > 0而不是“不是数字”,那么endian,aliasing和alignment等不是问题,那么OP的想法就可行。

可替代地,更为复杂的条件if() ...将工作 - 见下文

[非IEEE 754 binary64]

double一些使用在有相同值的多个表示的编码。这与“整数”比较不同。


测试代码:需要2的补码,同尾数为double和整数,不占楠。

int compare(double a, double b) { 
    union { 
    double d; 
    int64_t i64; 
    uint64_t u64; 
    } ua, ub; 
    ua.d = a; 
    ub.d = b; 
    // Cope with -0.0 right away 
    if (ua.u64 == 0x8000000000000000) ua.u64 = 0; 
    if (ub.u64 == 0x8000000000000000) ub.u64 = 0; 
    // Signs differ? 
    if ((ua.i64 < 0) != (ub.i64 < 0)) { 
    return ua.i64 >= 0 ? 1 : -1; 
    } 
    // If numbers are negative 
    if (ua.i64 < 0) { 
    ua.u64 = -ua.u64; 
    ub.u64 = -ub.u64; 
    } 
    return (ua.u64 > ub.u64) - (ua.u64 < ub.u64); 
} 

感谢@David C. Rankin的更正。

测试代码

void testcmp(double a, double b) { 
    int t1 = (a > b) - (a < b); 
    int t2 = compare(a, b); 
    if (t1 != t2) { 
    printf("%le %le %d %d\n", a, b, t1, t2); 
    } 

} 

#include <float.h> 
void testcmps() { 
    // Various interesting `double` 
    static const double a[] = { 
     -1.0/0.0, -DBL_MAX, -1.0, -DBL_MIN, -0.0, 
     +0.0, DBL_MIN, 1.0, DBL_MAX, +1.0/0.0 }; 

    int n = sizeof a/sizeof a[0]; 
    for (int i = 0; i < n; i++) { 
    for (int j = 0; j < n; j++) { 
     testcmp(a[i], a[j]); 
    } 
    } 
    puts("!"); 
} 
-2

有两个部分你的问题:

  1. 可以两个浮点数进行比较?答案是肯定的。比较浮点数的大小是完全有效的。通常你想避免等于因截断问题比较看here,但

    if (a < b) 
    

    会工作得很好。

  2. 可以将两个浮点数作为整数进行比较吗?这个答案也是肯定的,但这需要铸造。这个问题应该有助于这个问题的答案:convert from long long to int and the other way back in c++

+0

当然,我可以将浮点数转换为整数,然后将它们进行比较,但是我想要做的是将浮点数的二进制表示并将其视为整数,而不进行转换/转换。例如。 0.001953125 = 0011111101100000000000000000000000000000000000000000000000000000(IEEE 754 binary64)= 4566650022153682944(十进制); -0.001953125 = 1011111101100000000000000000000000000000000000000000000000000000(IEEE 754 binary64)= -4656722014701092864(十进制) – gordon

+0

如果不进行转换,C将遵循变量的类型。这是不可谈判的,因为C是一种类型语言。 – GKnight

0

如果严格施放一个浮点数其相应大小的有符号整数的位值(如你所做的),结果则有符号整数比较将与原始浮点值的比较相同,不包括NaN值。换言之,这种比较对于所有可表示的有限和无限数值是合法的。

换句话说,用于双精度(64位),这种比较将是有效的,如果下面的测试通过:

long long exponentMask = 0x7ff0000000000000; 
long long mantissaMask = 0x000fffffffffffff; 

bool isNumber = ((x & exponentMask) != exponentMask) // Not exp 0x7ff 
       || ((x & mantissaMask) == 0);   // Infinities 

为每个操作数X。

当然,如果您可以预先验证您的浮点值,那么快速的isNaN()测试会更加清晰。您必须进行配置才能了解性能影响。

+0

“然后签名整数比较的结果将是相同的” - >不同意。典型的整数是2的补码,而IEEE 754 binary64是有效的符号幅度。比较两个不同的负数会给出相反的答案。 – chux

+1

更何况,如果没有使用联合(或强制使用'-fno-strict-aliasing'编译)编译器将会(应该)发疯似的警告*解引用类型化的指针会打破严格别名规则*。 –

+0

@chux - D'oh!你是对的。我快速思考了一下,但显然是错误的。正确的方法是检查两个值的符号位。如果两个值都设置了符号位,则首先对它们的值执行符号取反。在测试之后,将这两个值作为有符号整数进行比较。 –

2

是 - 两个花车,好像他们是比较整数位模式(又名“类型双关”)产生在某些情况下限制有意义的结果...

等同于浮点比较时:

  • 两个数也是正的,口服正定零或正无穷大。
  • 一个正数和一个负数,并且您正在使用有符号整数比较。

浮点比较的逆时:

  • 这两个数字是负的,负零或负无穷大。
  • 一个正数和一个负数,并且您正在使用无符号整数比较。

无法比拟的浮点比较时:

  • 任一数字NaN的价值之一 - 与NaN的总是返回false浮点比较,这根本不可能(A < B),(A == B),(B < A)。

负浮点数字有点时髦b/c它们处理的方式与用于整数的2的补码算法非常不同。对负数浮点数的表示做一个整数+1会使它成为一个更大的负数。

随着一点点的操作,就可以使正反两方面的花车与整数运算可比性(这可以派上用场了一些优化):

int32 float_to_comparable_integer(float f) { 
    const uint32 bits = *reinterpret_cast<uint32*>(&f); 
    const uint32 sign_bit = bits & 0x80000000ul; 
    // If your compiler is smart, it will compile this IF-statement into a conditional move (CMOVE) instruction (much faster than an unpredictable branch). 
    if (sign_bit) { 
    bits = 0x7FFFFFF - bits; 
    } 
    return static_cast<int32>(bits); 
} 

而且,这并楠工作值,它总是返回从比较假,并且有多个有效位表示:

  • 信号NaN(W /符号位):0xFF800001,和0xFFBFFFFF之间的任何东西。
  • 信号NaNs(无符号位):0x7F800001和0x7FBFFFFF之间的任何值。
  • 安静的NaNs(带符号位):0xFFC00000和0xFFFFFFFF之间的任何值。
  • 安静的NaNs(无符号位):0x7FC00000和0x7FFFFFFF之间的任何值。

IEEE-754位格式:http://www.puntoflotante.net/FLOATING-POINT-FORMAT-IEEE-754.htm

更多类型 - 双关:https://randomascii.wordpress.com/2012/01/23/stupid-float-tricks-2/