【问题标题】:Issue with Square Root in C AlgorithmC算法中的平方根问题
【发布时间】:2017-11-02 06:08:16
【问题描述】:

我有一些代码可以在单位球面上找到一个点。回想一下,对于一个单位球体:

1 = sqrt(x^2 + y^2 + z^2)

该算法在零和一之间选择两个随机点(x 和 y 坐标)。如果它们的大小小于 1,我们就有空间通过求解上述 z 方程来定义第三个坐标。

void pointOnSphere(double *point){
double x, y;

do {
    x = 2*randf() - 1;
    y = 2*randf() - 1;
} while (x*x + y*y > 1);

double mag = sqrt(fabs(1 - x*x - y*y));

point[0] = 2*(x*mag);
point[1] = 2*(y*mag);
point[2] = 1 - 2*(mag*mag);
}

从技术上讲,我继承了这段代码。以前的所有者使用“无视严格的标准合规性”的 -Ofast 编译。 TL;DR 这意味着您的代码不需要遵循严格的 IEEE 标准。因此,当我尝试在不优化的情况下进行编译时,我遇到了错误。

 undefined reference to `sqrt'

什么是 IEEE 标准?嗯,因为计算机不能以无限精度存储浮点数,如果你不小心,在某些计算过程中会弹出舍入错误。

经过一番谷歌搜索后,我遇到了this question,这让我在正确使用 IEEE 东西方面走上了正轨。我什至读过this article 关于浮点数的文章(我推荐)。不幸的是,它没有回答我的问题。

我想在我的函数中使用 sqrt(),而不是像 Newton Iteration 这样的东西。我了解我的算法中的问题可能来自我可能(即使不是真的)将负数传递给 sqrt() 函数的事实。我只是不太确定如何解决这个问题。感谢大家的帮助!

哦,如果它是相关的,我正在使用 Mersenne Twister 数字生成器。

澄清一下,我将 libm 与 -lm 链接!我还确认它指向正确的库。

【问题讨论】:

  • -Ofast 可能内联了sqrt 调用。使用-lm 编译(特别是链接),你应该会很好
  • 您链接的问题中的this answer 是否无济于事?
  • 确保代码首先使用#include <math.h>
  • “算法在零和一之间选择两个随机点(x 和 y 坐标)。”和x = 2*randf() - 1; 不一致。 x[-1 0] 之间也可以有负值。
  • 你可能认为你正在链接 libm,但它很清楚地告诉你你不是。听听你的编译器。有时会出现问题的一件事是-lm 必须在gcc 命令上排在最后。另外,也许编译器和/或库没有安装正确?这里的所有其他东西都是分心的。找到图书馆!

标签: c algorithm sqrt ieee


【解决方案1】:

对于sqrt 的未定义引用,您需要与libm 链接,通常使用-lm 或类似选项。

还要注意

如果它们的大小小于 1,我们就有空间通过求解上述 z 方程来定义第三个坐标。

错了。 x 和 y 必须满足 x * x + y * y

【讨论】:

  • "x 和 y 必须满足 x * x + y * y 是不是用while (x*x + y*y > 1);投保了?
  • @chux 好吧,也许吧。我会说,代码与文本不一致。或者文字非常模棱两可。
  • 我在故障排除过程中很早就选中了这个框。我已经链接了 libm。这不是问题。你对数学的看法是正确的。
  • 然后你过早地勾选了那个框。其他一切都是干扰——让编译器命令指向正确的库。
  • 只有我一个人,还是只有这个答案真正试图回答这个问题?
【解决方案2】:

我会使用spherical coordinates

theta = randf()*M_PI;
phi = randf()*2*M_PI;
r = 1.0;
x = r*sin(theta)*cos(phi);
y = r*sin(theta)*sin(phi);
z = r*cos(theta);

【讨论】:

  • 注意:与 OP 的原始方法相比,使用球坐标确实会在球体上生成不同的点分布:可能更好,也可能更糟。然而,最终的 computed |x,y,z| 仍然可能超过 1.0 一点点。如果这对 OP 来说是个问题,那么在幅度过大时重新生成的循环很容易解决这个问题。
【解决方案3】:

为确保点满足条件,测试条件本身作为while 循环的一部分,而不是条件的推导。

// functions like `sqrt(), hypot()` benefit with declaration before use
//   and without it may generate "undefined reference to `sqrt'"
// Some functions like `sqrt()` are understood and optimized out by a smart compiler.
// Still, best to always declare them.
#include <math.h>

void pointOnSphere(double *point){
  double x, y, z;
  do {
    x = 2*randf() - 1;
    y = 2*randf() - 1;
    double zz = 1.0 - hypot(x,y); 
    if (zz < 0.) continue;  // On rare negative values due to imprecision
    z = sqrt(zz);
    if (rand()%2) z = -z;  // Flip z half the time
  } while (x*x + y*y + z*z > 1);  // Must meet this condition

  point[0] = x;
  point[1] = y;
  point[2] = z;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-14
    • 2021-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多