- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
在某些应用中,需要多个角度的正弦和余弦,其中角度是通过将相等大小的增量 incr 重复添加到起始值 base 得出的。出于性能原因,而不是调用 sin()
,cos()
标准数学库函数(或者可能是非标准的 sincos()
函数)对于每个生成的角度,只计算一次 sin(base) 和 cos(base),然后通过应用导出所有其他正弦和余弦是非常有利的angle-sum formulas :
sin(base+incr) = cos(incr) · sin(base) + sin(incr) · cos(base)
cos(base+incr) = cos(incr) · cos(base) - sin(incr) · sin(base)
这只需要对比例因子 sin(incr) 和 cos(incr) 进行一次性预计算,而不管执行了多少次迭代。
这种方法有几个问题。如果增量很小,cos(incr) 将是一个接近于 1 的数字,当以有限精度浮点格式计算时,通过隐式减法抵消导致精度损失。此外,由于计算未以有利的数值形式 sin(base+incr) = sin(base) + adjust 进行计算,因此会产生比必要更多的舍入误差,其中计算量 adjust 的量级明显小于 sin(base)(类似于余弦)。
由于一个人通常应用数十到数百次迭代步骤,因此这些错误会累积。如何以最有利于保持高精度的方式构建迭代计算?如果 fused multiply-add 应该对算法进行哪些更改操作 (FMA) 可用,它通过标准数学函数 fma()
和 fmaf()
?
最佳答案
正弦的 half-angle formula 应用允许解决问题中提到的两个影响准确性的问题:
sin(incr/2) = √((1-cos(incr))/2) ⇒
sin²(incr/2) = (1-cos(incr))/2 ⇔
2·sin²(incr/2) = 1-cos(incr) ⇔
1-2·sin²(incr/2) = cos(incr)
将其代入原始公式会得到此中间表示:
sin(base+incr) = (1 - 2·sin²(incr/2)) · sin(base) + sin(incr) · cos(base)
cos(base+incr) = (1 - 2·sin²(incr/2)) · cos(base) - sin(incr) · sin(base)
通过对项进行简单的重新排序,可以得到所需的公式形式:
sin(base+incr) = sin(base) + (sin(incr) · cos(base) - 2·sin²(incr/2) · sin(base))
cos(base+incr) = cos(base) - (2·sin²(incr/2) · cos(base) + sin(incr) · sin(base))
和原来的公式一样,这只需要一次性预计算两个比例因子,即2·sin²(incr/2)和sin(incr) .对于小增量,两者都很小:保留完整的精度。
关于如何将 FMA 应用于此计算,有两种选择。可以通过废除使用一次调整的方法来最小化操作次数,而是使用两次,希望 FMA 操作的减少舍入误差(一次舍入用于两次操作)将补偿精度损失:
sin(base+incr) = fma (-2·sin²(incr/2), sin(base), fma ( sin(incr), cos(base), sin(base)))
cos(base+incr) = fma (-2·sin²(incr/2), cos(base), fma (-sin(incr), sin(base), cos(base)))
另一种选择是将单个 FMA 应用于改进后的公式,尽管尚不清楚应将两个乘法中的哪一个映射到 FMA 内的未舍入乘法:
sin(base+incr) = sin(base) + fma (sin(incr), cos(base), -2·sin²(incr/2) · sin(base))
cos(base+incr) = cos(base) - fma (sin(incr), sin(base), 2·sin²(incr/2) · cos(base))
下面的脚手架通过生成许多 (base, incr) 对来评估上面讨论的每个计算备选方案,然后对它们中的每一个迭代一定数量的步骤同时收集生成的所有正弦和余弦值的误差。由此它为每个测试用例计算一个 root-mean square error,分别为正弦、余弦。最后报告在所有生成的测试用例中观察到的最大 RMS 误差。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define NAIVE (1)
#define ROBUST (2)
#define FAST (3)
#define ACCURATE (4)
#define MODE (ACCURATE)
// Fixes via: Greg Rose, KISS: A Bit Too Simple. http://eprint.iacr.org/2011/007
static unsigned int z=362436069,w=521288629,jsr=362436069,jcong=123456789;
#define znew (z=36969*(z&0xffff)+(z>>16))
#define wnew (w=18000*(w&0xffff)+(w>>16))
#define MWC ((znew<<16)+wnew)
#define SHR3 (jsr^=(jsr<<13),jsr^=(jsr>>17),jsr^=(jsr<<5)) /* 2^32-1 */
#define CONG (jcong=69069*jcong+13579) /* 2^32 */
#define KISS ((MWC^CONG)+SHR3)
int main (void)
{
double sumerrsqS, sumerrsqC, rmsS, rmsC, maxrmsS = 0, maxrmsC = 0;
double refS, refC, errS, errC;
float base, incr, s0, c0, s1, c1, tt;
int count, i;
const int N = 100; // # rotation steps per test case
count = 2000000; // # test cases (a pair of base and increment values)
#if MODE == NAIVE
printf ("testing: NAIVE (without FMA)\n");
#elif MODE == FAST
printf ("testing: FAST (without FMA)\n");
#elif MODE == ACCURATE
printf ("testing: ACCURATE (with FMA)\n");
#elif MODE == ROBUST
printf ("testing: ROBUST (with FMA)\n");
#else
#error unsupported MODE
#endif // MODE
do {
/* generate test case */
base = (float)(KISS * 1.21e-10); // starting angle, < 30 degrees
incr = (float)(KISS * 2.43e-10 / N); // increment, < 60/n degrees
/* set up rotation parameters */
s1 = sinf (incr);
#if MODE == NAIVE
c1 = cosf (incr);
#else
tt = sinf (incr * 0.5f);
c1 = 2.0f * tt * tt;
#endif // MODE
sumerrsqS = 0;
sumerrsqC = 0;
s0 = sinf (base); // initial sine
c0 = cosf (base); // initial cosine
/* run test case through N rotation steps */
i = 0;
do {
tt = s0; // old sine
#if MODE == NAIVE
/* least accurate, 6 FP ops */
s0 = c1 * tt + s1 * c0; // new sine
c0 = c1 * c0 - s1 * tt; // new cosine
#elif MODE == ROBUST
/* very accurate, 8 FP ops */
s0 = ( s1 * c0 - c1 * tt) + tt; // new sine
c0 = (-s1 * tt - c1 * c0) + c0; // new cosine
#elif MODE == FAST
/* accurate and fast, 4 FP ops */
s0 = fmaf (-c1, tt, fmaf ( s1, c0, tt)); // new sine
c0 = fmaf (-c1, c0, fmaf (-s1, tt, c0)); // new cosine
#elif MODE == ACCURATE
/* most accurate, 6 FP ops */
s0 = tt + fmaf (s1, c0, -c1 * tt); // new sine
c0 = c0 - fmaf (s1, tt, c1 * c0); // new cosine
#endif // MODE
i++;
refS = sin (fma ((double)i, (double)incr, (double)base));
refC = cos (fma ((double)i, (double)incr, (double)base));
errS = ((double)s0 - refS) / refS;
errC = ((double)c0 - refC) / refC;
sumerrsqS = fma (errS, errS, sumerrsqS);
sumerrsqC = fma (errC, errC, sumerrsqC);
} while (i < N);
rmsS = sqrt (sumerrsqS / N);
rmsC = sqrt (sumerrsqC / N);
if (rmsS > maxrmsS) maxrmsS = rmsS;
if (rmsC > maxrmsC) maxrmsC = rmsC;
} while (--count);
printf ("max rms error sin = % 16.9e\n", maxrmsS);
printf ("max rms error cos = % 16.9e\n", maxrmsC);
return EXIT_SUCCESS;
}
测试支架的输出表明,最快的基于 FMA 的替代方案优于问题中的朴素方法,而更准确的基于 FMA 的替代方案是所考虑替代方案中最准确的:
testing: NAIVE (without FMA)
max rms error sin = 4.837386842e-006
max rms error cos = 6.884047862e-006
testing: ROBUST (without FMA)
max rms error sin = 3.330292645e-006
max rms error cos = 4.297631502e-006
testing: FAST (with FMA)
max rms error sin = 3.532624939e-006
max rms error cos = 4.763623188e-006
testing: ACCURATE (with FMA)
max rms error sin = 3.330292645e-006
max rms error cos = 4.104813533e-006
关于c - 为等间距角度快速准确地迭代生成正弦和余弦,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51735576/
这个问题在这里已经有了答案: Why should there be spaces around '[' and ']' in Bash? (4 个回答) 3年前关闭。 作为初学者,我没有在任何地方找
我有一个程序,我在其中输入 Java 程序来检查输入的字符串是否为回文。我有 2 个问题正在发生,我似乎一辈子都无法解决。 我已经输入了代码,这样它会告诉我它是否是一个回文,当所有小写字母不涉及空格时
table { border: 0; padding: 0; border-collapse: collapse;
我有 10 个单元格,其中第 6 个单元格的宽度必须与其他单元格不同。我试图在流委托(delegate)方法中更改它。但是从第 7 个单元格到第 10 个单元格的间距出了点问题。 func coll
我只是希望将这些新闻发布很好地隔开,以便在每次发布之间留出空隙。我在下面附上了一张图片来解释。我试图增加下面的填充,但这没有用。感谢您的帮助 .headline { position: absolut
如何使用 css 删除表格结构中烦人的单元格间距和/或填充?如果解决方案在 IE7-9、Firefox 和 Chrome 中有效,请加倍支持! 为什么CSS这么难!真让人抓狂! 最佳答案 通常,在该表
我在我正在使用的网站上设置了按钮。我想在按钮外创建一个 2px 的边框,有一点间距。请参见设计图像。 我可以创建边框,但不能创建边框之外的间距。这是当前的开发站点。按钮是第一个图形。 到目前为止我已经
我正在网站上生成元素符号列表(通过使用 jquery 自动完成功能)和我在网站中使用响应式网页设计。 我想在每个列表项后留一个空格。为此,我添加了以下 CSS: li { margin-b
我在格式化我的 HTML 页面时遇到困难。 正如您从源代码中看到的那样,它是一个表格,其中每一行都包含由我的网络应用程序动态填充的格式化记录列表。如果其中一列有空值,我想保留行的格式,所以我基本上应该
我一直致力于设计一个具有三个链接的跨移动设备宽度的设计。我不明白为什么我不能得到正确的间距。什么看起来不对劲? 设计如下: 下面是编码版本的样子: 这是我的 CSS: .b-nav-Wrapper {
我需要在 matplotlib 中生成一大堆垂直堆叠的图。结果将使用 savefig 保存并在网页上查看,所以我不在乎最终图像有多高,只要子图间隔开,这样它们就不会重叠。 无论我允许这个数字有多大,子
我需要在 matplotlib 中生成一大堆垂直堆叠的图。结果将使用 savefig 保存并在网页上查看,所以我不在乎最终图像有多高,只要子图之间有间距,不重叠即可。 无论我允许图有多大,子图似乎总是
是否可以在 BorderPane 上设置节点之间的间距? ? Swing 等效项将是 BorderLayout 上的 hgap 和 vgap . 我在文档中没有找到任何内容,我能想到的唯一可行的解
我有一个基于日历的应用 我希望用户能够通过捏合来放大和缩小日历。这是我的代码: let p = UIPinchGestureRecognizer(target: self, action: #sele
我在为 Android 编写一段代码时遇到问题。我使用的是eclipse开发环境。我想要完成的是将一周中的日子均匀地分布在表格的第一行(有六行)。我不知道如何才能使这些单词真正散开,而不是仅仅粘在一起
我有一个基于日历的应用 我希望用户能够通过捏合来放大和缩小日历。这是我的代码: let p = UIPinchGestureRecognizer(target: self, action: #sele
我该怎么做才能对齐此代码中的所有列?这是正确的还是......? import urllib.request from re import findall def determinarLlegadas
当使用垂直对齐的 BoxLayout 时,如何阻止组件随着包含的 JFrame 的增长而扩展,从而在底部留下额外的空间?我尝试了不同的布局,但很快就变得一团糟。我还尝试在面板底部添加胶水,但布局管理器
我正在尝试制作 cout #include int main() { std::cout << setw(4) << 1 << setw(4) << 2 << std::endl; } 输出
使用示例 http://developer.android.com/guide/tutorials/views/hello-tabwidget.html通过向布局添加 HorizontalScro
我是一名优秀的程序员,十分优秀!