gpt4 book ai didi

python - 将 Python 浮点值增加最小的可能量

转载 作者:IT老高 更新时间:2023-10-28 20:21:27 24 4
gpt4 key购买 nike

如何在 python 中将浮点值增加最小的数量?


背景:我使用浮点值作为字典键。

偶尔,非常偶尔(也许永远不会,但不一定永远不会),会有碰撞。我想通过尽可能少地增加浮点值来解决这些问题。我该怎么做?

在 C 中,我会旋转尾数位来实现这一点,但我认为这在 Python 中是不可能的。

最佳答案

从 Python 3.9 开始,stdlib 中有 math.nextafter继续阅读旧 Python 版本中的替代方案。

Increment a python floating point value by the smallest possible amount

nextafter(x,y) 函数返回在 y 方向上跟随 x 的下一个离散不同的可表示浮点值。 nextafter() 函数保证在平台上工作或返回一个合理的值以指示下一个值是不可能的。

nextafter() 函数是 POSIX 和 ISO C99 标准的一部分,并且是 _nextafter() in Visual C 。符合 C99 标准的数学库、Visual C、C++、Boost 和 Java 都实现了 IEEE 推荐的 nextafter() 函数或方法。 (老实说,我不知道 .NET 是否有 nextafter()。微软不太关心 C99 或 POSIX。)

没有位旋转函数完全或正确处理边缘情况,例如值通过 0.0、负 0.0、次正规、无穷大、负值、上溢或下溢等。 Here is a reference implementation of nextafter() in C如果这是您的方向,请了解如何进行正确的旋转操作。

在 Python < 3.9 中有两个可靠的解决方法来获取 nextafter() 或其他排除的 POSIX 数学函数:

使用 Numpy:

>>> import numpy
>>> numpy.nextafter(0,1)
4.9406564584124654e-324
>>> numpy.nextafter(.1, 1)
0.10000000000000002
>>> numpy.nextafter(1e6, -1)
999999.99999999988
>>> numpy.nextafter(-.1, 1)
-0.099999999999999992

直接链接到系统数学 DLL:

import ctypes
import sys
from sys import platform as _platform

if _platform == "linux" or _platform == "linux2":
_libm = ctypes.cdll.LoadLibrary('libm.so.6')
_funcname = 'nextafter'
elif _platform == "darwin":
_libm = ctypes.cdll.LoadLibrary('libSystem.dylib')
_funcname = 'nextafter'
elif _platform == "win32":
_libm = ctypes.cdll.LoadLibrary('msvcrt.dll')
_funcname = '_nextafter'
else:
# these are the ones I have access to...
# fill in library and function name for your system math dll
print("Platform", repr(_platform), "is not supported")
sys.exit(0)

_nextafter = getattr(_libm, _funcname)
_nextafter.restype = ctypes.c_double
_nextafter.argtypes = [ctypes.c_double, ctypes.c_double]

def nextafter(x, y):
"Returns the next floating-point number after x in the direction of y."
return _nextafter(x, y)

assert nextafter(0, 1) - nextafter(0, 1) == 0
assert 0.0 + nextafter(0, 1) > 0.0

如果你真的想要一个纯 Python 解决方案:

# handles edge cases correctly on MY computer 
# not extensively QA'd...
import math
# 'double' means IEEE 754 double precision -- c 'double'
epsilon = math.ldexp(1.0, -53) # smallest double that 0.5+epsilon != 0.5
maxDouble = float(2**1024 - 2**971) # From the IEEE 754 standard
minDouble = math.ldexp(1.0, -1022) # min positive normalized double
smallEpsilon = math.ldexp(1.0, -1074) # smallest increment for doubles < minFloat
infinity = math.ldexp(1.0, 1023) * 2

def nextafter(x,y):
"""returns the next IEEE double after x in the direction of y if possible"""
if y==x:
return y #if x==y, no increment

# handle NaN
if x!=x or y!=y:
return x + y

if x >= infinity:
return infinity

if x <= -infinity:
return -infinity

if -minDouble < x < minDouble:
if y > x:
return x + smallEpsilon
else:
return x - smallEpsilon

m, e = math.frexp(x)
if y > x:
m += epsilon
else:
m -= epsilon

return math.ldexp(m,e)

或者,使用 Mark Dickinson's 优秀的 solution

显然 Numpy 解决方案是最简单的。

关于python - 将 Python 浮点值增加最小的可能量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6063755/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com