Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/141.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/image/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是';常数';双重复制+;比较安全?_C++_Floating Point - Fatal编程技术网

C++ 是';常数';双重复制+;比较安全?

C++ 是';常数';双重复制+;比较安全?,c++,floating-point,C++,Floating Point,我注意到有很多关于浮点计算错误的讨论,这要求您使用比==更复杂的比较。然而,所有这些文章似乎都假设该值被操纵(或双重计算),而我没有看到一个包含非常简单的常量复制的示例 请考虑以下事项: const double magical_value = -10; class Test { double _val; public: Test() : _val(magical_value) { } bool is_special() {

我注意到有很多关于浮点计算错误的讨论,这要求您使用比
==
更复杂的比较。然而,所有这些文章似乎都假设该值被操纵(或双重计算),而我没有看到一个包含非常简单的常量复制的示例

请考虑以下事项:

const double magical_value = -10;

class Test
{
    double _val;

public:
    Test()
        : _val(magical_value)
    {
    }

    bool is_special()
    {
        return _val == magical_value;
    }
};
据我所知,
magical_value
应该在编译时设置,以便所有舍入都发生在这一点上。之后,只需将值复制到类中,并与原始值进行比较。这样的比较能保证安全吗?或者复制或比较是否会在此处引入错误

请不要建议其他比较或神奇价值使用方法,这是另一个话题。我只是好奇这个假设

编辑:只是要注意,我有点担心在某些体系结构上,优化可能会导致将值复制到不同大小的浮点寄存器,从而导致精确值的差异。有这样的风险吗

这样的比较能保证安全吗?或者复制或比较是否会在此处引入错误

是,安全(这是复制操作的一项要求,如
=
所示)。只要源和目标类型相同,就不需要担心转换/促销

但是,请注意,
magical_值
可能不完全包含
10
,而是近似值。此近似值将被复制到
\u val


给定
const
限定符,有可能
magical_value
会被优化掉(如果您启用优化)或按原样使用(即,可能不会耗尽内存)。

除了可能大小不同的寄存器外,您还需要担心非规范化浮点(cq刷新为零)(请参阅)

为了让大家了解这可能导致的怪异,请尝试以下代码:

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: %d\n",SUPPORT_DENORMALIZATION);
printf("a = %.48f, aa = %.48f\na==aa %d, a==0.0f %d, aa==0.0f %d\n",a,aa,a==aa,a==0.0f,aa==0.0f);
printf("b = %.48f, bb = %.48f\nb==bb %d, b==0.0f %d, bb==0.0f %d\n",b,bb,b==bb,b==0.0f,bb==0.0f);
这将给出:(编译时没有刷新到零)

或者:(使用
gcc-ffast数学编译)

最后一行当然是奇数:
b==bb&&b=0.0f&&bb==0.0f
为真

因此,如果您仍在考虑比较浮点值,至少不要使用小值

更新为了抵消由于使用浮点数而不是双精度而引起的一些评论,它也适用于双精度,但您需要将常数设置为低于
DBL_MIN
,例如
1e-309

更新2与下面的一些评论相关的代码示例。这表明double也存在问题,并且比较可能变得不一致(当启用flush to zero时)

输出:

b==c 0
assigned a=b: a==b 1
assigned a=c: a==b 1

问题显示在最后一行中,在使用
c分配
a=c
后,您会天真地期望
a==b
将变为false=b

运行时是否会更改
\u val
的值?是的,它可以更改为实际值(但肯定是
-1
)。我不确定是否有必要将其“重置”为特殊值。我更希望复制浮点值不会改变它,并且给定两个相同原语类型的变量
a
b
,赋值
a=b
会导致
a==b
为真。然而,我是基于常识来做这个假设的,这在过去让我很失望。@Rook,前提是浮点不是任何计算的结果。从引入计算的那一刻起,您就开始涉及诸如扩展精度之类的内容。再加上一个优化器,您永远无法真正知道代码中实际发生了哪些赋值。因此,将任何东西与可能已计算的任何东西进行比较可能会导致精度问题。(当然,低值严格整数总是精确的)这与我的陈述相切。假设
float a=2f/7f,如果
浮点b=a,则仍应如此
那么
b==a
应该为真,对吗?这正是我的评论的目的。我高度怀疑是否有一种实现,
10
-10
不能准确地表示为
双精度
。在某些体系结构上,是否存在将值复制到不同精度寄存器的风险,从而引入潜在差异?@Henrik:不是大约值为10。此外,许多人倾向于忽略浮点类型使用尾数指数表示的事实。@MichałGórny:
magical_value
是一个
const
,可能永远看不到曙光(不断传播)。剩下要检查的是
\u val
的情况。[1] 鉴于
\u val
可能持有也可能不持有
magical\u value
的值,您不能依赖
=
进行相等性测试。[2] 请注意,您使用的是本机浮点类型,即
double
(其实际大小可能因架构而异)
double
(和
int
)是升级为类型的,因为它们是寄存器标准中最好的抽象。这应该可以解决任何与寄存器相关的问题。@MicthałGórny:我的意思是:
=
在副本上工作正常。复制的语义保证了这一点。但是,如果
\u val
可以有另一个值(比如通过某个表达式赋值),那么当然不能仅依靠
==
,而需要考虑浮点差异。-1。请参阅我在回答中的评论。我已经指出了这段代码的足够多的问题。“我真的看不出你想证明什么,”肮脏的家伙,放松点。警察局
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
    double a;
    const double b = 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001225;
    const double c = 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002225;

    printf("b==c %d\n",b==c);
    a = b;
    printf("assigned a=b: a==b %d\n",a==b);
    a = c;
    printf("assigned a=c: a==b %d\n",a==b);
b==c 0
assigned a=b: a==b 1
assigned a=c: a==b 1