提问人:Powereleven 提问时间:7/11/2022 最后编辑:Powereleven 更新时间:7/13/2022 访问量:137
浮点不准确以奇怪的方式破坏了幂等性
Floating point inaccuracies breaks idempotence in weird ways
问:
我想知道在归一化矢量(特别是 3D 矢量)时,浮点误差会有多严重。归一化一次应该给出与归一化两次相同的值,但正如预期的那样,浮点不准确并不能保证我们这一点。因此,我决定测试一些其他东西:如果你无限期地归一化,它会总是“收敛”到一个归一化为自身的值吗?答案是否定的。例如,几秒钟的测试,我发现了一个在 2: 和 之间循环的值。有些在 3、5 步后“收敛”。这是我无聊的代码:-0.60445204839058564 -0.54547899327834748 -0.58059485795902943
-0.60445204839058575 -0.54547899327834759 -0.58059485795902954
#include <iostream>
#include <numeric>
#include <random>
using namespace std;
struct Point
{
double x, y, z;
bool operator==(const Point& o) const
{
return
x == o.x &&
y == o.y &&
z == o.z;
}
};
auto square(auto x)
{
return x * x;
}
Point normalize(const Point& p)
{
auto l = sqrt(square(p.x) + square(p.y) + square(p.z));
return { p.x / l, p.y / l, p.z / l };
}
std::mt19937 mt(24);
std::uniform_real_distribution d(-1., 1.);
int main()
{
while (true)
{
auto
x = d(mt),
y = d(mt),
z = d(mt);
Point p{ x, y, z };
auto
n1 = normalize(p),
n2 = normalize(normalize(p));
int cnt = 1;
while (n1 != n2)
{
n1 = n2;
cnt++;
n2 = normalize(n2);
auto len = square(n2.x) + square(n2.y) + square(n2.z);
if (len != 1.)
{
__debugbreak();
}
}
if (cnt != 2)
{
cout << x << ' ' << y << ' ' << z
<< " took " << cnt << '\n';
}
}
}
所以我有一些好奇心:
- 哪些输入会产生最长的循环/周期,并且永远不会收敛?
- 哪些输入需要最长的时间才能收敛?
- 归一化一次后,什么输入给出长度为 1 的最大误差?
答: 暂无答案
评论
square(p.x) + square(p.y) + square(p.z)