具有负向量大小计算的 C++ pow 行为

C++ pow behaviour with negative vector size calculations

在使用参数调用 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() 自由函数,returns 大小作为有符号类型值。那么

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

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

因为 pow takes a floating point value as its first argument, I'd suggest letting the compiler decide the right promotion by adding the difference to 0.0 (or 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 位尾数。

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

所以我认为以下内容可以做到:

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