SLATEC 例程以意想不到的方式计算 Givens 旋转

计算科学 浮点 数字
2021-12-17 11:48:41

一些背景

我正在研究 SLATEC 例程的 C++ 翻译R1UPDT,它执行 Givens 旋转:

r=1.0a2+b2

通常,这个方程的形式略有不同,具体取决于是否|a|<|b|. 一个临时变量,c, 用于使得c小于1.

|a|<|b|c=ab方程写成r=bc2+1.

|a|>|b|c=ba方程写成r=a1+c2.

无论哪种方式,都可以避免潜在的溢出风险,因为平方项小于 1。

到现在为止还挺好。

关于问题

但是,Fortran 代码R1UPDT是这样编写的r=0.50.25+0.25c2

IE,

r = 0.5 / SQRT(0.25 + 0.25 * C**2)

我不得不问:为什么计算是这样编码的?方程的 RHS 可以简单地手动分解并编码。

IE,

r = 1.0 / SQRT(1.0 + C**2)

我的第一个想法是可以消除一次乘法并加快程序执行速度。然而,也许这是另一种避免溢出的技术。或者也许确保radicand在范围内[0.250.5]可以更快地计算或产生更准确的结果。我只是推测;也许这里有人可以澄清一下。

这里的任何人都知道为什么没有从这段代码中取出公因数吗?

2个回答

平方根是一个相对困难的数学运算。因此,可以合理地假设在IEEE-754 之前的主导世界中,参数范围可能会显着影响SQRT. 特别是,正如@njuffa 在评论中提到的那样

... IBM System/360 十六进制浮点格式的摆动精度

但是,在这种相对良性的重新缩放的情况下,我找不到对此的确认。

已经对精确、快速和高效的平方根算法进行了大量研究

在过去:

甚至在不久的将来,

但是,我不明白为什么范围[0.25,0.5]会比[1,2]. 特别是从使用指南SQRT的角度来看,即使是在 IEEE-754 之前的时代。

例如,参见手册IBM System/360 FORTRAN IV Library Subprograms, 1966在那里,第 39 页的表 12“性能统计”给出了不同 IBM System/360 模型中各种数学函数的准确度/速度性能。

虽然(在此表中)某些数学函数具有不同的精度/速度性能,但DSQRT被列为整个参数值范围的单个条目。最后,可能没有建议限制SQRTIBM System/360 的范围(顺便说一句,即使是 complex CSQRT)。

在此处输入图像描述

虽然有无数其他平台,但我认为没有太多需要阅读 SLATEC 代码的特殊细节。

出于您的目的:

以这种方式安排计算的动机几乎可以肯定是在使用 IBM System/360 的十六进制浮点格式进行计算时精度不稳定的问题。在那里,尾数被归一化,使得num=±16ef, 和116f<1. 这意味着尾数的最多三个前导位可以为零。

R1UPTD,c=max(|vn|,|vj|)/min(|vn|,|vj|)1, 意思就是11+c22,因此11+c22<2. 因此1+c2=161f, 在哪里116f<18. 这意味着平方根结果的前三位将为零,从而导致计算精度降低。

缩放0.25平方根的结果减半,所以0.25+0.25c2=160f, 在哪里12f<1,这意味着尾数中没有前导零位,并且保留了完整的准确性。

参见:WJ Cody,“数值子程序库的构建”,SIAM 评论,卷。16.,第 1 期,1974 年 1 月,第 36-46 页。

在具有基于 IEEE-754 标准的二进制浮点算法的现代平台上,不需要这种缩放,并且大多数编程环境都包含一个标准函数hypot(x,y),用于计算x2+y2具有最佳精度并消除了中间计算中的溢出或下溢问题。一些环境还提供rhypot(x,y)计算功能1x2+y2并且完全符合吉文斯轮换的需要。