'const'双重复制+比较安全吗?
Is 'const' double copying + comparison safe?
我注意到有很多关于浮点计算错误的讨论,这需要你使用比==
更复杂的比较。然而,所有这些文章似乎都假设该值以某种方式纵(或双重计算),而我没有看到一个涵盖非常简单的持续复制的示例。
请考虑以下事项:
const double magical_value = -10;
class Test
{
double _val;
public:
Test()
: _val(magical_value)
{
}
bool is_special()
{
return _val == magical_value;
}
};
据我了解,magical_value
应该在编译时设置,以便所有舍入都发生在该点。之后,应将该值复制到类中,并与原始值进行比较。这样的比较保证是安全的吗?或者复制或比较会在这里引入错误吗?
请不要建议其他比较或神奇值使用方法,这是另一个话题。我只是对这个假设感到好奇。
编辑:请注意,我有点担心在某些架构上,优化可能会导致将值复制到不同大小的浮点寄存器,从而引入确切值的差异。有没有发生类似事情的风险?
这样的比较保证是安全的吗?或者复制或比较会在这里引入错误吗?
是的,安全(这是 =
所暗示的复制操作的要求)。只要来源和目标类型相同,就无需担心转化/促销。
但是,请注意,magical_value
可能并不完全包含10
,而是一个近似值。此近似值将被复制到 _val
中。
考虑到const
限定符,magical_value
可能会被优化掉(如果您打开优化)或按原样使用(即可能不会用完内存)。
除了可能不同大小的寄存器之外,您还需要担心非规范化浮点(cq 齐平为零)(请参阅为什么将 0.1f 更改为 0 会使性能降低 10 倍?
只是为了说明这可能导致的奇怪之处,请尝试以下代码:
float a = 0.000000000000000000000000000000000000000047683384;
const float b = 0.000000000000000000000000000000000000000047683384;
float aa = a, bb = b;
#define SUPPORT_DENORMALIZATION ({volatile double t=DBL_MIN/2.0;t!=0.0;})
printf("support denormals: %dn",SUPPORT_DENORMALIZATION);
printf("a = %.48f, aa = %.48fna==aa %d, a==0.0f %d, aa==0.0f %dn",a,aa,a==aa,a==0.0f,aa==0.0f);
printf("b = %.48f, bb = %.48fnb==bb %d, b==0.0f %d, bb==0.0f %dn",b,bb,b==bb,b==0.0f,bb==0.0f);
它给出:(编译时不刷新为零)
support denormals: 1
a = 0.000000000000000000000000000000000000000047683384, aa = 0.000000000000000000000000000000000000000047683384
a==aa 1, a==0.0f 0, aa==0.0f 0
b = 0.000000000000000000000000000000000000000047683384, bb = 0.000000000000000000000000000000000000000047683384
b==bb 1, b==0.0f 0, bb==0.0f 0
或者:(用gcc -ffast-math
编译)
support denormals: 0
a = 0.000000000000000000000000000000000000000000000000, aa = 0.000000000000000000000000000000000000000000000000
a==aa 1, a==0.0f 1, aa==0.0f 1
b = 0.000000000000000000000000000000000000000047683384, bb = 0.000000000000000000000000000000000000000000000000
b==bb 1, b==0.0f 0, bb==0.0f 1
当然,最后一行是奇怪的:b==bb && b!=0.0f && bb==0.0f
是真的。
因此,如果您仍在考虑比较浮点值,请至少远离较小的值。
更新以抵消由于使用浮点数而不是双精度而导致的一些评论,它也适用于双精度,但您需要将常量设置为低于 DBL_MIN
的某个位置,例如 1e-309
.
更新 2 与下面提出的一些注释相关的代码示例。这表明双精度也存在问题,并且比较可能会变得不一致(当启用刷新为零时)
double a;
const double b = 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001225;
const double c = 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002225;
printf("b==c %dn",b==c);
a = b;
printf("assigned a=b: a==b %dn",a==b);
a = c;
printf("assigned a=c: a==b %dn",a==b);
输出:
b==c 0
assigned a=b: a==b 1
assigned a=c: a==b 1
该问题显示在最后一行中,您会天真地期望在分配a=c
后a==b
会变为 c!=b
。
- 从不同线程使用int64的不同字节安全吗
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 为什么比较运算符如此快速
- 虚拟决赛作为安全
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 单调计数整数的比较安全吗?
- 将无符号的 int 与 std::string::size_type 进行比较是否安全
- 原子增加和比较线程安全
- 在网络上的不同平台上比较boost :: typeIndex type hash_code()是安全的吗?
- 'const'双重复制+比较安全吗?
- 比较操作线程对 std::atomic 变量是安全的吗?
- 将两个 std::vector<cv::P oint> 向量和安全公共点与第三个 std::vector<cv::P oint 进行比较>
- xxx和bool在操作中的不安全混合仅在将值与TRUE进行比较时发出警告
- 按顺序比较C++迭代器安全吗
- 为什么编译器不使无符号与有符号的比较安全?
- 以本地化安全的方式比较C++中的字符串/字符和字符串/字符文本
- 正在使用std::max来比较两个替身是否安全
- 与 std::vector 的指针进行比较以检查相等性是否安全
- 在C, c++中比较布尔变量与1和0是否安全?