稍微转向浮点 (im) 精度,第 1 部分
-
08-06-2019 - |
题
大多数数学家都同意:
eπi + 1 = 0
然而,大多数浮点实现不同意。我们能如何很好地解决这一争端?
我很想了解不同的语言和实现,以及使结果尽可能接近于零的各种方法。有创意!
解决方案
这并不是说大多数浮点实现不同意,而是它们无法获得获得 100% 答案所需的准确性。正确的答案是他们不能。
PI 是一个无限的数字序列,除了符号表示之外,没有人能够用任何东西来表示,e^X 也是如此,因此达到 100% 准确度的唯一方法就是使用符号。
其他提示
这是我尝试过的实现和语言的简短列表。它按接近零的程度排序:
- 方案:
(+ 1 (make-polar 1 (atan 0 -1)))
- ⇒
0.0+1.2246063538223773e-16i
(Chez 计划、麻省理工学院计划) - ⇒
0.0+1.22460635382238e-16i
(诡计) - ⇒
0.0+1.22464679914735e-16i
(鸡肉与numbers
蛋) - ⇒
0.0+1.2246467991473532e-16i
(MzScheme、SISC、Gauche、Gambit) - ⇒
0.0+1.2246467991473533e-16i
(单片机)
- ⇒
- 通用 Lisp:
(1+ (exp (complex 0 pi)))
- ⇒
#C(0.0L0 -5.0165576136843360246L-20)
(CLISP) - ⇒
#C(0.0d0 1.2246063538223773d-16)
(中科大) - ⇒
#C(0.0d0 1.2246467991473532d-16)
(SBCL)
- ⇒
- 珀尔:
use Math::Complex; Math::Complex->emake(1, pi) + 1
- ⇒
1.22464679914735e-16i
- ⇒
- Python:
from cmath import exp, pi; exp(complex(0, pi)) + 1
- ⇒
1.2246467991473532e-16j
(CPython)
- ⇒
- 红宝石:
require 'complex'; Complex::polar(1, Math::PI) + 1
- ⇒
Complex(0.0, 1.22464679914735e-16)
(核磁共振成像) - ⇒
Complex(0.0, 1.2246467991473532e-16)
(JRuby)
- ⇒
- 回复:
complex(argument = pi) + 1
- ⇒
0+1.224606353822377e-16i
- ⇒
这场纠纷有可能得到解决吗?
我的第一个想法是寻找一种符号语言,比如 枫. 。但我认为这不算浮点数。
事实上,如何表示 我 (或者 j 对于工程师来说)用传统的编程语言?
也许更好的例子是 sin(π) = 0?(或者我又错过重点了?)
我同意瑞安的观点,你需要转向另一个数字表示系统。该解决方案超出了浮点数学的范围,因为您需要将 pi 表示为无限长的小数,因此任何有限精度的方案都行不通(至少在不使用某种捏造因子来弥补丢失的情况下是行不通的)精确)。
你的问题对我来说似乎有点奇怪,因为你似乎暗示浮点数学是由语言实现的。这通常是不正确的,因为 FP 数学是使用硬件中的浮点处理器完成的。但无论是软件还是硬件,浮点总是会不准确。这就是浮动的工作原理。
如果您需要更高的精度,则需要使用不同的数字表示形式。就像您对不适合 int 或 long 的数字进行整数数学一样。有些语言有内置的库(我知道 java 有 BigInteger 和 BigDecimal),但是您必须显式使用这些库而不是本机类型,并且性能会(有时明显)比使用浮点数差。
@瑞恩·福克斯
事实上,如何用传统的编程语言表示 i(或工程师的 j)?
原生复杂数据类型远非未知。Fortran 在 60 年代中期就出现了,并且 OP 展示了在其后续版本中支持它们的各种其他语言。
复数可以作为库添加到其他语言中(通过运算符重载,它们甚至看起来就像代码中的本机类型)。
但除非你为这个问题提供一个特殊情况,否则“不一致”只是机器算术不精确的一种表达,不是吗?就像抱怨一样
float r = 2/3;
float s = 3*r;
float t = s - 2;
以 (t != 0) 结尾(至少如果您使用足够愚蠢的编译器)...
我和我最好的朋友喝了很长时间的咖啡聊天,谈论无理数和其他数字之间的差异。好吧,我们都同意这个不同的观点:
无理数在某种程度上是关系,就像函数一样,以什么方式?好吧,想想“如果你想要一个完美的圆,给我一个完美的圆周率”,但圆与其他数字不同(4条边、5、6......100, 200) 但是...你还有多少条边,看起来更像一个圆。如果您到目前为止都跟着我,那么这里连接所有这些想法的是 pi 公式:
所以,pi 是一个函数,但是一个永无止境的函数!因为 Infinity 参数,但我喜欢认为你可以拥有 pi 的“实例”,如果你将 Infinity 参数更改为一个非常大的 Int,你将拥有一个非常大的 pi 实例。
和e一样,给我一个巨大的参数,我会给你一个巨大的e。
将所有想法放在一起:
由于我们有内存限制,语言和库为我们提供了巨大的无理数实例,在本例中为 pi 和 e,作为最终结果,您将需要很长的时间才能得到 0,就像@Chris Jester-Young 提供的示例一样
数值分析告诉我们,不能依赖大数之间微小差异的精确值。
这不仅会影响这里讨论的方程,还会给一切带来不稳定,从求解一组近奇异的联立方程,到找到多项式的零点,再到评估 log(~1) 或 exp(~0) (我什至看到了用于评估 log(x+1) 和 (exp(x)-1) 的特殊函数来解决这个问题)。
我鼓励您不要考虑将差异归零(您不能),而是以确保最小误差的方式进行相关计算。
抱歉,自从我在大学时被灌输这一点以来,已经有 43 年了,即使我还记得这些参考资料,我确信现在有更好的东西。我建议 这 作为起点。
如果这听起来有点居高临下,我深表歉意。我的“数值分析101”是化学课程的一部分,因为当时没有太多计算机科学。我对数值分析在现代计算机科学课程中的地位/重要性并没有真正的感觉。
这是我们当前浮点计算架构的限制。浮点运算只是像 e 或 pi 这样的数字极点的近似值(或超出位允许的精度的任何值)。我真的很喜欢这些数字,因为它们无法分类,而且似乎比素数(一个规范级数)具有更大的熵(?)。比率违背了数字表示,有时这样简单的事情可能会让人大吃一惊(我喜欢它)。
幸运的是,整个语言和库都可以通过使用符号概念(类似于 拉塞 V.卡尔森 ).
考虑一种以机器可以理解的形式描述 e 和 pi 等概念的库/语言。机器知道什么是完美的圆吗?也许不是,但我们可以创建一个对象 - 圆,它满足我们赋予它的所有已知特征(恒定半径,半径与周长的关系为 2*pi*r = C)。像 pi 这样的对象只能通过上述比率来描述。r & C 可以是数字对象,可以用您想要赋予它们的任何精度来描述。e 可以定义为“因为 e 是唯一的实数,使得函数 f(x) = ex 在点 x = 0 处的导数(切线斜率)的值恰好为 1” 维基百科.
有趣的问题。