将浮点数相乘并保持/获得双精度精度

Multiplying floats and keep/get double precision accuracy

本文关键字:双精度 精度 浮点数      更新时间:2023-10-16

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

当两个浮点数相乘时,例如float e, f;double g = e * f,什么时候位被截断?

在下面的示例函数中,我是否需要强制类型转换,如果是,在哪里?这是一个紧密的内循环,如果我把static_cast<double>(x)放在每个变量a b c d周围,我得到5-10%的减速。但我怀疑我不需要单独转换每个变量,只在某些位置,如果有的话?还是说这里返回一个double类型不会给我任何增益我可以直接返回一个float类型?

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

当您将两个浮点数相乘而不进行强制转换时,结果将以浮点精度计算(即截断),然后转换为double。

要以double形式计算结果,首先需要将至少一个操作数强制转换为double类型。然后整个计算将以双精度完成(并且所有浮点值都将被转换)。然而,这将造成同样的放缓。速度变慢可能是因为将浮点数转换为双精度数并不完全是微不足道的(不同的位大小以及指数和尾数的范围)。

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

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

意义比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);
}

我会选择这个,即使它有点慢,因为它表达了你想在计算中有双精度的想法,只需要接口上的浮点数;虽然它使函数体与强制转换分离(后者在一步中完成)。