10

I was always assuming that the following test will always succeed for finite values (no INF, no NAN) of somefloat:

assert(somefloat*0.0==0.0);

In Multiply by 0 optimization it was stated that double a=0.0 and double a=-0.0 are not strictly speaking the same thing.

So I was wondering whether this can lead to problems on some platforms e.g. can the result of the above test depend on a beeing positive or negative.

Community
  • 1
  • 1
Martin
  • 4,738
  • 4
  • 28
  • 57
  • 1
    The C++ standard requires that `+0.0` and `-0.0` have the same behavior. The answer suggesting otherwise in the thread you quote is wrong, at least for C and C++. – James Kanze Dec 20 '12 at 12:34
  • On my computer which my compiler everything is fine, on another embedded target as well, but ... I just want no later surprises – Martin Dec 20 '12 at 12:35
  • 1
    This isn't a float operation, it is a double operation. – Lundin Dec 20 '12 at 12:39
  • 3
    @James: the standard says that positive and negative zeros compare equal, that's not the same thing as saying they have the same behavior in *all* circumstances. Isn't `atan2` permitted (but not required) to return a value for `atan2(ZERO,ZERO)` that is distinct from the vale of `atan2(NEGATIVE_ZERO,NEGATIVE_ZERO)`? So the validity of that optimization in the other question isn't just a matter of whether the two possible results are equal. But I think what you wrote is correct, since IIRC in C and C++ the expression `-0.0` doesn't evaluate to a negative zero. – Steve Jessop Dec 20 '12 at 12:41
  • @Lundin: You are right, the title was misleading and should not mention float. Just changed it. I do not want to specify whether somefloat is float or double – Martin Dec 20 '12 at 12:46
  • @SteveJessop `atan2` has undefined behavior if the second argument is `0`. And of course, if the program has undefined behavior, then the standard makes _no_ requirements on it. – James Kanze Dec 20 '12 at 13:04
  • While this code may work, for the sake of the people who will maintain it after you, I would change the code to count on less obscure parts of the language. – brian beuning Dec 20 '12 at 13:14
  • @brianbeuning: The assert was only an example. Let me give you the real usage: You use a particle filter and weight the particles in one step. Duiring filtering the weight of a particle is reduced by multiplication with a gridtile weight. The weight of illegal tiles is 0.0. Later you want to sort out particles with zero weight (NOT almost 0). Is this obscure ? – Martin Dec 20 '12 at 13:20
  • @Martin I thought the == 0.0 was for the sake of theory in this discussion? You probably know this already, but in a real application you shouldn't use equality operators to check for a certain float number, you need to check [within a specified interval](http://stackoverflow.com/questions/17333/most-effective-way-for-float-and-double-comparison). – Lundin Dec 20 '12 at 13:30
  • @Martin I am not a 3D GUI developer, but that makes some sense to me. How about a nice big comment in the source code? – brian beuning Dec 20 '12 at 13:34
  • @Lundin: In this very case I want to test for 0.0 since I disable a particle by multiplying with 0.0. All others should pass the test, hence this is exactly what I want. The number I test against in this scenario is always 0.0. Of course for other values such tests are fruitless and dangerous indeed. And yes I would not do sth. like this if it is not the most performance critical part of the whole filter (several 100k particles are possible filter frequency is quite high) – Martin Dec 20 '12 at 13:51
  • 1
    @James: it's not UB, "it's a domain error" when both arguments are zero. A domain error means an implementation-defined value is returned (potentially). So for implementations that respect negative zeros and define that value to depend on the signs of the inputs, they can't just discard the sign of a zero willy-nilly in optimization because someone might later use it in `atan2`. The assert in this question is another matter, of course. – Steve Jessop Dec 20 '12 at 20:05
  • @Martin Have you considered the other side of the issue? There are pairs of non-zero numbers whose produce is 0.0 or -0.0. At least one of the numbers has to be small, so the case may not happen in your program. – Patricia Shanahan Dec 20 '12 at 21:28
  • @SteveJessop I'd missed the domain error. The function is defined to return the `arctan(y/x)`, and division by zero is undefined behavior; there's also a rule that if an argument has an invalid value, behavior is undefined. So if `x` is zero, the behavior is undefined unless `y` is also zero? (But I see that there is special wording for ``, which presumably overrides the generic "invalid argument is undefined behavior" which rules in the rest of the library.) – James Kanze Dec 21 '12 at 09:03
  • @PatriciaShanahan: This is ok for me, very small particles get sorted out anyway but the notion of what is very small varies since the sum of all particle weights sums up to 1. For the record: A good source on comparing small numbers and the woes of floating points can be found here: http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ – Martin Dec 21 '12 at 09:03
  • @Lundin There are a number of cases in real applications where it is appropriate to compare floating point values for equality, and tests for near equality aren't necessarily correct either. If you're using floating point, you have to know what you're doing, and do what is appropriate. – James Kanze Dec 21 '12 at 09:09
  • @JamesKanze: 1.0/+0.0 is positive infinity. 1.0/-0.0 is negative infinity. These are not equal. So +0.0 and -0.0 do not "have the same behaviour." – tmyklebu Jan 04 '13 at 08:30

3 Answers3

9

If your implementation uses IEEE 754 arithmetic (which most do), then positive and negative zero will compare equal. Since the left-hand side of your expression can only be either positive or negative zero for finite a, the assertion will always be true.

If it uses some other kind of arithmetic, then only the implementor, and hopefully the implementation-specific documentation, can tell you. Arguably (see comments) the wording of the standard can be taken to imply that they must compare equal in any case, and certainly no sane implementation would do otherwise.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • The documentation isn't implementation-specific; the C++ standard requires that positive and negative zero compare equal. (For that matter, I can't conceive of an implementation where they wouldn't compare equal. It would be unusable.) – James Kanze Dec 20 '12 at 12:38
  • @James Do you have a reference from the standard? – Andreas Brinck Dec 20 '12 at 12:41
  • @JamesKanze: I agree that it would be unusable otherwise, but I can't find where the standard requires it. Do you have a reference? – Mike Seymour Dec 20 '12 at 12:43
  • @Mike Seymour Depending on how one interprets it 5.3.1/7 might be it. "The operand of the unary - operator shall have arithmetic or enumeration type and the result is the *negation of its operand*" The negation of zero is zero. – Andreas Brinck Dec 20 '12 at 12:48
  • Just out of interest: Is this also guaranteed for different floating point types e.g. float a =0.0; double b = -a*0.0; assert(a==b); ? – Martin Dec 20 '12 at 12:56
  • 2
    @MikeSeymour It's in the basic definition of the operators: "Each of the operators shall yield `true` if the specified relationship is true and `false` if it is false." Unless you're using a very special math, `-0.0` is equal to `0.0`, so `-0.0 == 0.0` must return `true`. One could also deduce it from §5.2.4.2.2/1 in the C standard. But I agree that it could be clearer. – James Kanze Dec 20 '12 at 12:59
  • 1
    @Martin I think so, but you'd probably have to go to §5.2.4.2.2/1 in the C standard to prove it (which is included as part of the C++ standard in §18.2.2---not exactly where you'd go first to look for this sort of thing). – James Kanze Dec 20 '12 at 13:01
3

-0.0 == 0.0 according to double comparison rules.

For non-finite values (+-Inf, Nan) somefloat*0.0 != 0.0.

Aki Suihkonen
  • 19,144
  • 1
  • 36
  • 57
  • 1
    `NaN` as finite value is a bit weird. The OP asks about finite value. – nhahtdh Dec 20 '12 at 12:35
  • Just refined it. NAN will not occur in my specific scenario – Martin Dec 20 '12 at 12:37
  • What do you mean by "for non-finite values (+-Inf, Nan) somefloat*0.0 != 0.0." ? This looks a little confusing or is it just the formatting – Martin Dec 20 '12 at 12:42
  • @Martin: I expect the intended meaning is “If somefloat is +infinity, -infinity, or a NaN, then `somefloat*0. != 0.` evaluates to `true`.” – Eric Postpischil Dec 20 '12 at 14:52
1

Your assert can never fail, as long as somefloat is not infinity or NaN. On systems which don't support infinity or NaN, the compiler can simply optimize it out.

James Kanze
  • 150,581
  • 18
  • 184
  • 329