16331239353195370.0有特殊意义吗?

92

使用 import numpy as np 时,我注意到

np.tan(np.pi/2)

提供标题中的数字而不是 np.inf

16331239353195370.0

我对这个数字很好奇。它是否与某些系统机器精度参数有关?我能从什么地方计算它吗?(我在思考类似于 sys.float_info 的内容)

编辑:相同的结果确实可以在其他环境中再现,如Java、Octave、Matlab...但建议的重复问题并没有解释为什么。


11
https://dev59.com/w2nWa4cB1Zd3GeqPximg - Padraic Cunningham
11
我不喜欢那个答案,完全是含糊其辞,没有真正解释原因。 "嗯,用弧度表示的 tan(pi/2) 本质上是无限的,不是吗?" 并没有解释为什么 - 正如提问者在这里问的那样 - 答案实际上不是 np.inf。但是,不仅可以简单地解释为什么它不是,还可以解释为什么答案恰好是所看到的 - 所以我这样做了;-) - Tim Peters
1个回答

123

pi无法被Python浮点类型(同平台C的double类型)准确表示。使用最接近可表示的近似值。

这是我电脑上使用的精确近似值(可能与您的电脑相同):

>>> import math
>>> (math.pi / 2).as_integer_ratio()
(884279719003555, 562949953421312)
为了找到这个比值的正切,我现在要切换到wxMaxima:
(%i1) fpprec: 32;
(%o1) 32
(%i2) tan(bfloat(884279719003555) / 562949953421312);
(%o2) 1.6331239353195369755967737041529b16

基本上与您获得的相同。 使用的 pi / 2 的二进制近似值略小于 pi / 2 的数学(“无限精度”)值。 因此,您将获得非常大的正切值而不是无穷大。 计算出的 tan()适用于实际输入!

出于完全相同的原因,例如,

>>> math.sin(math.pi)
1.2246467991473532e-16

不返回0。近似值math.pi略小于pi,并且显示的结果是正确的,在那个条件下。

其它查看math.pi的方法

有几种方法可以看到使用的精确近似值:

>>> import math
>>> math.pi.as_integer_ratio()
(884279719003555, 281474976710656)

math.pi 的值完全等于该比率的数学(“无限精度”)值。

或者是以十六进制表示的精确浮点数:

>>> math.pi.hex()
'0x1.921fb54442d18p+1'

或者用几乎所有人都能理解的方式来说:

>>> import decimal
>>> decimal.Decimal(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875')

虽然可能不是显而易见的,但是每个有限的二进制浮点数都可以精确地表示为有限的十进制浮点数(反之则不成立; 例如,十进制数0.1不能精确地表示为有限的二进制浮点数),Decimal(some_float)构造函数会生成精确等价物。

这里是pi的真实值,后面跟着math.pi的精确十进制值,并且第三行上的插入符号指向它们首次不同的数字:

true    3.14159265358979323846264338327950288419716939937510...
math.pi 3.141592653589793115997963468544185161590576171875
                         ^

math.pi现在在几乎所有的计算机上都相同,因为几乎所有的计算机都使用相同的二进制浮点数格式(IEEE 754双精度)。您可以使用上述任何一种方法来确认您的计算机上是否如此,或者如果您的计算机是例外情况,则可以找到正在使用的精确近似值。


1
@Tim Peters - 这非常清晰。为了完整起见,我猜测这个 np.pi 的表示是最接近系统 epsilon 的有理表示? - Aguy
3
假设np.pi与Python的math.pi具有相同的值(我没有检查,但您可以检查;-)),那么它是该平台本地C double浮点格式中可表示的最接近数学π的值。这意味着几乎所有现在的计算机都使用IEEE 754双精度浮点数,因此其最接近的二进制浮点数具有53位(尾数)精度。因此,有理数集被限制为形式为+/- I * 2 ** J的形式,其中整数I为0或2 ** 52 <= I <2 ** 53,整数J的范围足够广泛,可以覆盖所有接近pi的此类有理数。 - Tim Peters
2
这就是为什么我会非常喜欢如果“二进制”三角函数更普遍地被实现。既然 π 无法表示为有理数,那么一组作用于从 0 到 1 的角度的函数会非常方便。 - pipe
他们导入了 np.pi,而不是 math.pi - EKons
2
@Έρικ Κωνσταντόπουλος math.pinp.piscipy.pi都相同;它们只是为了方便命名而重复。https://dev59.com/f2cs5IYBdhLWcg3wtmED - Tim Peters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接