C++使用负矢量大小计算的 pow 行为

C++ pow behaviour with negative vector size calculations

本文关键字:计算 pow 行为 C++      更新时间:2023-10-16

在调用pow函数后,如下面的代码所示 它产生一些高数字,就好像它正在访问一些无效的内存位置一样。 我不知道为什么会发生这种情况,任何帮助将不胜感激。

#include <iostream>
#include <vector>
#include <math.h>
using namespace std;
int main() {
vector<vector<int>> G = {
{1, 2, 3}, 
{0, 4}
};
cout << pow(G[1].size() - G[0].size(), 2) << endl;
return 0;
}

这将打印 1.84467e+019。

.size()的类型是unsigned的,当左操作数小于右操作数时,你不能简单地减去它们。

试试这个:

cout << pow((long) G[1].size() - (long)G[0].size(), 2) << endl;
~~~~~~               ~~~~~~

但是,此解决方案基于以下假设:强制转换.size()的结果适合signed long


如果你想要一个更具防御性的代码,试试这个:

size_t size_diff(size_t s0, size_t s1)
{
return s0 < s1? (s1 - s0) : (s0 - s1);
}
int main() {
// ...   
cout << pow(size_diff(G[1].size(), G[0].size()), 2) << endl;
} 

除了接受的答案之外,我还想指出,在 C++20 中,我们将拥有std::ssize()免费函数,该函数将 size 作为有符号类型值返回。然后

std::pow(std::ssize(G[1]) - std::ssize(G[0]), 2)

将在没有显式类型强制转换的情况下生成正确的结果。

由于pow将浮点值作为其第一个参数,因此我建议让编译器通过将差异添加到0.0(或0.0L(来决定正确的提升:

#include <iostream>
#include <cstdint>
#include <cmath>
using namespace std;
int main()
{
std::string name;
/// 52 of 64 bits used
uint64_t n1 = 0x000ffffffffffffd;
uint64_t n2 = 0x000fffffffffffff;
cout << "plain: " << n1 - n2 << endl;
cout << "float: " << (float)n1 - (float)n2 << endl;
cout << "double: " << (double)n1 - (double)n2 << endl;
cout << "long double: " << (long double)n1 - (long double)n2 << endl;
cout << "0.0+: " << 0.0 + n1 - n2 << endl;
cout << "0.0L+: " << 0.0L + n1 - n2 << endl;
cout << "pow(plain, 2): " << pow(n1-n2, 2) << endl;
cout << "pow(0.0+diff, 2): " << pow(0.0+n1-n2, 2) << endl;
cout << "pow(0.0L+diff, 2): " << pow(0.0L+n1-n2, 2) << endl;
}

输出

plain: 18446744073709551614
float: 0
double: -2
long double: -2
0.0+: -2
0.0L+: -2
pow(plain, 2): 3.40282e+38
pow(0.0+diff, 2): 4
pow(0.0L+diff, 2): 4

表明普通减法出错。即使投射到float也是不够的,因为float只提供 23 位尾数。

对于地址空间低于 4.5 PB 的进程,是使用0.0还是0.0L来决定实际std::vector::size()调用返回的size_t值的差异是理论上的。

所以我认为以下内容就可以了:

cout << pow(0.0 + G[1].size() - G[0].size(), 2) << endl;