what is the best way to avoid negative zero in output?
Asked Answered
C

3

12

As in this question is said, there is some differences between negative and positive zero in floating point numbers. I know it's because of some important reasons. what I want to know is a short code to avoid negative zero in output.

for example in the following code:

cout << fixed << setprecision(3);
cout << (-0.0001) << endl;

"-0.000" is printed. but I want "0.000".

Note all other negative numbers (e.g. -0.001) should still be printed with the minus sign preceding them, so simply * -1 will not work.

Chrono answered 21/9, 2012 at 18:35 Comment(5)
@TonyTheLion what if my number is -0.001? it sould be printed -0.001 and I shouldn't * -1 this.Chrono
AFAIK a minus number multiplied by another minus number yields a positive number. That's basic maths. What's your point?Heimer
You will have to check that your number is not positive before you do the *-1, else you'll get a negative number as output.Heimer
@TonyTheLion I should multiply by -1 only when the result is -0.000. not all negative numbers as you said "You will have to check that your number is not positive before you do the *-1"Chrono
You seem to be talking about two separate things: negative zero, and a negative number small enough that it rounds to zero when printed so some particular precision. Which do you want to prevent?Lorenzo
O
5

Try depending on your precision.

cout << ((abs(ans) < 0.0005)? 0.000: ans) << endl;

Offence answered 21/9, 2012 at 18:51 Comment(8)
it should be: 'cout << (abs(ans) < 0.0005)? 0.000: ans << endl;'Chrono
@wallyk: You can't return different types from a conditional expression in C++.Progenitor
@wallyk it's not needed. becuase setprecision(3) is called before that.Chrono
@nneonneo: Oh, yeah. I have been doing too much javascript and php lately.Forelli
This code does not compile. << has higher precedence than ?:, so it is parsed with ans << endl as a subexpression. This fails to resolve because ans is presumably a floating-point type, and no insert operator (<<) is declared for it with the type of endl.Junkojunkyard
Add parenthisis around the ()?: combination, it should work fine!!Offence
@Eric: it should be parsed as (cout.operator<<(()?:)).operator<<(endl); Why does it behave the way you say it does?!Offence
@Aladdin: << has higher precedence than ?:. In the C++ formal grammar, << is parsed with shift-expression → shift-expression << additive-expression, and ?: is parsed with conditional-expression → logical-or-expression ? expression : assignment-expression. Because of other rules of the grammar, ans << endl can be an assignment-expression, but an unparenthesized …?…:… cannot be a shift-expression. Therefore, the << rule must be used to reduce ans << endl before the ?: expression can be reduced.Junkojunkyard
B
2

How about:

cout << (value == 0.0 ? abs(value) : value)  << endl;
Blankbook answered 21/9, 2012 at 19:18 Comment(4)
There are plenty of resources online explaining why value == 0.0 is a bad idea. docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html is goodLaughton
This answer would be correct (and a good idea) if the questioner really only wanted to catch negative 0. But the body of the question shows that's not the case.Cohbert
@Laughton - what a got from that article was that "the IEEE standard defines comparison so that +0 = -0"...so I'm genuinely interested - can you point me to something that more explicitly explains the problem? Steve Jessop - it looks to me like the body of the question asked specifically about negative 0 only. Did I miss something?Blankbook
Yes, the body of the question says that the questioner wants "0.000" to be printed instead of "-0.000" for the value -0.0001. So it's not just negative zero that needs to be treated specially, -0.0001 does too. Basically, the questioner is referring to any output of "-0.000" from cout as "negative zero", they don't just mean an IEEE negative zero in value.Cohbert
W
2

If you care about arbitrary precision, as opposed to just a fixed one at 3, you'll need a small bit of work. Basically, you'll have to do a pre-check before the cout to see if the number will get formatted in a way you don't like.

You need to find the order of magnitude of the number to see if it the imprecise digits will be lost, leaving only the sign bit.

You can do this using the base 10 logarithm of the absolute value of the number. If negative of result is greater than the precision you have set, the number will show in a way you don't want.

log10 of 0.0001 is -4.

negative of (-4) is 4.

4 > 3 (the arbitrary precision) Thus the value will show up unhappily.

In very bad pseudocode:

float iHateNegativeZeros(float theFloat, int precision)
{
   if((theFloat < 0.0f) &&
      (-log10(abs(theFloat)) > precision))
   {
     return -theFloat;
   }
   else
   {  
     return theFloat;
   }
}
Whereon answered 21/9, 2012 at 20:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.