(浮动)(1.2345f*6.7809)比1.2345f*6.7809f更准确吗?

Rol*_*lie 11 c++

我有一些代码块:

float total = <some float>;
double some_dbl = <some double>;

total *= some_dbl;
Run Code Online (Sandbox Code Playgroud)

这引发了我想要关闭的编译器警告,但我不喜欢关闭这样的警告 - 相反,我宁愿根据需要显式地转换类型.让我思考的是...... (float)(total * some_dbl)比准确total * (float)some_dbl吗?它是编译器还是平台特定的?

更好的代码示例(链接如下):

#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;

int main() {
    double d_total = 1.2345678;
    float f_total = (float)d_total;
    double some_dbl = 6.7809123;

    double actual = (d_total * some_dbl);
    float no_cast = (float)(f_total * some_dbl);
    float with_cast = (float)(f_total * (float)some_dbl);

    cout << "actual:               " << setprecision(25) << actual << endl;
    cout << "no_cast:              " << setprecision(25) << no_cast << endl;
    cout << "with_cast:            " << setprecision(25) << with_cast << endl;
    cout << "no_cast, nextafter:   " << setprecision(25) << nextafter(no_cast, 500.0f) << endl;

    cout << endl;

    cout << "Diff no_cast:   " << setprecision(25) << actual - no_cast << endl;
    cout << "Diff with_cast: " << setprecision(25) << with_cast - actual << endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编辑: 所以,我给了这个镜头.通过我尝试过的例子,我确实找到了一个total * (float)(some_dbl)看起来准确的地方.我认为这并非总是如此,而是绘制的运气,或者编译器截断双精度以获得浮动,而不是舍入,从而导致可能更糟的结果.请参阅:http://ideone.com/sRXj1z

编辑2:我确认使用std::nextafter(float)(total * some_dbl)返回截断值,并更新链接代码.这是非常令人惊讶的:如果在这种情况下编译器总是截断双精度,那么你可以说(float)some_dbl <= some_dbl,这意味着with_cast <= no_cast.但事实并非如此!因为我们在乘法发生之前丢弃信息,所以它with_cast不仅大于no_cast,而且更接近实际值,这有点令人惊讶.

Cor*_*son 10

它将根据所涉及数字的大小产生影响,因为double它不仅仅是更精确,而且还可以包含大于的数字float.这是一个示例,它将显示一个这样的实例:

double d = FLT_MAX * 2.0;
float f = 1.0f / FLT_MAX;

printf("%f\n", d * f);
printf("%f\n", (float)d * f);
printf("%f\n", (float)(d * f));
Run Code Online (Sandbox Code Playgroud)

并输出:

2.000000
inf
2.000000
Run Code Online (Sandbox Code Playgroud)

发生这种情况是因为虽然float显然可以保持计算结果 - 2.0但它不能保持中间值FLT_MAX * 2.0


小智 2

如果您执行某个操作,则编译器会将变量转换为该操作的最大数据类型。这里是双的。在我看来,操作: (float)(var1f * var2) 具有更高的准确性。