乘以浮动并保持/获得双精度精度

时间:2016-09-11 13:02:44

标签: c++ casting floating-point precision

我有一个浮点函数,我用它们做一些计算,我想在返回的结果中尽可能保持准确性。我读到,当你乘以两个浮点数时,你的有效数字加倍。

因此,当两个浮点数相乘时,例如float e, f;而{I} double g = e * f,这些位何时被截断?

在我下面的示例函数中,我是否需要转换,如果是,在哪里?这是一个紧密的内循环,如果我在每个变量static_cast<double>(x)周围放置a b c d,我会减速5-10%。但是我怀疑我不需要分别投射每个变量,只在某些地方,如果有的话?或者在这里返回一个双倍并不会给我任何收益,我也可以返回一个浮点数?

double func(float a, float b, float c, float d) {
    return (a - b) * c + (a - c) * b;
}

2 个答案:

答案 0 :(得分:6)

当你在没有强制转换的情况下乘以两个浮点数时,结果将使用浮点精度计算(即截断),然后转换为double。

要以double计算结果,您需要将至少一个操作数强制转换为double。然后整个计算将以double结束(并且所有浮点值都将被转换)。但是,这将创造同样的减速。减速很可能是因为将一个数字从float转换为double并不是完全无关紧要的(不同的位大小以及指数和mantisa的范围)。

如果我这样做并且控制了函数定义,我将所有参数都传递为double(我通常在任何地方使用double,在现代计算机上计算float与double之间的速度差异可以忽略不计,只有问题可能是在大型值数组上运行时的内存吞吐量和缓存性能。)

顺便说一下。对精度很重要的情况实际上不是乘法,而是加法/减法 - 这就是精度可以产生很大差异的地方。考虑添加/减去1e + 6和1e-3。

答案 1 :(得分:4)

意义比5-10%减速更重要。我要做的是:

double func_impl(double a, double b, double c, double d) {
    return (a - b) * c + (a - c) * b;
}

double func(float a, float b, float c, float d) {
    return func_impl(a, b, c, d);
}

我选择这个,即使它有点慢,因为它表达了你想要计算中的双精度并且只需要接口上的浮点数的想法;同时它保持你的功能的主体与铸造分开(后者在一个步骤中完成)。