浮点可以任意精度吗?
只是为了好玩,因为它真的很简单,我编写了一个简短的程序来生成嫁接数字,但由于浮点精度问题,它没有找到一些较大的示例。
def isGrafting(a):
for i in xrange(1, int(ceil(log10(a))) + 2):
if a == floor((sqrt(a) * 10**(i-1)) % 10**int(ceil(log10(a)))):
return 1
a = 0
while(1):
if (isGrafting(a)):
print "%d %.15f" % (a, sqrt(a))
a += 1
此代码至少遗漏了一个已知的嫁接编号。 <代码>9999999998 => 99999.99998999999999949999999994999999999374999999912...乘以10**5
后似乎会降低额外的精度。
>>> a = 9999999998
>>> sqrt(a)
99999.99999
>>> a == floor((sqrt(a) * 10**(5)) % 10**int(ceil(log10(a))))
False
>>> floor((sqrt(a) * 10**(5)) % 10**int(ceil(log10(a))))
9999999999.0
>>> print "%.15f" % sqrt(a)
99999.999989999996615
>>> print "%.15f" % (sqrt(a) * 10**5)
9999999999.000000000000000
所以我写了一个简短的C++程序来看看是我的CPU以某种方式截断了浮点数还是python。
#include <cstdio>
#include <cmath>
#include <stdint.h>
int main()
{
uint64_t a = 9999999998;
printf("%ld %.15f %.15f %.15f %.15f\n", a, sqrt((double)a), sqrt((double)a)*1e4, sqrt((double)a)*1e5, sqrt((double)a)*1e6);
a = 999999999998;
printf("%ld %.15f %.15f %.15f %.15f\n", a, sqrt((double)a), sqrt((double)a)*1e5, sqrt((double)a)*1e6, sqrt((double)a)*1e7);
a = 99999999999998;
printf("%ld %.15f %.15f %.15f %.15f\n", a, sqrt((double)a), sqrt((double)a)*1e6, sqrt((double)a)*1e7, sqrt((double)a)*1e8);
return 0;
}
哪个输出:
9999999998 99999.999989999996615 999999999.899999976158142 9999999999.000000000000000 99999999990.000000000000000
999999999998 999999.999998999992386 99999999999.899993896484375 999999999999.000000000000000 9999999999990.000000000000000
99999999999998 9999999.999999899417162 9999999999999.900390625000000 99999999999999.000000000000000 999999999999990.000000000000000
所以看起来我正在努力挑战浮点精度的限制,并且CPU正在砍掉剩余的位,因为它认为剩余的差异是浮点错误。有没有办法在 Python 下解决这个问题?或者我需要转移到 C 并使用 GMP 之类的吗?
Just for fun and because it was really easy, I've written a short program to generate Grafting numbers, but because of floating point precision issues it's not finding some of the larger examples.
def isGrafting(a):
for i in xrange(1, int(ceil(log10(a))) + 2):
if a == floor((sqrt(a) * 10**(i-1)) % 10**int(ceil(log10(a)))):
return 1
a = 0
while(1):
if (isGrafting(a)):
print "%d %.15f" % (a, sqrt(a))
a += 1
This code misses at least one known Grafting number. 9999999998 => 99999.99998999999999949999999994999999999374999999912...
It seems to drop extra precision after multiplying by 10**5
.
>>> a = 9999999998
>>> sqrt(a)
99999.99999
>>> a == floor((sqrt(a) * 10**(5)) % 10**int(ceil(log10(a))))
False
>>> floor((sqrt(a) * 10**(5)) % 10**int(ceil(log10(a))))
9999999999.0
>>> print "%.15f" % sqrt(a)
99999.999989999996615
>>> print "%.15f" % (sqrt(a) * 10**5)
9999999999.000000000000000
So I wrote a short C++ program to see if it was my CPU truncating the floating point number or python somehow.
#include <cstdio>
#include <cmath>
#include <stdint.h>
int main()
{
uint64_t a = 9999999998;
printf("%ld %.15f %.15f %.15f %.15f\n", a, sqrt((double)a), sqrt((double)a)*1e4, sqrt((double)a)*1e5, sqrt((double)a)*1e6);
a = 999999999998;
printf("%ld %.15f %.15f %.15f %.15f\n", a, sqrt((double)a), sqrt((double)a)*1e5, sqrt((double)a)*1e6, sqrt((double)a)*1e7);
a = 99999999999998;
printf("%ld %.15f %.15f %.15f %.15f\n", a, sqrt((double)a), sqrt((double)a)*1e6, sqrt((double)a)*1e7, sqrt((double)a)*1e8);
return 0;
}
Which outputs:
9999999998 99999.999989999996615 999999999.899999976158142 9999999999.000000000000000 99999999990.000000000000000
999999999998 999999.999998999992386 99999999999.899993896484375 999999999999.000000000000000 9999999999990.000000000000000
99999999999998 9999999.999999899417162 9999999999999.900390625000000 99999999999999.000000000000000 999999999999990.000000000000000
So it looks like I'm running up hard against the limits of floating point precision and the CPU is chopping off the remaining bits because it thinks that the remaining difference is floating point error. Is there a way to work around this under Python? Or do I need to move to C and use GMP or something?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
在标准库中,
decimal
模块可能就是您正在寻找的。另外,我发现 mpmath 非常有帮助。 文档也有很多很好的例子(不幸的是我的办公室计算机没有mpmath
安装;否则我会验证一些示例并发布它们)。不过,关于
decimal
模块的一个警告。该模块包含几个用于简单数学运算的内置函数(例如sqrt
),但这些函数的结果可能并不总是与math
或其他模块中的相应函数匹配更高的精度(尽管它们可能更准确)。例如,在 Python 3.2.3 中,这会输出前两行
,如上所述,这并不完全是您所期望的,您可以看到精度越高,结果匹配越少。请注意,在此示例中,decimal 模块确实具有更高的准确性,因为它更接近于 实际值。
In the standard library, the
decimal
module may be what you're looking for. Also, I have found mpmath to be quite helpful. The documentation has many great examples as well (unfortunately my office computer does not havempmath
installed; otherwise I would verify a few examples and post them).One caveat about the
decimal
module, though. The module contains several in-built functions for simple mathematical operations (e.g.sqrt
), but the results from these functions may not always match the corresponding function inmath
or other modules at higher precisions (although they may be more accurate). For example,In Python 3.2.3, this outputs the first two lines
which as stated, isn't exactly what you would expect, and you can see that the higher the precision, the less the results match. Note that the
decimal
module does have more accuracy in this example, since it more closely matches the actual value.对于这个特殊问题,十进制是一个很好的方法,因为它将十进制数字存储为元组!
由于您正在寻找最自然地用十进制表示的属性,因此使用二进制表示有点愚蠢。您链接到的维基百科页面没有表明在“嫁接数字”开始之前可能会出现多少个“非嫁接数字”,因此这可以让您指定:
我认为
Decimal.sqrt(由于二进制表示和十进制表示之间的转换,至少在这一点上, )
比 math.sqrt() 的结果更准确。例如,考虑以下情况:For this particular problem,
decimal
is a great way to go, because it stores the decimal digits as tuples!Since you're looking for a property that is most naturally expressed in decimal notation, it's a bit silly to use a binary representation. The wikipedia page you linked to didn't indicate how many "non-grafting digits" may appear before the "grafting digits" begin, so this lets you specify:
I think there's a good chance the result of
Decimal.sqrt()
will be more accurate, at least for this, than the result ofmath.sqrt()
because of the conversion between binary representation and decimal representation. Consider the following, for example:您可以尝试使用 Decimal 而不是浮点数。
You can try with Decimal instead of floatingpoint.
Python 没有内置的任意精度浮点数,但有使用 GMP 的第 3 方 Python 包: gmpy 和 PyGMP。
Python has no built-in arbitrary-precision floats, but there are 3rd-party Python packages that use GMP: gmpy and PyGMP.
使用
十进制
,(这是一个更清晰的示例):use
decimal
, (here is a clearer example):