80

Is it possible to check if a float is a positive zero (0.0) or a negative zero (-0.0)?

I've converted the float to a String and checked if the first char is a '-', but are there any other ways?

e4lime
  • 960
  • 1
  • 6
  • 11
  • 8
    Checking the sign bit (leftmost bit) should be enough – boxed__l Mar 14 '14 at 15:23
  • 6
    Indeed zero is neither negative nor a positive number. – Grijesh Chauhan Mar 14 '14 at 18:24
  • 22
    @GrijeshChauhan: Only theoretically – Mooing Duck Mar 14 '14 at 18:33
  • 10
    @fridge: but the question isn't about mathematics, it's about Java. Any relation that floating-point values might bear to numbers is by human design and liable to leaky abstractions ;-) – Steve Jessop Mar 15 '14 at 15:10
  • It's a long time since i was in school but it is to with the representation of real numbers in binary and pivots around the use of 1's complement and 2's compliment method of handling numbers in the machine. In 1's complement the -0 occurs in 2's it is avoided. If you have an HP16c calculator you can switch it to 1's complement and then start subtracting 1's from a number and watch it roll to 1, 0, -0, -1, ... Most disconcerting. But in reality it is just a trick of the light. However makes me wonder even more about Java. – PurplePilot Mar 18 '14 at 20:06
  • @PurplePilot it's nothing specific to Java. It's an [IEEE 754 single-precision floating point number](http://en.wikipedia.org/wiki/Single_precision). This question could be asked in C/C++/C#/Python/PHP/Javascript... pretty much any language uses the hardware to do floating point math, and stores floating point numbers in the format the hardware expects – Kip Mar 21 '14 at 03:19
  • 3
    May be a stupid question, but I was just wondering: Why does one need to differentiate between a positive an a negative 0? – siegi Mar 29 '14 at 22:13

8 Answers8

81

Yes, divide by it. 1 / +0.0f is +Infinity, but 1 / -0.0f is -Infinity. It's easy to find out which one it is with a simple comparison, so you get:

if (1 / x > 0)
    // +0 here
else
    // -0 here

(this assumes that x can only be one of the two zeroes)

harold
  • 61,398
  • 6
  • 86
  • 164
  • 6
    Wouldn't it be easier to transfer the sign of the zero to a different number, say 1.0, with Math.copySign? E.g. `if (math.copySign (1.0, x) < 0.0) ...` – njuffa Mar 14 '14 at 17:39
  • 3
    @njuffa: Not sure how `math.copySign(1.0,x)<0.0` is "easier" than `1/x>0`. I mean both are quite un-self-explanatory, so you want to have a function for that anyway – Niklas B. Mar 14 '14 at 20:06
  • @Niklas B.: Sorry, I should have expressed myself more clearly. "more efficient" is what I meant. Floating-point division tends to be a heavy-weight operation, while sign transfer should be light weight. I would agree with your thoughts on wrapping for maintainability, but I assumed Klockrent is interested mostly in basic techniques. – njuffa Mar 14 '14 at 21:36
  • 2
    @njuffa: Yes, I thought you readability issues with this answer ;) I didn't consider division would be heavy, since there is probably a special case for zero divisors anyway – Niklas B. Mar 14 '14 at 21:39
  • 1
    Well if you guys want to get into how heavy it is then.. it depends. For example, a sign transfer is annoying to do with x87 instructions, but great with SSE. And for how long division takes, that ranges from 9 (I think?) to over a hundred cycles (depending on the values being divided and the µarch). Either one could win, and that's just on x86 systems. – harold Mar 14 '14 at 21:43
  • 1
    If you just want efficiency, wouldn't converting it to an int and interrogating the sign bit be the best solution? I'm not sure how efficiently you can do that in Java, but on most architectures, that can be done simply with an OR instruction followed by a jump zero or jump not zero instruction and the OR is usually single-cycle. The conditional jump cost varies a lot by architecture, though. – reirab Mar 15 '14 at 05:10
  • What about when the language prevents you from dividing by zero? – Aaron Franke Dec 23 '21 at 05:30
  • @AaronFranke then a new question should be asked for that language, this one is for Java – harold Dec 23 '21 at 11:29
41

You can use Float.floatToIntBits to convert it to an int and look at the bit pattern:

float f = -0.0f;

if (Float.floatToIntBits(f) == 0x80000000) {
    System.out.println("Negative zero");
}
Jesper
  • 202,709
  • 46
  • 318
  • 350
  • Much better than dividing, which can take several clock cycles and may trap an overflow condition in the FPU unit. Better yet: `(Float.floatToIntBits(f) & 0x80000000) < 0` – Mark Jeronimus Sep 06 '18 at 09:59
12

Definitly not the best aproach. Checkout the function

Float.floatToRawIntBits(f);

Doku:

/**
 * Returns a representation of the specified floating-point value
 * according to the IEEE 754 floating-point "single format" bit
 * layout, preserving Not-a-Number (NaN) values.
 *
 * <p>Bit 31 (the bit that is selected by the mask
 * {@code 0x80000000}) represents the sign of the floating-point
 * number.
 ...
 public static native int floatToRawIntBits(float value);
12

Double.equals distinguishes ±0.0 in Java. (There's also Float.equals.)

I'm a bit surprised no-one has mentioned these, as they seem to me clearer than any method given so far!

Reuben Thomas
  • 647
  • 6
  • 13
9

The approach used by Math.min is similar to what Jesper proposes but a little clearer:

private static int negativeZeroFloatBits = Float.floatToRawIntBits(-0.0f);

float f = -0.0f;
boolean isNegativeZero = (Float.floatToRawIntBits(f) == negativeZeroFloatBits);
assylias
  • 321,522
  • 82
  • 660
  • 783
8

When a float is negative (including -0.0 and -inf), it uses the same sign bit as a negative int. This means you can compare the integer representation to 0, eliminating the need to know or compute the integer representation of -0.0:

if(f == 0.0) {
  if(Float.floatToIntBits(f) < 0) {
    //negative zero
  } else {
    //positive zero
  }
}

That has an extra branch over the accepted answer, but I think it's more readable without a hex constant.

If your goal is just to treat -0 as a negative number, you could leave out the outer if statement:

if(Float.floatToIntBits(f) < 0) {
  //any negative float, including -0.0 and -inf
} else {
  //any non-negative float, including +0.0, +inf, and NaN
}
Kip
  • 107,154
  • 87
  • 232
  • 265
1

For negative:

new Double(-0.0).equals(new Double(value));

For positive:

new Double(0.0).equals(new Double(value));
Tridib
  • 61
  • 1
  • 5
1

Just use Double.compare (d1,d2).

double d1 = -0.0;    // or d1 = 0.0

if ( Double.compare (d1, 0.0)  < 0 )
    System.out.println("negative zero");
else
    System.out.println("positive zero");
Humpity
  • 152
  • 1
  • 9