精度损失?
Loss of precision?
我有这样的功能:
double calc( double x );
使用这些表达式时我会失去精度吗:
double y1 = calc( 1.0 / 3 );
double y2 = calc( 1.0 / 3.0 );
这些是否更准确:
double y3 = calc( static_cast<double>(1) / 3 )
double y4 = calc( static_cast<double>(1) / static_cast<double>(3) )
编辑
对不起,我打错号码了。
但是,我的意思是 1.0
被解释为 float
或 double
并且情况总是如此还是取决于某些编译器标志?如果它是 float
,那么 1.0/3
也会是 float
,然后才转换为 double
。如果是这样,会导致精度损失,不是吗?
编辑 2
我已经用 g++
测试了这个,事实证明,如果程序是用 -fsingle-precision-constant
标志编译的,你 do 会失去精度。
#include <iostream>
#include <limits>
#include <typeinfo>
long double calc( long double val)
{
return val;
}
int main() {
std::cout.precision(std::numeric_limits< long double >::max_digits10);
std::cout << calc(1.0/3.0) << std::endl;
std::cout << calc(static_cast<float>(1)/3) << std::endl;
std::cout << calc(static_cast<double>(1)/3) << std::endl;
std::cout << calc(static_cast<long double>(1)/3) << std::endl;
std::cout << typeid(1.0).name() << std::endl;
return 0;
}
结果是,
0.333333343267440795898
0.333333343267440795898
0.33333333333333331483
0.333333333333333333342
f
所以,为了安全起见,我决定使用static_cast< long double >(1) / 3
。
没有。 y1
的常量表达式被 隐式 转换为 double
。 y2
的常量表达式已经是 double
.
你在 y3
和 y4
中所做的是定义一个常量整数值并将其转换为 double
,而你可以简单地定义一个双精度浮点数正如您所做的那样保持不变。
None 您显示的替代方案会导致任何精度损失 [至少如果编译器按照标准所说的去做,则不会]。即所有一个操作数是 double
的二元运算符,另一侧会自动提升为 double
[并且通常,当两个操作数的大小不同时,它们会被提升为较大的一个]。
特别是 [低于尾数的位数] 的整数值总是被精确表示。
[显然,我们不知道 calc
对您的输入做了什么 - 这可能是所有类型错误的根源,但我假设您实际上是在问 3.0/8.0
在您建议的情况下将始终为 0.375
- 当然 3/8
将导致零,因为它在两边都是整数]
针对正在编辑的原始问题进行编辑:
如果代码显示 1.
或 1.0
或 0.3
或 .3
,则它是 double
。如果你写0.5f
,它就是一个float
。根据上述规则,1.0/3
将是 double(1.0)/double(3.0)
的结果。
编译器仅支持一种浮点类型在技术上是可行的,有 3 种不同的编写方式 - C 和 C++ 标准不要求 double
的位数多于 float
.
我有这样的功能:
double calc( double x );
使用这些表达式时我会失去精度吗:
double y1 = calc( 1.0 / 3 );
double y2 = calc( 1.0 / 3.0 );
这些是否更准确:
double y3 = calc( static_cast<double>(1) / 3 )
double y4 = calc( static_cast<double>(1) / static_cast<double>(3) )
编辑
对不起,我打错号码了。
但是,我的意思是 1.0
被解释为 float
或 double
并且情况总是如此还是取决于某些编译器标志?如果它是 float
,那么 1.0/3
也会是 float
,然后才转换为 double
。如果是这样,会导致精度损失,不是吗?
编辑 2
我已经用 g++
测试了这个,事实证明,如果程序是用 -fsingle-precision-constant
标志编译的,你 do 会失去精度。
#include <iostream>
#include <limits>
#include <typeinfo>
long double calc( long double val)
{
return val;
}
int main() {
std::cout.precision(std::numeric_limits< long double >::max_digits10);
std::cout << calc(1.0/3.0) << std::endl;
std::cout << calc(static_cast<float>(1)/3) << std::endl;
std::cout << calc(static_cast<double>(1)/3) << std::endl;
std::cout << calc(static_cast<long double>(1)/3) << std::endl;
std::cout << typeid(1.0).name() << std::endl;
return 0;
}
结果是,
0.333333343267440795898
0.333333343267440795898
0.33333333333333331483
0.333333333333333333342
f
所以,为了安全起见,我决定使用static_cast< long double >(1) / 3
。
没有。 y1
的常量表达式被 隐式 转换为 double
。 y2
的常量表达式已经是 double
.
你在 y3
和 y4
中所做的是定义一个常量整数值并将其转换为 double
,而你可以简单地定义一个双精度浮点数正如您所做的那样保持不变。
None 您显示的替代方案会导致任何精度损失 [至少如果编译器按照标准所说的去做,则不会]。即所有一个操作数是 double
的二元运算符,另一侧会自动提升为 double
[并且通常,当两个操作数的大小不同时,它们会被提升为较大的一个]。
特别是 [低于尾数的位数] 的整数值总是被精确表示。
[显然,我们不知道 calc
对您的输入做了什么 - 这可能是所有类型错误的根源,但我假设您实际上是在问 3.0/8.0
在您建议的情况下将始终为 0.375
- 当然 3/8
将导致零,因为它在两边都是整数]
针对正在编辑的原始问题进行编辑:
如果代码显示 1.
或 1.0
或 0.3
或 .3
,则它是 double
。如果你写0.5f
,它就是一个float
。根据上述规则,1.0/3
将是 double(1.0)/double(3.0)
的结果。
编译器仅支持一种浮点类型在技术上是可行的,有 3 种不同的编写方式 - C 和 C++ 标准不要求 double
的位数多于 float
.