是
a < b and not(a - b < 0)
由于 float 舍入错误, float 可能吗? 有例子吗?
最佳答案
[此答案旨在作为对 Patricia Shanahan 已经给出的良好答案的学究补充。该答案涵盖了正常情况;在这里,我们担心的是您在实践中不太可能遇到的边缘情况。]
是的,这是完全可能的。这是我非常普通的基于 Intel 的 Mac 笔记本电脑的 Python session :
Enthought Canopy Python 2.7.6 | 64-bit | (default, Jan 29 2014, 17:09:48)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import evil
>>> a = float.fromhex('1p-1022')
>>> b = float.fromhex('1.01p-1022')
>>> a < b and not(a - b < 0)
True
当然,正如导入所示,这里发生了一些邪恶的事情。这是evil.py
的内容. (警告:这是高度特定于平台的,并且所写的仅适用于 OS X。如果 Python 已被编译为使用 SSE2 指令而不是 x87 单元进行浮点运算,则此变体应该适用于 Linux/x64 .我对Windows一无所知。)
# Being lazy: we should really import just the things we need.
from ctypes import *
# Type corresponding to fenv_t from fenv.h. (Platform specific!)
class fenv_t(Structure):
_fields_ = [("control", c_ushort), ("status", c_ushort),
("mxcsr", c_uint), ("reserved", c_char * 8)]
# Wrap fegetenv and fesetenv from the C library.
libc = CDLL("/usr/lib/libc.dylib")
fegetenv = libc.fegetenv
fegetenv.restype, fegetenv.argtypes = c_int, (POINTER(fenv_t),)
fesetenv = libc.fesetenv
fesetenv.restype, fesetenv.argtypes = c_int, (POINTER(fenv_t),)
# Set the flush-to-zero (FTZ) bit in the MXCSR control register.
env = fenv_t()
fegetenv(pointer(env))
env.mxcsr |= 1 << 15
fesetenv(pointer(env))
所以我们在这里做的是弄乱 MXCSR 控制寄存器中保存的 FPU 设置。在支持 SSE 指令集的 Intel 64 处理器上,有两个有趣的标志会影响涉及次正规数的运算行为。设置 FTZ(清零)标志后,会将算术运算的任何次正规输出替换为零。 DAZ(denormals-are-zero)标志在设置时会导致算术运算的任何次正规输入都被视为零。这些标志的意义在于,它们可以显着加快涉及次正规数的运算,但会牺牲对 IEEE 754 标准的遵从性。在上面的代码中,我们在 MXCSR 控制寄存器中设置了 FTZ 标志。
现在我们选择a
和 b
这样两个a
和 b
是正常的,但它们的差异是次正常的。然后 a < b
将是真的(像往常一样),但是 a - b
将是 -0.0
, 以及比较 a - b < 0
失败。
要点是,您使用的浮点格式 是 IEEE 754 格式是不够的。您还需要知道您的操作符合标准。 FTZ 模式是可能失败的一种方式的示例。将此与 Patricia Shanahan 的回答联系起来:evil.py
中的代码正在关闭 IEEE 754 promise 的逐渐下溢。 (感谢@EricPostpischil 在评论中指出这一点。)
关于python - 可能有 `` a < b 和 not(a - b < 0 )`` with floats,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21590883/