浮点算术运算的不可结合性
结合律(associative law)是一个数学定律,是指计算结果不会因为计算顺序的不同而发生改变,例如:
(a + b) + c = a + (b + c)
(a × b) × c = a × (b × c)
遵循IEEE 754标准的具体实现中,绝大多数浮点数都只能近似的表示,其精确程度取决于精度。由于精度和值域范围的限制,浮点表达式的重排经常会受到限制。由于舍入误差(roundoff error),即使在没有溢出(overflow)和下溢(underflow)的情况下,具体实现中浮点表达式通常也不能使用加法或者乘法的数学结合律(associative law)。以下是一个范例:
|
|
将输出(注:使用ideone编译。):
FLT_EVAL_METHOD = 0
0.000000
2.000000
宏FLT_EVAL_METHOD会影响float类型的浮点操作和浮点常量的评估,其值由具体实现定义。当宏FLT_EVAL_METHOD值为0时,将根据float类型的范围和精度评估所有float类型的浮点操作和浮点常量;当宏FLT_EVAL_METHOD值为1时,将根据double类型的范围和精度评估所有float类型的浮点操作和浮点常量;当宏FLT_EVAL_METHOD值为2时,将根据long double类型的范围和精度评估所有float类型的浮点操作和浮点常量。
上面的例子中,A处的输出仅在宏FLT_EVAL_METHOD值为0时,输出0.000000;如果宏FLT_EVAL_METHOD值为1或者2时,将输出2.000000。
powf(2.0f, 25.0f)返回float类型的2.025.0。2.0+2.025.0的值为1.0000 0000 0000 0000 0000 0001×225。
C语言中的float类型数据在支持IEEE 754标准的计算机上以32位二进制格式表示。
2.025.0的32位二进制格式表示:
0 | 1001 1000 | 0000 0000 0000 0000 0000 000 |
1.0000 0000 0000 0000 0000 0001×225的32位二进制格式表示:
0 | 1001 1000 | 0000 0000 0000 0000 0000 000 |
两者表示形式相同;当数据类型是float类型时,1.0000 0000 0000 0000 0000 0001×225小数点后的1无法表示。
综上所述,通常情况下可认为浮点算术运算不具有可结合性。
主要参考资料:
2、《深入理解计算机系统》原书第3版 作者:Randal E. Bryant David R. O'Hallaron 出版社:机械工业出版社