Floating point 精确龙格-库塔系数

Floating point 精确龙格-库塔系数,floating-point,precision,numerical-methods,floating-accuracy,Floating Point,Precision,Numerical Methods,Floating Accuracy,当使用数值方法(例如)时,计算机上浮子的有限精度可能会影响解(Brouwer定律) 在本文中,它建议作为一种补救措施,模拟精确的龙格-库塔系数,例如a=B+C,其中B是一个精确的机器编号,C是一些小的修正 有人能解释一下这在实践中是如何起作用的吗?例如,如果A=3/10,那么如何确定B和C 感谢您的帮助。在论文中,他们建议对分母为1024的a使用有理近似。 (这意味着A最多有10个有效非零位)。你有(3/10)*1024=307.2,所以B将是 B=307/1024=0.2998046875和C

当使用数值方法(例如)时,计算机上浮子的有限精度可能会影响解(Brouwer定律)

在本文中,它建议作为一种补救措施,模拟精确的龙格-库塔系数,例如a=B+C,其中B是一个精确的机器编号,C是一些小的修正

有人能解释一下这在实践中是如何起作用的吗?例如,如果A=3/10,那么如何确定B和C


感谢您的帮助。

在论文中,他们建议对分母为1024的a使用有理近似。 (这意味着A最多有10个有效非零位)。你有(3/10)*1024=307.2,所以B将是

B=307/1024=0.2998046875和C=A-B=0.0001953125

C不能精确表示为IEEE二进制64,最接近的浮点数为

C=1.9531249999998889776975374843…E-4


在公式(3.1f)中插入这些值。

这一技巧在2007年提交论文时可能有效,但我认为在现代平台上不太可能有效

在现代x86(32位和64位)处理器上,浮点计算有两个独立的指令集:

  • 旧的x87指令(可追溯到原始的8087协处理器),具有80位寄存器

  • 最新的SSE指令,使用与格式相同宽度的寄存器(32位表示
    浮点
    ,64位表示
    双精度

较新的SSE指令通常是现代编译器的首选指令,因为它们往往更快,因为它们可以完全流水线,并且支持SIMD操作等奇特的操作。然而在2007年,一些编译器默认情况下仍然只使用x87指令,因为二进制文件可以在较旧的机器上使用(在32位机器上尤其如此)

80位寄存器支持最多64位的有效位,比64位
双精度
的53位有效位多11位。其想法是,您可以潜在地减少中间舍入误差,在这种情况下,您可以利用这种误差

考虑他们问题的一个简单版本:计算

Y = A*X
按照他们的建议,将
A
拆分为
B+C
B
只有10个有效位。然后是手术

B*X
不会产生任何舍入错误,因为它最多有63个有效位。完整计算

Y = B*X + C*X
因此,将为您提供几乎全部64位精度的结果

如果没有扩展精度,
B*X
通常会产生大致相同大小的舍入误差,就像您刚刚直接计算
A*X
一样(除非
X
本身以降低精度存储)

这听起来很好:你可能想知道为什么SSE指令会去掉这个?不幸的是,这是不可预测的:在某些情况下,编译器会对其进行安排以使其工作,但在其他情况下,它需要将寄存器“溢出”到内存中,在这种情况下,您将失去这种额外的精度。这反过来会产生一些奇怪的结果,比如让诸如
x+y==x+y
之类的运算计算为false,这取决于对单个运算的计算时间

然而,一切都没有失去!如果您有一台相当新的机器,您可以利用操作来提高精度。在这种情况下,它看起来像

Y = fma(B,X,C*X)

也许我遗漏了一些东西,但我不明白问题中相关论文中的技术在哪里依赖于扩展精度硬件的存在?它使用(方程式3.1)分别使用系数的高阶和低阶部分进行单独累加,并在最后合并累加和。我同意FMA的存在现在提供了改进的补偿计算方法,比如这一种。我添加了一个章节:基本上你需要扩展精度(或者截断
X
的精度),以确保
B*X
可以无误计算。否则,您将产生与直接计算A*X时大致相同的大小错误。您完全正确:我们希望高阶乘积在添加到总和之前完全准确,这需要额外的位。不知道我怎么会忽略了。。。