当前位置: 首页 > 知识库问答 >
问题:

我应该对循环浮点使用乘法还是除法?

范瀚昂
2023-03-14

众所周知,除法比乘法需要更多的时钟周期来计算。(请参阅此处的讨论:浮点除法与浮点乘法。)

我已经在我的C代码中使用了< code>x * 0.5而不是< code>x / 2和< code>x * 0.125而不是< code>x / 8,但是我想知道我应该这样做到什么程度。

对于倒置时重复出现的小数(即1/num是重复出现的十进制),我使用除法而不是乘法(例如x/2.2而不是x*0.45454545454)。

我的问题是:在迭代次数相当大的循环中,我应该用循环的乘法替换除数吗(即x*0.45454545454而不是x/2.2),还是这会带来更大的精度损失?

编辑:我做了一些分析,我在Visual Studio中打开了完整的优化,使用Windows QueryPerformceCounter()函数来获取分析结果。

int main() {
    init();
    int x;
    float value = 100002030.0;
    start();
    for (x = 0; x < 100000000; x++)
        value /= 2.2;
    printf("Div: %fms, value: %f", getElapsedMilliseconds(), value);
    value = 100002030.0;
    restart();
    for (x = 0; x < 100000000; x++)
        value *= 0.45454545454;
    printf("\nMult: %fms, value: %f", getElapsedMilliseconds(), value);
    scanf_s("");
}

结果为:Div:426.907185ms,value:0.000000 Mult:289.616415ms,value:0.000000

除法花费的时间几乎是乘法的两倍,即使有优化。性能优势是有保证的,但它们会降低精度吗?


共有2个答案

赵英范
2023-03-14

当乘以一个倒数与除以时,您会得到不同的答案,但在实践中,这通常并不重要,性能提升是值得的。相对于除法的ULP,倒数乘法的误差最多为1 ULP。但是一定要

a = b * (1.f / 7.f);

而不是

a = b * 0.142857f;

因为前者将为1/7生成最准确的(½ULP)表示。

锺离卓
2023-03-14

对于反转时循环出现的小数(即1 / num是循环小数),我用除法代替乘法(例x / 2.2代替x * 0.45454545454)。

众所周知,22/10不能用二进制浮点数精确表示,因此您所实现的不是乘以稍微不准确的值,而是除以稍微不准确的值。

事实上,如果目的是除以22/10或其他一些不一定能在二进制浮点数中精确表示的实值,那么乘法比除法精确一半,因为碰巧1/X的相对误差小于X的相对误差。

另一个注意事项是,您的微基准遇到了次正规数,其中计时不能代表对正常浮点数的常规操作的计时,过了一会儿,value为零,这再次意味着计时不能代表正常数的乘除。正如Mark Ransom所说,您至少应该使两个测量的操作数相同:如当前所写,所有乘法都取零操作数,结果为零。此外,由于2.20.454545454double都有类型,您的基准是测量双精度乘法和除法,如果您愿意通过双精度乘法器实现单精度除法,这不需要任何精度损失(但您必须为 提供更多数字)。

但是不要让自己被愚弄去试图修复微观基准。你不需要它,因为当X不能比1/X更精确地表示时,就没有权衡了。没有理由不使用乘法。

注意:您应该显式乘以1/X,因为由于/X*(1/X)这两个操作略有不同,编译器本身无法进行替换。另一方面,您不需要将/2替换为*0.5,因为任何称职的编译器都应该为您执行此操作。

 类似资料:
  • 我知道浮点数和双倍点数的精度问题,这就是为什么我要问这个问题: 如果我有一个公式,例如:

  • 我正在写一个算法,舍入一个浮点数。输入将是64位IEEE754双类型数,非常接近X.5,其中X是小于32的整数。我想到的第一个解决方案是使用位掩码,掩码掉那些最低有效位,因为它们代表2^-n的非常小的分数。(给定指数不大)。 但是问题是我应该这样做吗?有没有其他方法来完成同样的事情?我觉得在浮点上使用比特操作非常有争议。谢谢! 顺便说一下,我用的语言是C。 编辑:谢谢你们的评论。我很感激!假设我有

  • 问题内容: 我正在使用c / c 为osx和linux开发命令行界面可执行文件。该项目将链接到opencv。我应该使用libc 还是libstdc ++? 问题答案: 我会为每个操作系统使用本机库,即GNU / Linux上的libstdc 和Mac OS X上的libc 。 libc 在GNU / Linux上不是100%完整的,而libstdc 更完整时使用libc并没有真正的优势。另外,如果

  • 问题内容: 和CSS 和有什么不一样?我应该使用哪一个?为什么? 问题答案: 所有这些答案似乎都是不正确的。与直觉相反,在CSS 中不是pixel 。至少不是在简单的物理意义上。 从W3C,EM,PX,PT,CM,IN…阅读本文,了解如何为CSS发明一个“神奇的”单元。的含义因硬件和分辨率而异。(该文章是最新的,最新更新为2014-10。) 我自己的思考方式: px单位是CSS的魔术单位。它与当前

  • 问题内容: 我正在一个将Angular和Underscore都作为依赖项的项目。 当我需要创建对象的副本时,根据当时的心情,我可以使用或 在我看来,这些方法中的一种可能比另一种更快速/可靠/健壮。 假设已经包含两个库,那么这两个函数中的任何一个是否存在使另一个函数更好或更坏使用的已知问题? 问题答案: 关于您的问题: angular.copy和_.clone是不同的。这不是哪个更好的问题,而是关于

  • 问题内容: 我想从文本文件中读取每一行并将它们存储在ArrayList中(每一行是ArrayList中的一项)。 到目前为止,我知道BufferedInputStream写入缓冲区,并且仅在缓冲区为空时才进行另一次读取,这可以最大程度地减少或至少减少操作系统的操作量。 我正确吗-我说得通吗? 如果以上情况是在任何情况下,任何人都想使用DataInputStream。最后,我应该使用这两个中的哪一个