views:

829

answers:

14

In C++,

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

it SHOULD display the number zero

I understand this is because Pi is being approximated, but is there any way I can have a value of Pi hardcoded into my program that will return 0 for sin(Pi)? (a different constant maybe?)

In case you're wondering what I'm trying to do: I'm converting polar to rectangular, and while there are some printf() tricks I can do to print it as "0.00", it still doesn't consistently return decent values (in some cases I get "-0.00")

The lines that require sin and cosine are:

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

BTW: My Rectangular -> Polar is working fine... it's just the Polar -> Rectangular

Thanks!

edit: I'm looking for a workaround so that I can print sin(some multiple of Pi) as a nice round number to the console (ideally without a thousand if-statements)

+3  A: 

3.58979e-009 this is 0,0000000358979

Is a ~~0 like yours ~~PI.

Svisstack
+25  A: 

What Every Computer Scientist Should 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), but the crux of it is this: you'll never get perfectly accurate floating point calculations. From the article:

Squeezing infinitely many real numbers into a finite number of bits requires an approximate representation.

Don't let your program depend on exact results from floating point calculations - always allow a tolerance range. FYI 3.58979e-009 is about 0.0000000036. That's well within any reasonable tolerance range you choose!

AshleysBrain
yeah I tried having a threshold such that anything within some really small range of a integer gets rounded to that integer, but I must have picked too big of a range because I kept falsely rounding other numbers that I didn't intend to.
advs89
`if (fabs(x - y) < 0.000001)` should do the trick. It will be true if x is very nearly equal to y (in this case y is 0).
AshleysBrain
This is essentially what I was looking for... I made an attempt at this on my own but my threshold constant was too loose. This seems to work well enough.
advs89
actually now that I think about it, my threshold was stricter than that... I do, however, think I may have left out the absolute value function.
advs89
+1  A: 

it's equal to zero if your equality operator has enough tolerance

drscroogemcduck
A: 

More significant figures might help. My C compiler (gcc) uses the constant 3.14159265358979323846 for M_PI in "math.h". Other than that, there aren't many options. Creating your own function to validate the answer (as described in another answer to your question) is probably the best idea.

Dustin
Why is the Python one different after the 15th decimal place?
Michael Myers
*shrug* I'm just providing information that I have. It appears that the Python one is inaccurate... It is now removed. :P
Dustin
Looks like you are using a double for that. Additional digits won't help at all.The correct figures are3.141592653589793 2384626433...
EvilTeach
The Python one is wrong. Or rather, it's being displayed in more digits than its accuracy warrants.
Mark Ransom
The closest `double` approximation of pi is 3.141592653589793 115997963468544185161590576171875. This is accurate to 16 significant digits, but Python prior to 3.1 always had `repr` return 17 significant digits.
dan04
+1  A: 

You could write a little wrapper function:

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

As others have noted, floating-point maths is notoriously inexact. You need some kind of tolerance if you want something to appear as exactly zero.

Peter
You might also need a comparison for near 1.0 as well.
Mark Ransom
What about values that should equal exactly 0.5 etc?
UncleBens
You're never going to get exactly ½√3, so in the end you'll have to admit the limitations of binary floating point.
MSalters
+12  A: 

Let's put it this way, 3.58979e-009 is as close to 0 as your 3.14159265 value is to the real Pi. What you got is, technically, what you asked for. :)

Now, if you only put 9 significant figures (8 decimal places) in, then instruct the output to also display no more, i.e. use:

cout.precision(8);
cout << sin(Pi);

Cheers, V.

vladr
Eh? It's almost exactly the same distance away (as you would expect from Taylor's theorem).
Mike Dinsdale
@Mike, it was just a parable... in the non-mathematical sense. :) OK, in the interest of science it is now correct.
vladr
that's actually what I have right now, but I keep getting -0.00 for certain inputs and the only way I can think of to bypass -0.00 involves using sprintf() and comparing it to "-0.00" and hardcoding in the correct value.
advs89
@Vlad: Darn, now I better find some other nits to pick! :)
Mike Dinsdale
Just tried to build your example in VS2010 and it didn't worked. Still getting the non-approximated result...
Bruno Brant
add this and his works:cout << setiosflags(ios::fixed);
advs89
(other than the -0.0000000 thing)
advs89
actually adding 0.0 fixed my negative zero problem (although the post that suggested me do that mysteriously disappeared)
advs89
+2  A: 

why not force to however many digits you need

 int isin = (int)(sin(val) * 1000);
 cout << (isin/1000.0)
pm100
+1  A: 

sin(PI) should equal 0, for an exact value of PI. You are not entering the exact value of PI. As other people are pointing out, the result you are getting rounded to 7 decimal places is 0, which is pretty good for your approximation.

If you need different behavior you should write your own sine function.

taspeotis
For an exact value of PI and an exact implementation of sin. Binary computers accommodate neither.
Ben Voigt
A: 

If you use float or double in math operations you will never have exact results. The reason is that in a computer everything is stored as a power of 2. This does not translate exactly to our decimal number system. (An example is that there is n o representation in base 2 of 0.1)

In addition float and double are 64 bits at least on some compilers and platforms. (I think - somebody correct me on that if needed). This will cause some rounding errors for either very large values or for very small values (0.0000000000xxx)

In order to get exact results you are going to need some big integer library.

As written in the comments to the question above see the site ... http://docs.sun.com/source/806-3568/ncg_goldberg.html

Romain Hippeau
+4  A: 

Did you try M_PI, available in most <cmath> or <math.h> implementations?

Even so, using floating point in this way will always introduce a certain amount of error.

Mark B
yeah unfortunately cout << sin(M_PI) is still not zero
advs89
@Adam: it's closer, though!
Potatoswatter
well you know what they say: close only counts in horseshoes and decimal approxima... wait a second!
advs89
M_PI is not standard and often not present...
Alexandre C.
+1  A: 

You could throw in some more digits to get a better result (try for example 3.1415926535897932384626433832795029L), but you'll still get rounding errors.

Still, you can create your own sin and cos versions that check against your known Pi value and return exactly zero in those cases.

namespace TrigExt
{
    const double PI = 3.14159265358979323846;

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

You may also expand this thing for the other trigonometric functions and to handle Pi multiples.

Matteo Italia
A: 

You know, just for the mathematical correctness out there: sin(3.14159265) ins't zero. It's approximately zero, which is exactly what the program is telling you. For calculations, this number ought to give you a good result. For displaying, it sucks, so whenever you print a float, make sure to format the number.

I don't really think that there are any float mechanics in the work here... it's just simple math.

About the code though, be careful... doesn't make your code give the wrong result by making the approximations before the display, just display the information the right way.

Bruno Brant
A: 
double cut(double value, double cutoff=1e-7) {
  return (abs(value) > cutoff)*value;
}

this will zero values below threshold, use it like this cut(sin(Pi))

aaa
+2  A: 

This should display zero:

cout << fixed << sin(Pi);

(I don't think you should be trying to round anything. If you are worried about display, deal with the display functions, not with the value itself.)

UncleBens
+1: this is one of the few answers on the page that actually produces the desired output. Only problem is you have to add 0.0 to sin(Pi) in order to avoid getting -0.0 as a result in certain cases. For that reason I prefer the answer that I selected to be the "accepted answer."
advs89