(浮点)(1.2345f * 6.7809)比 1.2345f * 6.7809f 更准确
Is (float)(1.2345f * 6.7809) more accurate than 1.2345f * 6.7809f?
我有一些代码块可以:
float total = <some float>;
double some_dbl = <some double>;
total *= some_dbl;
这引发了一个编译器警告,我想关闭它,但我不喜欢关闭这样的警告 - 相反,我宁愿根据需要显式转换类型。这让我想到...(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;
}
编辑:所以,我试了一下。通过我尝试的示例,我确实很快找到了一个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
,而且也更接近实际值,这有点令人惊讶,因为我们在乘法发生之前就丢弃了信息。
> 根据所涉及的数字的大小,它会有所不同,因为double
不仅更精确,而且还可以容纳大于 float
的数字。下面是一个示例,它将显示一个这样的实例:
double d = FLT_MAX * 2.0;
float f = 1.0f / FLT_MAX;
printf("%fn", d * f);
printf("%fn", (float)d * f);
printf("%fn", (float)(d * f));
和输出:
2.000000
inf
2.000000
这是因为虽然float
显然可以保存计算结果 - 2.0
,但它不能保存FLT_MAX * 2.0
的中间值
如果执行操作,则编译器会将变量转换为该操作的最大数据类型。这里是双倍的。在我看来,操作:(float((var1f * var2(具有更高的准确性。
我测试了一下,它们并不相等。以下结果为 true
.http://codepad.org/3GytxbFK
#include <iostream>
using namespace std;
int main(){
double a = 1.0/7;
float b = 6.0f;
float c = 6.0f;
b = b * (float)a;
c = (float)((double)c * a);
cout << (b-c != 0.0f) << endl;
return 0;
}
这让我想到了理由:从乘法结果表示为double
到float
的转换将有更好的机会四舍五入。有些位可能会随着float
乘法而从末尾掉落,当在 double
s 上进行乘法然后转换为 float
时,该乘法本可以正确考虑。
顺便说一句,我选择了 1/7*6,因为它以二进制重复。
编辑:经过研究,似乎从双精度到浮点数的转换和浮点数乘法的舍入应该是相同的,至少在符合IEEE 754的实现中 https://en.wikipedia.org/wiki/Floating_point#Rounding_modes 是这样。
根据代码转储中的数字,float
的两个相邻可能值为:
d1 = 8.37149524...
d2 = 8.37149620...
以双精度执行乘法的结果是:
8.37149598...
当然,这介于这两者之间。 将此结果转换为 float
是实现定义的,即它是向上"还是向下"舍入"。 在代码结果中,转换选择了 d1
,这是允许的,即使它不是最接近的。混合精度乘法最终得到d2
.
因此,我们可以得出一个有点不直观的结论,在某些情况下,以双精度计算双精度然后转换为float
不如完全以float
精度计算准确!
- C++将浮点指针值舍入为小数位数
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 为什么在浮点中从大到小会引入更多的误差
- 我可以信任表示整数的浮点或双精度来保持精度吗
- 为什么mpfr_printf与十六进制浮点(%a转换说明符)的printf不同
- C++Lua用户数据扰乱了Mathfu浮点值
- 将CHW格式的浮点向量转换为cv::Mat
- 算术运算的结果类似于:C浮点变量中的1/3
- 格式化浮点值:返回默认值
- 浮点定向舍入和优化
- 短是浮点类型吗?
- 从VS 2015更新3更新到VS2015更新3 d后浮点计算行为不同的原因
- 使用 int 表示浮点除法 C++
- 像union_这样的 Boost.Geometry 操作如何处理浮点类型的基本不精确性?
- 浮点异常(核心转储)#694457
- 奇怪的缩小转换在 g++ 编译器中加倍到浮点警告
- C++17 十六进制浮点文字单精度后缀冲突?
- 从.txt文件中读取浮点型数字并在公式中使用它们
- 如何将 int 指针转换为浮点指针
- (浮点)(1.2345f * 6.7809)比 1.2345f * 6.7809f 更准确