14

在 C++ 中,

const double Pi = 3.14159265;
cout << sin(Pi);                          // displays: 3.58979e-009

它应该显示数字零

我知道这是因为 Pi 是近似的,但是有什么方法可以将 Pi 的值硬编码到我的程序中,为 sin(Pi) 返回 0?(也许是一个不同的常数?)

如果您想知道我要做什么:我正在将极坐标转换为矩形,虽然我可以使用一些 printf() 技巧将其打印为“0.00”,但它仍然不能始终如一地返回体面值(在某些情况下我得到“-0.00”)

需要正弦和余弦的行是:

x = r*sin(theta);
y = r*cos(theta);

顺便说一句:我的 Rectangular -> Polar 工作正常......它只是 Polar -> Rectangular

谢谢!

编辑: 我正在寻找一种解决方法,以便我可以将 sin(Pi 的倍数)作为一个不错的整数打印到控制台(理想情况下没有一千个 if 语句)

4

14 回答 14

28

What Every Computer Scientist shall know about Floating-Point Arithmetic (edit: also got linked in a comment) is pretty hardcore reading (I can't claim to have read all of it),但关键在于:你会永远不会得到完全准确的浮点计算。来自文章:

将无限多个实数压缩为有限位数需要近似表示。

不要让你的程序依赖于浮点计算的精确结果——总是允许一个公差范围。仅供参考 3.58979e-009 约为 0.0000000036。这完全在您选择的任何合理公差范围内!

于 2010-04-19T21:26:37.580 回答
15

让我们这样说,3.58979e-009就像你的值与真实 Pi一样接近0 。3.14159265从技术上讲,你得到的是你所要求的。:)

现在,如果您只输入 9 位有效数字(8 位小数),则指示输出也不再显示,即使用:

cout.precision(8);
cout << sin(Pi);
于 2010-04-19T21:31:05.933 回答
4

如果您的等式运算符有足够的容差,则它等于零

于 2010-04-19T21:27:49.007 回答
4

您是否尝试过 M_PI,在大多数<cmath><math.h>实现中都可用?

即便如此,以这种方式使用浮点数总是会引入一定量的错误。

于 2010-04-19T21:32:26.367 回答
4

这应该显示为零:

cout << fixed << sin(Pi);

(我认为您不应该尝试四舍五入。如果您担心显示,请处理显示功能,而不是值本身。)

于 2010-04-19T22:10:09.573 回答
3

3.58979e-009 这是 0,0000000358979

是一个 ~~0 喜欢你的 ~~PI。

于 2010-04-19T21:26:13.957 回答
2

您可以输入更多数字以获得更好的结果(例如尝试 3.1415926535897932384626433832795029L),但仍然会出现舍入错误。

尽管如此,您仍然可以创建自己的版本sincos版本来检查您已知的 Pi 值并在这些情况下准确返回零。

namespace TrigExt
{
    const double PI = 3.14159265358979323846;

    inline double sin(double theta)
    {
        return theta==PI?(0.0):(std::sin(theta));
    }
}

您也可以将这个东西扩展为其他三角函数并处理 Pi 倍数。

于 2010-04-19T21:33:39.707 回答
1

你可以写一个小包装函数:

double mysin(const double d) {
    double ret = sin(d);
    if(fabs(ret) < 0.0000001) {
        return 0.0;
    } else {
        return ret;
    }
}

正如其他人所指出的,浮点数学是出了名的不精确。如果您希望某些东西看起来完全为零,则需要某种容忍度。

于 2010-04-19T21:30:35.387 回答
1

为什么不强制你需要多少位数

 int isin = (int)(sin(val) * 1000);
 cout << (isin/1000.0)
于 2010-04-19T21:31:38.333 回答
1

sin(PI) 应该等于 0,以获得 PI 的精确值。您没有输入 PI 的确切值。正如其他人指出的那样,您四舍五入到小数点后 7 位的结果是 0,这对您的近似值来说非常好。

如果您需要不同的行为,您应该编写自己的正弦函数。

于 2010-04-19T21:31:51.823 回答
0

如果您在数学运算中使用浮点数或双精度数,您将永远不会得到准确的结果。原因是在计算机中,所有内容都存储为 2 的幂。这并不能完全转换为我们的十进制数字系统。(一个例子是 0.1 的底数 2 中没有表示)

此外 float 和 double 至少在某些编译器和平台上是 64 位的。(我认为 - 如果需要,有人纠正我)。对于非常大的值或非常小的值(0.0000000000xxx),这将导致一些舍入错误

为了获得准确的结果,您将需要一些大整数库。

如对上述问题的评论中所写,请参阅该网站... http://docs.sun.com/source/806-3568/ncg_goldberg.html

于 2010-04-19T21:32:20.883 回答
0
double cut(double value, double cutoff=1e-7) {
  return (abs(value) > cutoff)*value;
}

这会将低于阈值的值归零,像这样使用它cut(sin(Pi))

于 2010-04-19T21:59:53.983 回答
-1

更重要的数字可能会有所帮助。我的 C 编译器 (gcc) 使用3.14159265358979323846“math.h”中的 M_PI 常量。除此之外,没有太多选择。创建自己的函数来验证答案(如您的问题的另一个答案中所述)可能是最好的主意。

于 2010-04-19T21:30:28.323 回答
-1

你知道,只是为了数学上的正确性:sin(3.14159265)不是零。它大约为零,这正是程序告诉你的。对于计算,这个数字应该会给你一个很好的结果。为了显示,它很糟糕,所以每当你打印一个浮点数时,一定要格式化数字。

我真的不认为这里的工作中有任何浮动机制......这只是简单的数学。

但是,关于代码,请注意...不会通过在显示之前进行近似来使您的代码给出错误的结果,只需以正确的方式显示信息。

于 2010-04-19T21:55:43.910 回答