如何避免 math.sin(math.pi*2*VERY LARGE NUMBER) 的误差范围比 math.sin(math.pi*2) 大得多?
How to avoid math.sin(math.pi*2*VERY LARGE NUMBER) having a much larger error margin than math.sin(math.pi*2)?
我在其他问题中读到,例如 sin(2π) 由于浮点表示不为零,但非常接近。这个非常小的错误在我的代码中不是问题,因为我可以将 5 位小数四舍五入。
但是当2π乘以一个非常大的数时,误差就被放大了很多。答案应该是零(或接近),但远非如此。
我的想法是不是做错了什么?如果不是,如何避免 π 的浮点数误差范围得到 "magnified" 作为周期数 (2*PI*X) → ∞ ?
请注意,最后 3 个结果都是相同的。谁能解释为什么即使 5) 恰好 PI/2 大于 4)?即使正弦曲线有很大的偏移,PI/2 的增加仍然会产生不同的数字,对吗?
校验小数SIN(2*PI)
print math.sin(math.pi*2)
RESULT = -2.44929359829e-16 AS EXPECTED → 这个误差范围对我来说是可以的
在上面的代码中添加PI/2:SIN(2*PI + PI/2)
print math.sin((math.pi*2)+(math.pi/2))
结果:1.0 符合预期
正在检查非常大的数字 SIN(2*PI*VERY LARGE NUMBER)(仍期望接近于零)
print math.sin(math.pi*2*(415926535897932384626433832795028841971693993751))
结果:-0.759488037749 与预期不符 --> 这个误差范围不适合我的目的
在上面的代码中添加 PI/2:SIN(2*PI*VERY LARGE NUMBER + PI/2)(预计接近 1)
print math.sin((math.pi*2*(415926535897932384626433832795028841971693993751))+(math.pi/2))
如上所述,但我添加了 PI/2 - 期望得到 1.0 作为结果
结果:-0.759488037749 与预期不同 - 为什么我添加 PI/2 时结果与上面相同(应该在正弦曲线上走四分之一周期)
将随机数 (8) 添加到非常大的数中,既不期望 1 也不期望 0
print math.sin(math.pi*2*(415926535897932384626433832795028841971693993759))
如上,但我添加了 8 - 希望既不会得到 0 也不会得到 1
结果:-0.759488037749 与预期不同 - 为什么我添加 8
时结果与上面相同
使用的算法是近似值,值(例如 pi)也是近似值。所以 $\pi\cdot {SomeLargeNumber}$ 将 有一个较大的错误(因为 $\pi$ 的值是近似值)。 (硬件?)使用的函数将减少参数,可能使用稍微不同的 $\pi$ 值。
请注意,浮点运算 不 满足实数运算的公理。
这根本不适用于双精度变量。
math.pi
的值只对小数点后16位左右(二进制53位)是正确的,所以当你用它乘以像415926535897932384626433832795028841971693993751(159位)这样的数字时,就不可能得到有意义的结果。
您需要改用任意精度的数学库。例如,尝试使用 mpmath
。告诉它你想要 1000 位的精度,然后再次尝试你的求和:
>>> import mpmath
>>> mpmath.mp.prec=1000
>>> print(mpmath.sin((mpmath.pi*2*(415926535897932384626433832795028841971693993751))+(mpmath.pi/2)))
1.0
How to avoid math.sin(math.pi*2*VERY LARGE NUMBER)
having a much larger error margin than math.sin(math.pi*2)
?
你可以% 1
那个非常大的数字:
>>> math.sin(math.pi*2*(415926535897932384626433832795028841971693993751))
-0.8975818793257183
>>> math.sin(math.pi*2*(415926535897932384626433832795028841971693993751 % 1))
0.0
>>> math.sin((math.pi*2*(415926535897932384626433832795028841971693993751))+(math.pi/2))
-0.8975818793257183
>>> math.sin((math.pi*2*(415926535897932384626433832795028841971693993751 % 1))+(math.pi/2))
1.0
我在其他问题中读到,例如 sin(2π) 由于浮点表示不为零,但非常接近。这个非常小的错误在我的代码中不是问题,因为我可以将 5 位小数四舍五入。
但是当2π乘以一个非常大的数时,误差就被放大了很多。答案应该是零(或接近),但远非如此。
我的想法是不是做错了什么?如果不是,如何避免 π 的浮点数误差范围得到 "magnified" 作为周期数 (2*PI*X) → ∞ ?
请注意,最后 3 个结果都是相同的。谁能解释为什么即使 5) 恰好 PI/2 大于 4)?即使正弦曲线有很大的偏移,PI/2 的增加仍然会产生不同的数字,对吗?
校验小数SIN(2*PI)
print math.sin(math.pi*2)
RESULT = -2.44929359829e-16 AS EXPECTED → 这个误差范围对我来说是可以的
在上面的代码中添加PI/2:SIN(2*PI + PI/2)
print math.sin((math.pi*2)+(math.pi/2))
结果:1.0 符合预期
正在检查非常大的数字 SIN(2*PI*VERY LARGE NUMBER)(仍期望接近于零)
print math.sin(math.pi*2*(415926535897932384626433832795028841971693993751))
结果:-0.759488037749 与预期不符 --> 这个误差范围不适合我的目的
在上面的代码中添加 PI/2:SIN(2*PI*VERY LARGE NUMBER + PI/2)(预计接近 1)
print math.sin((math.pi*2*(415926535897932384626433832795028841971693993751))+(math.pi/2))
如上所述,但我添加了 PI/2 - 期望得到 1.0 作为结果
结果:-0.759488037749 与预期不同 - 为什么我添加 PI/2 时结果与上面相同(应该在正弦曲线上走四分之一周期)将随机数 (8) 添加到非常大的数中,既不期望 1 也不期望 0
print math.sin(math.pi*2*(415926535897932384626433832795028841971693993759))
如上,但我添加了 8 - 希望既不会得到 0 也不会得到 1
结果:-0.759488037749 与预期不同 - 为什么我添加 8 时结果与上面相同
使用的算法是近似值,值(例如 pi)也是近似值。所以 $\pi\cdot {SomeLargeNumber}$ 将 有一个较大的错误(因为 $\pi$ 的值是近似值)。 (硬件?)使用的函数将减少参数,可能使用稍微不同的 $\pi$ 值。
请注意,浮点运算 不 满足实数运算的公理。
这根本不适用于双精度变量。
math.pi
的值只对小数点后16位左右(二进制53位)是正确的,所以当你用它乘以像415926535897932384626433832795028841971693993751(159位)这样的数字时,就不可能得到有意义的结果。
您需要改用任意精度的数学库。例如,尝试使用 mpmath
。告诉它你想要 1000 位的精度,然后再次尝试你的求和:
>>> import mpmath
>>> mpmath.mp.prec=1000
>>> print(mpmath.sin((mpmath.pi*2*(415926535897932384626433832795028841971693993751))+(mpmath.pi/2)))
1.0
How to avoid
math.sin(math.pi*2*VERY LARGE NUMBER)
having a much larger error margin thanmath.sin(math.pi*2)
?
你可以% 1
那个非常大的数字:
>>> math.sin(math.pi*2*(415926535897932384626433832795028841971693993751))
-0.8975818793257183
>>> math.sin(math.pi*2*(415926535897932384626433832795028841971693993751 % 1))
0.0
>>> math.sin((math.pi*2*(415926535897932384626433832795028841971693993751))+(math.pi/2))
-0.8975818793257183
>>> math.sin((math.pi*2*(415926535897932384626433832795028841971693993751 % 1))+(math.pi/2))
1.0