2

I am new to c++ and have written a small program to find out the sine and cosine values of an angle. My sample code is as follows:

#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;
}

I am getting 1.7949e-009 as the result for cos(90). Is there any way to get 0 as the result (in result variable) instead of this format? same problem is happing for sin 180 degree. I want a general solution of the cases where the resultant value will be 0.

user76289
  • 85
  • 1
  • 5

5 Answers5

3

Since you tagged the post C++ and not C, let me give you some C++ hints:

  1. The standard header for math is <cmath> and not <math.h>
  2. in c++ there are better way to declare constants that #define
  3. Floating point numbers are not exact representation of real number (for which no computational exact representation can exist), so you always end up with rounding errors.

A more idiomatic way to come to the result cam be this:

#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;
}

Note how I let std:: explicit: C++ <cmath> have more overload for math functions than C.

See:

Note also that, although a more accurate PI makes result to be more accurate, there is always the possibility that the result is not perfect, so -when display floating point values- set the precision to a level that is enough to compensate for commutation errors at a level that makes sense for your problem.

The representation precision of real numbers can be obtained from std::numeric_limits<double>::digits10 (from the <limits> header): it is alway good to cut-out 2-3 digits.

Also, consider rounding errors, when doing subtractions or comparisons: see the example in the std::numeric_limits::epsilon reference doc:

#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";
}

which shows how sqrt(5) squared is not ... 5, even if you manage to look so:

(Spoiler: the outpu is

d1 != d2
d1 almost equals d2

) ;-)

Emilio Garavaglia
  • 20,229
  • 2
  • 46
  • 63
1

Is there any way to get 0 as the result [for cosine(90°)]?

Step 1, use a more accurate machine PI

Step 2: Rather than convert to radians and then call cos(), reduce the range and then convert to radians and then call cos().

The range reduction can be done exactly with fmod(x,360.0) and further with various trigonometric identifies.

This answer provide info on the general approach and a detailed sind(double degrees). The following is a general solution of the cases where the resultant value will be 0. This post discusses -0.0 concerns.

// 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;
}
Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

the result is 1.7949e-009,this is the scientific way, you can use the fixed way,even specify the precision of point.

In fact 1.7949e-009 is about 0.0000000017949.

the user krzaq specify the output format to be fixed way and set precision 2, it will print :

the cosine of 90.0 degree is 0.00

besides your PI is not accurate enough.

to get high precision, the only extra thing you need to do is to download glm. glm is a outstanding math party, it works excellent in OpenGL math function. here is the code using 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;
}
Xin YANG
  • 81
  • 1
  • 9
  • is there any way to store the precise value in the result variable for future use? @FrancisHoo – user76289 Oct 13 '16 at 06:40
  • the result value is still 1.7949e-009, it does not been changed by the keyword fixed and setprecision(2). the keyword fixed and setprecision(2) just limit the output format. – Xin YANG Oct 13 '16 at 06:43
  • yes I am telling this. but what will I have to do to store the precise value for use? @FrancisHoo – user76289 Oct 13 '16 at 06:46
  • you mean you want to get the result value more precise? you can use the third party named glm. it has the function which can convert angle to radian. then the result will be 6.1232339957367660e-017, it is about 0.00000000000000006123233995736766. i will attach the code in my answer. – Xin YANG Oct 13 '16 at 06:57
  • no, I mean I will actually store 0 to result instead of 1.7949e-009. Is it possible? @FrancisHoo – user76289 Oct 13 '16 at 06:58
  • if the result variable's type is int, Then result will store 0, but i think it does suit the case when the angle is not 90. – Xin YANG Oct 13 '16 at 07:02
  • You don't *have* to download glm. Adding dependency on a substantially large library just for a simple math function (that you can brew on your own, if this answer actually bothered touching the point), is poor design. – StoryTeller - Unslander Monica Oct 13 '16 at 08:30
  • @StoryTeller yes, i agree. i thought/misunderstand user76289 wants to make the result more precise, so i just suggest a easy way to achieve it. but user76289 does not want to make the result precise, user76289 wants to make the result to be 0. so there is no need to use glm. you should see my comment above, i think you know why i put the glm code, right? – Xin YANG Oct 13 '16 at 10:08
0

I have try M_PI, 3.141592653589793238L or acos(-1l). All of these approximation of PI are not produce exactly 0 in your program. However, at least your can use std::setprecision and std::fixed (in iomanip) to display 0. Or maybe you can use custom epsilon to round the result.

khôi nguyễn
  • 626
  • 6
  • 15
-1
#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;
}