Problem with signed (negative) zeros of type double

My program is converting polar coordinates to cartesian coordinates. I am having trouble getting rid of the minus sign in the -0.000 that are displayed. I tried googling and found common solutions that goes like this:

1
2
3
double res = value;
    if (res == 0.0) res = 0.0;
    return res;


I have also tried determining the equality using epsilon but it remains the same:

1
2
3
4
bool equal(double a, double b) 
{
    return std::fabs(a - b) < std::numeric_limits<double>::epsilon();
}



Here's my code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <cmath>
#include <iomanip>
#include <limits>

#define PI 3.14159265

using namespace std;

int main()
{
	int cases;
	cin >> cases;
	while (cases--)
	{
		float r, theta;
		cin >> r >> theta;
		
		float x = r * cos(theta * PI / 180);
		float y = r * sin(theta * PI / 180);
		
		if (x == 0.0) 
			x = 0.0;
		if (y == 0.0) 
			y = 0.0;
		
		cout << fixed << setprecision(3) << x << " " << fixed << setprecision(3) << y << endl;
	}
	return 0;
}


BTW, I don't know if this has an effect but displaying results in 3 decimal places is required.

Here's the sample input:
4
0 0
30 0
30 270
10 45


And the corresponding output:
0.000 0.000
30.000 0.000
-0.000 -30.000
7.071 7.071


The problem is in the 3rd line of input.

How will I get rid of that minus sign? Any suggestions?
Firstly, I would always doubles instead of floats, this will not solve the problem, but will help with any precision problems.

With this part:
if (x == 0.0)

will almost certainly be false.

The use of epsilon is a much better idea, although you should scale the epsilon up to the values you are using, because the epsilon is the 'distance' to the next representable number from 1.0. So if r == 30.0, multiply epsilon by 30.0.

Why does it matter that you have a -0.0?

HTH
I am submitting this to an online judge. This is only for displaying purposes, otherwise, it will be judged wrong. BTW, how do I set the scale of an epsilon, considering the equal function I posted above?
Last edited on
galiwocky wrote:
BTW, I don't know if this has an effect but displaying results in 3 decimal places is required.

Well, it has the effect of hiding the cause.

If we use this code,
1
2
3
    cout.precision(8);
    cout << fixed << right << setw(12) << x << " " 
      << fixed << right << setw(12) << y << endl;

then this is the output:
  0.00000000   0.00000000
 30.00000000   0.00000000
 -0.00000016 -30.00000000
  7.07106781   7.07106781

If we use a more accurate value for PI, the results change slightly, but there's still a problem. const float PI = 3.1415926535897932385;
  0.00000000   0.00000000
 30.00000000   0.00000000
  0.00000036 -30.00000000
  7.07106781   7.07106781

One thing you could do is a test something like this:
1
2
3
4
5
6
    const float limit = 0.000001;

    if (fabs(x) < limit)
        x = 0.0;
    if (fabs(y) < limit)
        y = 0.0;

Actually, I'd recommend using type double rather than float, throughout the entire program. In that case, something like const double limit = 1E-14; might be about right.

If you really are interested only in three decimal places, you could probably use a much less stringent value for limit.
Last edited on
Thanks a lot Chervil! Finally got it right. :)
galiwocky wrote:
how do I set the scale of an epsilon, considering the equal function I posted above?


Just multiply the number you are dealing with by the epsilon:

1
2
double r= 30.0;
REpsilon = r * std::numeric_limits<double>::epsilon()


HTH
And if the number you are dealing with is zero....?
And if the number you are dealing with is zero....?


There are two situations - input values and output values.

For an input value that is to be used in a calculation, there is no need to compare with epsilon, because you can do that with the result of the calculation. This is the case with the OP's problem.

If an input value is to be checked before use, as in divide by zero, or it is an output value, then the following should work:

If the value is between 1.0 and -1.0 then use epsilon, otherwise multiply the value by epsilon.

The thing to remember is the 'distance' between representable numbers.

Of course you can use an arbitrary precision value like you have done, which is perfectly fine for a lot of things, but might not work quite as well as expected in some situations.

For example, I was writing some code to deal with degrees, minutes and seconds of arc. I had to be careful with the exact value of the seconds to avoid problems with rounding up. Having 60 seconds is invalid, and requires settings seconds to zero and incrementing the minutes. So I needed 59.5 seconds or more to initiate the rounding up, while 59.4 or less does not. Using an arbitrary precision of 0.1 seconds, didn't always work, so I found myself having to use an epsilon value as well, so it would work in every situation.

Any way that is my understanding of it all.
Topic archived. No new replies allowed.