Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 带有准确信息的数字类型?_Python_Floating Accuracy - Fatal编程技术网

Python 带有准确信息的数字类型?

Python 带有准确信息的数字类型?,python,floating-accuracy,Python,Floating Accuracy,最近有人想要一个无冲突散列函数将一百万个值散列为32位散列值。如果你知道,你知道那不可能是无碰撞的。但是想知道概率,我这样计算(从概率1开始,然后对于一百万个值中的每一个,乘以它不是前面的概率): 但是我在那里增加了一百万个浮动,所以我担心会失去越来越多的准确性 有没有一种数字类型,与简单的浮点数不同,它不仅给我一个不准确的数字,而且告诉我它有多不准确?像[2.73e-51,2.74e-51]这样的范围,或者像2.7390147476139603e-51+/-1e-54这样的错误 或者有其他方法

最近有人想要一个无冲突散列函数将一百万个值散列为32位散列值。如果你知道,你知道那不可能是无碰撞的。但是想知道概率,我这样计算(从概率1开始,然后对于一百万个值中的每一个,乘以它不是前面的概率):

但是我在那里增加了一百万个浮动,所以我担心会失去越来越多的准确性

有没有一种数字类型,与简单的浮点数不同,它不仅给我一个不准确的数字,而且告诉我它有多不准确?像
[2.73e-51,2.74e-51]
这样的范围,或者像
2.7390147476139603e-51+/-1e-54这样的错误


或者有其他方法来检查结果的准确性吗?

获得范围的一种方法是使用整数,将概率按10100的比例缩放。对于下限,始终向下舍入;对于上限,始终向上舍入:

>>> lower = 10**100
>>> for i in range(10**6):
        lower = lower * (2**32 - i) // 2**32

>>> lower
27390147476140722271150280539996691121583143636646
调整它们:

upper  27390147476140722271150280539996691121583143640960
p     2.7390147476139603e-51
lower  27390147476140722271150280539996691121583143636646
我们可以看到
p
float
)实际上超出了实际范围,有点太小了。但它的前12位数字是正确的,所以看起来很不错


通过比较
下部
上部
,我们还得到了更多匹配的正确数字:2.73901474761407222711502805399966911215831436e-51。使用更大的比例因子,我们可以得到更多。

这里是一个最坏的情况:在每个操作(乘法或除法)上,显式地将结果乘以1+2^-52或1-2^-52,并检查(使用
断言
)它是否确实产生了影响。这应该估计出不确定性的上限,它仍然很小——它在没有任何断言失败的情况下到达终点,差值是10^9的一部分

import sys

m_upper = (1 + 2**(1 - sys.float_info.mant_dig))
m_lower = (1 - 2**(1 - sys.float_info.mant_dig))

p_upper = p_lower = 1

for i in range(10**6):

    factor = (2**32 - i) / 2**32
    f_upper = factor * m_upper
    f_lower = factor * m_lower

    assert(f_upper > factor)
    assert(f_lower < factor)

    p_upper *= f_upper

    p_upper1 = p_upper * m_upper
    assert(p_upper1 > p_upper)
    p_upper = p_upper1
    
    p_lower *= f_lower

    p_lower1 = p_lower * m_lower
    assert(p_lower1 < p_lower)
    p_lower = p_lower1

print(p_upper, p_lower, p_upper - p_lower)
请注意,如果将
(1-sys.float\u info.mant\u dig)
替换为
-sys.float\u info.mant\u dig
(即使用2^-53而不是2^-52),则断言开始失败。

As,即“和相关概念”

谷歌搜索发现。让我们试试:

from interval import interval

p = interval[1]
for i in range(10**6):
    p *= (2**32 - i) / 2**32
print(p)
输出(运行):

让我们将其与以下公式的边界进行比较:

因此,
区间
解的精确度较低(它是一个较大的区间,只有上下限匹配的前十位),但它是正确的(实际值确实在区间内)。从这个意义上说,我想它永远是正确的,尽管我没有研究它是如何工作的。

(基于)

系数
(2**32-i)/2**32
是准确的,也就是说,它们精确地表示为
浮点
。此外,浮点标准保证乘法得到最准确的
浮点值。它可能低于或高于实际产品,但它是最接近的
float
值。因此,如果我们有意总是偏离下一个更大的
float
值,它永远不会小于实际值,也就是说,它给了我们一个上限。我们通过偏离下一个较小的
float
值得到一个下限

Python 3.9引入了以下内容:

>>> import math
>>> lower = upper = 1
>>> for i in range(10**6):
        factor = (2**32 - i) / 2**32
        lower = math.nextafter(lower * factor, -math.inf)
        upper = math.nextafter(upper * factor, math.inf)

>>> lower, upper
(2.739014747179961e-51, 2.739014748048138e-51)
>>> upper - lower
8.681767916298978e-61

我还不太理解它(我会仔细考虑),但它在
(1+2**(-sys.float\u info.mant\u dig))
中失败的原因是它只有1。但是你仍然可以将其用于
m_lower
,而不是
m_upper
@superbrain,谢谢-我没有测试。我的观点是,使用的值是我通过这种(相当保守的)技术所能实现的最大值。当然,可能有更好的技术可以实现更窄的范围。因此,如果我理解正确,您可以通过使用更大的数字来抵消舍入错误,而使用更小的数字来抵消舍入错误,对吗?现在我正在考虑安装Python3.9,只是为了尝试一下它的功能……是的,这是我的基本想法。我的假设是,如果您一次只执行一个操作,那么任何此类错误都只会影响最后一位,因此,如果您上升/下降到足以获得不同的值,那么这就足以抵消它们。希望这是有效的!是的,我同意这是有效的,而且我真的很喜欢数学。给我一个稍微窄一点的结果区间。你正在寻找和相关的概念。一个web搜索显示和Python实现。@EricPostchil谢谢,将其变成了一个。
2.739014748809663e-51 2.7390147464186476e-51 2.3910154124504752e-60
from interval import interval

p = interval[1]
for i in range(10**6):
    p *= (2**32 - i) / 2**32
print(p)
interval([2.7390147473969355e-51, 2.739014747831127e-51])
interval upper 2.739014747831127e-51
integer upper   27390147476140722271150280539996691121583143640960
integer lower   27390147476140722271150280539996691121583143636646
interval lower 2.7390147473969355e-51
>>> import math
>>> lower = upper = 1
>>> for i in range(10**6):
        factor = (2**32 - i) / 2**32
        lower = math.nextafter(lower * factor, -math.inf)
        upper = math.nextafter(upper * factor, math.inf)

>>> lower, upper
(2.739014747179961e-51, 2.739014748048138e-51)
>>> upper - lower
8.681767916298978e-61