具有负向量大小计算的 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;
在使用参数调用 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;