1

This question is for standards gurus.

What does a typical C++ compiler do that Java doesn't or vice-versa when interpreting floating point values.

Now I know the basics of how floating point numbers are stored. I know that the computer cannot exactly represent those numbers that are not a power of 2.

However, it occurred to me that C++ somehow manages to correct for that.For example the expression 0.15 + 0.15 yields 0.3 when compiled in C++ (gcc) as opposed to 0.30000000000000004 in Java So my question is two-fold:

  1. If the number is actually represented internally as 0.30000000000000004, what does a C++ compiler do to correct for it? Does it simply reduce the precision? Does the correction happen only when the number is evaluated? Is there an overhead? Or is it actually stored as 0.3 somehow?

  2. What was the rationale behind the design decision that makes Java not correct for it. This makes using floating point primitives a real pain in Java (Yes I am aware of BigDecimal etc.)? Is it faster this way? Is it more correct?

If there is a benefit behind the Java-way of doing things I would be glad to hear it.

I really would like to hear both sides in this. This is for programming language design research.

MadOgre
  • 501
  • 6
  • 15
  • 1
    I think your assumptions about C++ are wrong. You are just printing out a rounded version of the number. Play around with `std::setprecision` and see. – juanchopanza Oct 07 '14 at 08:35
  • `System.out.println(0.15 + 0.15)` prints `0.3` in Java. You are mixing concepts: 0.3 can't be represented exactly as a floating point number but you can truncate the string representation to 1 decimal place to make it look as if it were. Java follows the [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point) standard and you have the option to do the same in C++. – assylias Oct 07 '14 at 08:37
  • You should also mention what precesion you talk about? float or double? – user2504380 Oct 07 '14 at 08:38
  • @juanchopanza Yes I figured that, but what logic does it use for the default rounding algorithm. Clearly Java and C++ differ on that. I am trying to figure out what the exact differences are – MadOgre Oct 07 '14 at 08:39
  • @MadOgre Java is as precise as C++, when it comes to floating point precision it's all about math! and the math used is the same! – Alboz Oct 07 '14 at 08:39
  • @MadOgre But this isn't to do with how the compiler treats the numbers, but with how some functions print them out by default. – juanchopanza Oct 07 '14 at 08:40
  • @juanchopanza In that case I suppose the question should be: What does cout<< do differently by default than System.out.println when in comes to doubles? – MadOgre Oct 07 '14 at 08:42
  • 1
    @MadOgre as assylias told you: System.out.println(0.15 + 0.15) prints 0.3 in Java. – Alboz Oct 07 '14 at 08:45
  • @Alboz Yes you are right it does. But here is a snippet that doesn't for (double d = 0.1; d <= 0.5; d += 0.1) System.out.println(d); This is what confuses me – MadOgre Oct 07 '14 at 08:52
  • Related, for the [display precision](http://stackoverflow.com/q/26092469/3747990) – Niall Oct 07 '14 at 08:55
  • @MadOgre http://stackoverflow.com/questions/4937402/moving-decimal-places-over-in-a-double – assylias Oct 07 '14 at 08:55
  • 1
    C and C++ - if not given a full precision - often beautify the number representation. A practicality. – Joop Eggen Oct 07 '14 at 08:59
  • @JoopEggen yes they do! That's what I was talking about. The question is how. How does it know to convert 3.54300000003 into 3.543? Is there an algorithm that says "if there are more than x zeros don't print the rest of the number?" – MadOgre Oct 07 '14 at 09:02
  • 1
    @MadOgre I never did see a specification of that behaviour, but yes, something like leave out the last digit. A `printf("%.20f", x);` should proof interesting. C probably might use a fixed precision whereas java relentlessly gives the highest precision. – Joop Eggen Oct 07 '14 at 09:41

1 Answers1

4

There are actually some differences in the usage of floating point values in Java.

But not what you observed: 0.15+0.15 is not 0.3 in both languages (since 0.15 is not 0.15 either).

In general the differences are not located in the compiler, but in the way the runtime computations are done.

In C++ it is obviously all platform dependent. And with respect to the compiler options some floating point units of the processor are used and so on...

In Java there are two modes that can be used for floating point computations.

The first is the default mode, that allows the JVM (since 1.2) to make use of a higher precision during computations. So if you add two float values (32 bit) for example, the intermediate results may be stored with 60 bit precision - but this is highly platform depended! That can make some differences.

To avoid that, you can use the strictfp keyword on classes, interfaces and non-abstract methods. Then all intermediate results are truncated to the precision of the type you use (32 bit for float and 64 bit for double).

If there is a benefit behind the Java-way of doing things I would be glad to hear it.

The default way has no benefits and is often criticised. The usage of the strictfp keyword might have some benefits regarding to portability.

Niall
  • 30,036
  • 10
  • 99
  • 142
UniversE
  • 2,419
  • 17
  • 24
  • I yearn for the day when computers are fast enough and we can afford to take a performance hit and simply use base 10 to represent floating points exactly (like BigDecimal in Java or decimal in C#) Floating point arithmetic is way more pain than it should be. – MadOgre Oct 07 '14 at 09:06
  • @MadOgre "use base 10 to represent floating points exactly" many numbers are impossible to represent exactly in base 10. For example BigDecimal is unable to represent exact value of 1/3. – reducing activity Nov 28 '18 at 10:37
  • Necro comment! I should point out that BigDecimal is only one format of base 10. It's technically still possible to represent 1/3 in base 10 by writing it as 1/3, you're just writing it as a fraction instead of a decimal. I don't think it would be too much of a pain to write a simple class that has a numerator and a denominator stored separately, much like BigDecimal stores the raw value and a scale separately. – Nach0z Sep 27 '19 at 17:14