4

In java the output of the following code is 0.0,-0.0,-0.0. what is the reason for these different answers?

System.out.print((0.0 % -1)+","+(-0.0 % 1)+","+ (-0.0 % -1));
Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Sammy
  • 58
  • 7
  • What output are you actually expecting? – Robert Harvey Dec 27 '13 at 16:48
  • I expected 0.0,0.0,0.0 – Sammy Dec 27 '13 at 16:49
  • 2
    So the question is, "Why does Java print a negative sign in front of `0` when `0` without sign is equal and more commonly accepted as correct?" – Reinstate Monica -- notmaynard Dec 27 '13 at 16:51
  • @iamnotmaynard: yes you are correct.. :) – Sammy Dec 27 '13 at 16:52
  • 2
    http://stackoverflow.com/questions/13544342/why-do-floating-points-have-signed-zeros – assylias Dec 27 '13 at 16:54
  • 1
    A very relevant aspect: is this exclusive to Java or do other languages exhibit the same behaviour ? – Radu Murzea Dec 27 '13 at 16:55
  • @RaduMurzea I know that the Ada language also "sort of" distinguishes +0 and -0; they will be equal if you compare them, but there are situations where using +0 and -0 produce different results. Whether formatting for output is one of them, I don't know. The biggest difference is when you use it with two-argument arctangent. The behavior of +0 and -0 is actually an IEEE standard that has nothing to do with the language, and the behavior is often implemented directly in hardware. – ajb Dec 27 '13 at 17:00
  • @RaduMurzea: C# displays it as 0.0 – Robert Harvey Dec 27 '13 at 17:02
  • That may be C#'s implementation of the % operator though. Give C# -0 to print and what does it display? – Tim B Dec 27 '13 at 17:04
  • @TimB: That's what I did. I didn't do the `%` operator. I did `-0.0f` – Robert Harvey Dec 27 '13 at 17:04
  • Correction: An Ada program may or may not distinguish signed zeroes, depending on the implementation, and there's a way a program can tell whether it does or not. The language definition has some parts where the definition depends on whether signed zeros are implemented. Ada is intended to be portable and work on machines that use non-IEEE floats, such as VAX. – ajb Dec 27 '13 at 17:05

4 Answers4

6

The modulo operator just takes the remainder once you divide a number by that.

Divide 0 by -1 and you get 0, so the result is 0.

Floating points and doubles do actually know the difference between -0 and +0 though, so when you take the remainder of a -0 you get -0 as that is still a valid number between 0 and 1 (or -1).

This is a quirk of the way floating point numbers work, and of the special properties of 0 as the same does not hold true for other numbers:

System.out.println((0.0 % -1)+","+(-0.0 % 1)+","+ (-0.0 % -1));

System.out.println((0 % -1)+","+(-0 % 1)+","+ (-0 % -1));

System.out.println((3 % -1)+","+(-3 % 1)+","+ (-3 % -1));

Displays:

0.0,-0.0,-0.0 
0,0,0 
0,0,0

Since references were requested:

Floating points are defined in IEEE_754-1985:

http://en.wikipedia.org/wiki/IEEE_754-1985

There is a whole wikipedia page discussing Negative Zero:

http://en.wikipedia.org/wiki/Negative_zero

This also at least partly explains why the modulo works as:

According to the IEEE 754 standard, negative zero and positive zero should compare as equal with the usual (numerical) comparison operators, like the == operators of C and Java.

Since modulo produces a number >= to 0 and < than the given value then -0 already satisfies the >= requirement (since -0 == 0) and the operation can just end immediately.

Tim B
  • 40,716
  • 16
  • 83
  • 128
  • So, (if I might put on my crystal ball hat here), since `float` actually supports negative zero, the designers of Java decided it was probably less risk to just leave the sign alone, rather than change it? – Robert Harvey Dec 27 '13 at 16:53
  • Can you cite the parts of the spec that describe this behavior (both of floats and of the `%` operator)? – Reinstate Monica -- notmaynard Dec 27 '13 at 16:54
  • 1
    @RobertHarvey I think you can blame the people at IEEE (the people on the 754 committee in fact). – Elliott Frisch Dec 27 '13 at 16:54
  • @ElliottFrisch: No. The Java designers could have decided to display all types of zeros as positive zero if they wanted to. – Robert Harvey Dec 27 '13 at 16:58
  • But there are differences, that become important in some areas. – Tim B Dec 27 '13 at 17:01
  • @TimB : So is this common with all other programming languages? – Sammy Dec 27 '13 at 17:01
  • I've done an edit with some references that will help explain. I can't speak for the designers of Java, but it should give you some more to go from. @Sammy - all programming languages that follow the IEEE specification (which is virtually all of them, and virtually all floating point processors too). The exact behaviour of things like % will depend on how they implement it in that language though. – Tim B Dec 27 '13 at 17:02
  • @RobertHarvey Sure. But then it wouldn't be IEEE-754 compliant. – Elliott Frisch Dec 27 '13 at 17:02
  • @ElliottFrisch: Then that's the answer, isn't it. – Robert Harvey Dec 27 '13 at 17:03
  • @ElliottFrisch I think IEEE-754 defines how arithmetic operations involving signed zeroes are to be performed, but does it say anything at all about what happens when it's formatted to a string? I doubt it (but I could be wrong). So that's an area where languages could go their own way, I think. – ajb Dec 27 '13 at 17:07
1

Because IEEE float has both positive and negative zero values.

Hot Licks
  • 47,103
  • 17
  • 93
  • 151
0

Because float supports negative zero. Changing the sign would cause a loss of information, however meaningless that information might be.

So basically it comes down a display problem, not a data representation; if you want the "correct" rendition, provide a formatting string for your output. This holds true for any sort of scenario where you dislike the default ToString() representation.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
0

The reason is to do with IEEE-754 signed zero rules. Specifically, because a floating point number is not "infinitely" precise and it "simplifies" handling complex numbers.

Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249