浮点数可以有任意精度吗?

2024-12-06 08:39:00
admin
原创
143
摘要:问题描述:只是为了好玩,而且因为它真的很容易,我编写了一个简短的程序来生成嫁接数字,但由于浮点精度问题,它找不到一些较大的例子。def isGrafting(a): for i in xrange(1, int(ceil(log10(a))) + 2): if a == floor((sqrt(a...

问题描述:

只是为了好玩,而且因为它真的很容易,我编写了一个简短的程序来生成嫁接数字,但由于浮点精度问题,它找不到一些较大的例子。

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
", 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 之类的东西?


解决方案 1:

在标准库中,decimal模块可能就是您要找的。此外,我发现mpmath非常有用。文档中也有很多很棒的示例(不幸的是我的办公室电脑没有mpmath安装;否则我会验证一些示例并发布它们)。

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

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 中,这将输出前两行

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

如上所述,这并不完全符合您的预期,并且您可以看到精度越高,结果匹配度越低。请注意,decimal此示例中的模块确实具有更高的精度,因为它更接近实际值。

解决方案 2:

对于这个特殊的问题,decimal这是一个很好的方法,因为它将十进制数字存储为元组!

>>> a = decimal.Decimal(9999999998)
>>> a.as_tuple()
DecimalTuple(sign=0, digits=(9, 9, 9, 9, 9, 9, 9, 9, 9, 8), exponent=0)

由于您要寻找的属性最自然地以十进制表示,因此使用二进制表示有点愚蠢。您链接到的维基百科页面没有指出在“嫁接数字”开始之前可能出现多少个“非嫁接数字”,因此您可以指定:

>>> def isGrafting(dec, max_offset=5):
...     dec_digits = dec.as_tuple().digits
...     sqrt_digits = dec.sqrt().as_tuple().digits
...     windows = [sqrt_digits[o:o + len(dec_digits)] for o in range(max_offset)]
...     return dec_digits in windows
... 
>>> isGrafting(decimal.Decimal(9999999998))
True
>>> isGrafting(decimal.Decimal(77))
True

我认为,由于二进制表示和十进制表示之间的转换, 的结果很有可能比 的结果Decimal.sqrt()更准确,至少就这一点而言math.sqrt()。例如,考虑以下内容:

>>> num = decimal.Decimal(1) / decimal.Decimal(7)
>>> decimal.Decimal(math.sqrt(num) ** 2) * 7
Decimal('0.9999999999999997501998194593')
>>> decimal.Decimal(num.sqrt() ** 2) * 7
Decimal('1.000000000000000000000000000')

解决方案 3:

您可以尝试使用十进制而不是浮点数。

解决方案 4:

Python 没有内置的任意精度浮点数,但有使用 GMP 的第三方 Python 包: gmpy和PyGMP。

解决方案 5:

使用decimal, (这里有一个更清晰的例子):

>>> 2.3-2.2
0.09999999999999964
>>> from decimal import Decimal
>>> Decimal('2.3')-Decimal('2.2')
Decimal('0.1')
>>> float(Decimal('2.3')-Decimal('2.2'))
0.1
>>> 
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用