C++ 为什么两个浮点型变量的值不同

C++ 为什么两个浮点型变量的值不同,c++,C++,我有两个大小接近1000的整数向量,我要做的是检查这两个向量的平方整数之和是否相同。所以我写了以下代码: std::vector<int> array1; std::vector<int> array2; ... // initialize array1 and array2, and in the experiment all elements // in the two vectors are the same but the sequence of elem

我有两个大小接近1000的整数向量,我要做的是检查这两个向量的平方整数之和是否相同。所以我写了以下代码:

std::vector<int> array1;
std::vector<int> array2;
... // initialize array1 and array2, and in the experiment all elements
    // in the two vectors are the same but the sequence of elements may be different.
    // For example: array1={1001, 2002, 3003, ....} 
   //               array2={2002, 3003, 1001, ....}
assert(array1.size() == array2.size());
float sum_array1 = 0;
float sum_array2 = 0;
for(int i=0; i<array1.size(); i++)
       sum_array1 +=array1[i]*array1[i];
for(int i=0; i<array2.size(); i++)
       sum_array2 +=array2[i]*array2[i];

这次
sum\u array1
等于
sum\u array2
sum\u array1=sum\u array2=1286862225.0000000
。我的问题是为什么会发生。谢谢

浮点表示法(通常是IEEE754)使用有限位来表示小数,所以

通常,与常识相反,如果
a
是浮点变量,则类似
a==((a+1)-1)
的比较会导致
false

解决方案: 要比较两个浮点,必须使用一种“精度损失范围”。也就是说,如果一个数不同于其他精度损失范围,则认为数字是相等的:

//Supposing we can overload operator== for floats
bool operator==( float lhs , float rhs)
{
    float epsilon = std::numeric_limits<float>.epsilon();

    return std::abs(lhs-rhs) < epsilon;
}
//假设我们可以重载浮点运算符==
布尔运算符==(浮动左侧,浮动右侧)
{
float epsilon=std::numeric_limits.epsilon();
返回标准::abs(lhs-rhs)
A
double
float
有更多的位,因此保存的信息也更多。当您将值添加到浮点时,它将在sum_array1与sum_array2的不同时间舍入信息

根据输入值的不同,使用double作为float(如果值足够大)时可能会出现相同的问题


通过网络搜索“有关浮点数的所有您需要了解的信息”,您可以很好地了解这些限制,以及如何最好地处理它们。

在两个循环中,您添加的数字相同,但顺序不同。一旦总和超过了可由
浮点
精确表示的整数值,就会开始失去精度,并且总和可能会略有不同

供您尝试的实验:

float n = 0;
while (n != n + 1)
    n = n + 1;
//Will this terminate? If so, what is n now?
如果你运行这个,你会发现循环实际上终止了——这看起来完全违反直觉,但根据IEEE算法的定义,这是正确的行为


您可以尝试同样的实验,将
浮点
替换为
双精度
。您将看到相同的奇怪行为,但这一次循环将在
n
大得多时终止,因为IEEE数字具有更高的精度。

浮点值大小有限,因此只能以有限的精度表示实际值。当您需要比存储精度更高的精度时,这会导致舍入错误

特别是,当把一个小数字(比如你正在求和的数字)加到一个大得多的数字(比如你的累加器)上时,与这个小数字相比,精度的损失可能相当大,从而产生很大的误差;根据顺序的不同,错误也会有所不同

通常,
float
具有24位精度,对应于大约7位小数。累加器需要10位小数(大约30位),因此您将体验精度损失。通常,
double
有53位(大约16位小数位),因此可以精确地表示结果

64位整数可能是这里的最佳选择,因为所有输入都是整数。使用整数可以避免精度损失,但如果输入太多或太大,则会有溢出的危险


如果不能使用足够宽的累加器,为了最大限度地减少错误,可以对输入进行排序,以便首先累加最小的值;或者您可以使用更复杂的方法,例如。

您没有提供足够的信息。这两种计算是相同的,因此它们应该产生相同的结果。问题一定出在其他地方,在你没有展示的代码中。永远不要比较浮点数是否相等!使用任意或固定精度的整数类,或在可接受的错误级别内比较浮点。这些向量的长度相同吗?您能对它们进行排序并按元素进行比较吗?你能利用身份sq(a)-sq(b)=(a+b)*(b-a)吗?有一些事情要考虑,我不认为这个问题应该结束。问题不仅仅是比较浮点数。这是关于为什么以不同的顺序添加浮点数会产生不同的结果。如果这个问题是重复的,我会投票将其标记为重复,但这不是“比较浮动”常见问题的重复。但是这两个计算是相同的。浮点不是随机的,结果应该相同。编辑不正确。有些值的等式不成立,但作为一般语句,它不是真的。@PeteBecker,如果它们按不同的顺序添加,它们就不一样了。@PeteBecker取决于哪些浮点数被放入CPU寄存器以及何时放入。CPU寄存器可能大于浮点型。@joshpoley-你说得对;我没注意到。@Pete:计算结果不一样。它们的顺序不同,这会影响结果。如果您在
array1
中循环两次,它们是相同的。如果您(无意中)使用激进的优化,则循环可能永远不会终止,这会导致
n=n+1
无论发生什么
n
,即使用数学上精确的算法进行推理(不包括
n
=无穷大)。@沃尔特回答这个问题的要点。
float n = 0;
while (n != n + 1)
    n = n + 1;
//Will this terminate? If so, what is n now?