浮点任意精度是否可用?

问题描述

只是为了好玩,因为它真的很简单,我写了一个小程序来生成 嫁接号码,但由于浮点精度问题,它没有找到一些更大的示例.

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

此代码至少缺少一个已知的嫁接编号.<代码>9999999998 =>99999.99998999999999949999999994999999999374999999912... 乘以 10**5 后似乎会降低额外的精度.

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

所以我写了一个简短的 C++ 程序,看看是我的 CPU 以某种方式截断浮点数还是 python.

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
", a, sqrt((double)a), sqrt((double)a)*1e4, sqrt((double)a)*1e5, sqrt((double)a)*1e6);
  a = 999999999998;
  printf("%ld %.15f %.15f %.15f %.15f
", a, sqrt((double)a), sqrt((double)a)*1e5, sqrt((double)a)*1e6, sqrt((double)a)*1e7);
  a = 99999999999998;
  printf("%ld %.15f %.15f %.15f %.15f
", 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 之类的?

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?


解决方案

在标准库中,decimal 模块可能是您正在寻找的.另外,我发现 mpmath 很有帮助.documentation 也有很多很好的例子(不幸的是我的办公室电脑没有 mpmath 已安装;否则我会验证几个示例并发布它们).

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 have mpmath installed; otherwise I would verify a few examples and post them).

关于 decimal 的一个警告模块,虽然.该模块包含几个用于简单数学运算的内置函数(例如 sqrt),但这些函数的结果可能并不总是与 math 或其他模块中的相应函数匹配更高的精度(尽管它们可能更准确).例如,

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 in math or other modules at higher precisions (although they may be more accurate). For example,

from decimal import *
import math

getcontext().prec = 30
num = Decimal(1) / Decimal(7)

print("   math.sqrt: {0}".format(Decimal(math.sqrt(num))))
print("decimal.sqrt: {0}".format(num.sqrt()))

在 Python 3.2.3 中,这会输出前两行

In Python 3.2.3, this outputs the first two lines

   math.sqrt: 0.37796447300922719758631274089566431939601898193359375
decimal.sqrt: 0.377964473009227227214516536234
actual value: 0.3779644730092272272145165362341800608157513118689214

如前所述,这并不是您所期望的,您可以看到精度越高,结果匹配越少.请注意,decimal 模块在此示例中确实具有更高的准确性,因为它更接近地匹配 实际值.

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.

相关文章