【问题标题】:finding sine and cosine values of an angle in c++在 C++ 中查找角度的正弦和余弦值
【发布时间】:2016-10-13 05:52:21
【问题描述】:

我是 C++ 新手,编写了一个小程序来找出角度的正弦和余弦值。我的示例代码如下:

#include <math.h>
#include <iostream>
#include <iomanip>
using namespace std;
#define PI 3.14159265

int main ()
{
    double rate, result;
    rate = 90.0;
    result = cos (rate*PI/180);
    cout<<"The cosine of " << rate << " degrees is " << result <<endl;
    return 0;
}

我得到 1.7949e-009 作为 cos(90) 的结果。有没有办法得到 0 作为结果(在结果变量中)而不是这种格式?同样的问题也发生在 180 度的罪中。我想要一个结果值为 0 的情况的通用解决方案。

【问题讨论】:

  • 抛弃#define PI,使用数学标题中的M_PI。
  • @n.m.这不是一个标准化的定义
  • 我会说你的 PI 不够准确(它的精度与你得到的结果大致相同)所以试着给它,比如说,15 位数的精度,然后再试一次。
  • 附带说明:在编写 c++ 代码时,更喜欢使用 cmath 而不是 math.h。它更地道。
  • @krzaq 由 POSIX 标准化。不符合规范的系统可能会在地狱中被烧毁。

标签: c++ math trigonometry


【解决方案1】:

既然您标记了帖子 C++ 而不是 C,让我给您一些 C++ 提示:

  1. 数学的标准标题是&lt;cmath&gt; 而不是&lt;math.h&gt;
  2. 在c++中有更好的方法来声明#define的常量
  3. 浮点数不是实数的精确表示(不存在计算精确表示),因此您总是会出现舍入错误。

获得结果的更惯用方法是:

#include <cmath>
#include <iostream>
#include <iomanip>

int main ()
{
    const auto PI = std::acos(-1); //let the  computer to find out what PI is

    double rate{}, result{}; //don't let uninitialized values
    rate = 90.0;
    result = std::cos (rate*PI/180);
    std::cout<<"The cosine of " << // set outoput precison for floating point
         std::setprecision(4) << rate << " degrees is " << 
         std::setprecision(4) << result <<endl;
    return 0;
}

注意我是如何让 std:: 显式:C++ &lt;cmath&gt; 的数学函数比 C 有更多的重载。

见:

还要注意,虽然更准确的 PI 会使result 更准确,但结果总是有可能不完美,因此 - 当显示浮点值时 - 将精度设置为足够的水平在对您的问题有意义的水平上补偿换向错误。

实数的表示精度可以从std::numeric_limits&lt;double&gt;::digits10(来自&lt;limits&gt;标头)获得:切掉2-3位总是好的。

此外,在进行减法或比较时,请考虑舍入误差:请参阅std::numeric_limits::epsilon 参考文档中的示例:

#include <cmath>
#include <limits>
#include <iomanip>
#include <iostream>
#include <type_traits>
#include <algorithm>

template<class T>
typename std::enable_if<!std::numeric_limits<T>::is_integer, bool>::type
    almost_equal(T x, T y, int ulp)
{
    // the machine epsilon has to be scaled to the magnitude of the values used
    // and multiplied by the desired precision in ULPs (units in the last place)
    return std::abs(x-y) < std::numeric_limits<T>::epsilon() * std::abs(x+y) * ulp
    // unless the result is subnormal
           || std::abs(x-y) < std::numeric_limits<T>::min();
}
int main()
{
    double d1 = 0.2;
    double d2 = 1 / std::sqrt(5) / std::sqrt(5);

    if(d1 == d2)
            std::cout << "d1 == d2\n";
    else
            std::cout << "d1 != d2\n";

    if(almost_equal(d1, d2, 2))
            std::cout << "d1 almost equals d2\n";
    else
            std::cout << "d1 does not almost equal d2\n";
}

这表明 sqrt(5) 的平方不是... 5,即使您设法看起来是这样:

(剧透:输出是

d1 != d2
d1 almost equals d2

) ;-)

【讨论】:

    【解决方案2】:

    有没有办法得到 0 作为结果 [for cosine(90°)]?

    第一步,用更精准的机器PI

    第 2 步:与其转换为弧度然后调用cos(),不如缩小范围并然后转换为弧度然后调用cos()

    范围缩小可以通过exactlyfmod(x,360.0) 来完成,还可以通过各种trigonometric identifies 来完成。

    This answer 提供有关一般方法的信息和详细的sind(double degrees)。以下是结果值为 0 的情况的一般解决方案。This post 讨论 -0.0 关注点。

    // cos()  of 90.0 degrees is   6.1232339957367660e-17
    // cosd() of 90.0 degrees is   0.0000000000000000e+00
    
    #include <cmath>
    
    
    static double d2r(double d) {
      static const auto PI = std::acos(-1);
      return (d / 180.0) * PI;
    }
    
    double cosd(double x /* degrees */) {
      if (!isfinite(x)) {
        return std::cos(x);
      }
      int quo;
      double x90 = std::remquo(std::fabs(x), 90.0, &quo);
      double xr = d2r(x90);
      switch (quo % 4) {
        case 0:
          return std::cos(xr);
        case 1:
          // Use + 0.0 to avoid -0.0
          return std::sin(-xr + 0.0);
        case 2:
          return -std::cos(xr);
        case 3:
          return std::sin(xr + 0.0);
      }
      return 0.0;
    }
    

    【讨论】:

      【解决方案3】:

      我尝试过 M_PI、3.141592653589793238L 或 acos(-1l)。在您的程序中,所有这些 PI 近似值都不会精确地产生 0。 但是,至少您可以使用 std::setprecision 和 std::fixed (在 iomanip 中)来显示 0。 或者,也许您可​​以使用自定义 epsilon 来舍入结果。

      【讨论】:

        【解决方案4】:

        结果是1.7949e-009,这是科学的方式,可以使用固定方式,甚至可以指定点的精度。

        事实上 1.7949e-009 大约是 0.0000000017949。

        用户 krzaq 指定输出格式为固定方式并设置精度为 2,它将打印:

        the cosine of 90.0 degree is 0.00
        

        除了你的 PI 不够准确。

        要获得高精度,您唯一需要做的额外事情就是下载 glm。 glm 是一个出色的数学派对,它在 OpenGL 数学函数中表现出色。 这是使用 glm 的代码:

        #include <iostream>
        #include <glm.hpp>
        
        int main()
        {
            double Angle, Result;
            Angle  = 90.0;
            Result = glm::cos(glm::radians(Angle));
            std::cout << "The cosine of " << Angle << " degrees is " << std::fixed << Result << std::endl;
            return 0;
        }
        

        【讨论】:

        • 有没有办法将精确值存储在结果变量中以备将来使用? @FrancisHoo
        • 结果值还是1.7949e-009,没有被关键字fixed和setprecision(2)改变。关键字 fixed 和 setprecision(2) 只是限制输出格式。
        • 是的,我在说这个。但是我必须做些什么来存储使用的精确值? @FrancisHoo
        • 你的意思是你想得到更精确的结果值?您可以使用名为 glm 的第三方。它具有将角度转换为弧度的功能。那么结果将是 6.1232339957367660e-017,大约是 0.00000000000000006123233995736766。我将在我的答案中附上代码。
        • 不,我的意思是我实际上会将 0 存储到结果而不是 1.7949e-009。是否可以? @FrancisHoo
        【解决方案5】:
        #include <stdio.h>      
        #include <math.h>    
        
        #define PI 3.14159265
        
        int main (){
        
          double param, result;
          param = 30.0;
          result = sin (param*PI/180);
          printf ("The sine of %f degrees is %f.\n", param, result );
          return 0;
        }
        

        【讨论】:

        • 但它实际上并没有在结果变量中存储 0。对? @risabhgupta
        • printfostream 可能使用不同的打印精度,但这只是处理症状。
        猜你喜欢
        • 2017-10-06
        • 1970-01-01
        • 2013-04-05
        • 1970-01-01
        • 2016-06-16
        • 2012-10-06
        • 1970-01-01
        • 2015-05-23
        • 1970-01-01
        相关资源
        最近更新 更多