-3

While I was having fun with codes from Java Puzzlers(I don't have the book) I came across this piece of code

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }

Output is

0.8999999999999999

When I tried changing the code to

2.00d - 1.10d still I get the same output as 0.8999999999999999

For,2.00d - 1.10f Output is 0.8999999761581421
For,2.00f - 1.10d Output is 0.8999999999999999
For,2.00f - 1.10f Output is 0.9

Why din't I get the output as 0.9 in the first place? I could not make any heads or tails out of this? Can somebody articulate this?

Mureinik
  • 297,002
  • 52
  • 306
  • 350
prasanth
  • 3,502
  • 4
  • 28
  • 42

3 Answers3

6

Because in Java double values are IEEE floating point numbers.

The work around could be to use Big Decimal class

Immutable, arbitrary-precision signed decimal numbers. A BigDecimal consists of an arbitrary precision integer unscaled value and a 32-bit integer scale. If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale. The value of the number represented by the BigDecimal is therefore (unscaledValue × 10^-scale).

On a side note you may also want to check Wikipedia article on IEEE 754 how floating point numbers are stored on most systems.

The more operations you do on a floating point number, the more significant rounding errors can become.

Rahul Tripathi
  • 168,305
  • 31
  • 280
  • 331
  • BigDecimal is not a catch-all solution. It does not provide correct answers for calculating monthly interest given an annual percentage rate, for converting currencies, or for calculating the unit price in a three-for-one-price deal. – Eric Postpischil Sep 29 '13 at 14:03
  • @EricPostpischil:- Yes I know what you want to say. I have just tried to make OP realise that there are some workaround for this. And that is the reason I have written **"the work around could be"** I have read an interesting article: https://blogs.oracle.com/CoreJavaTechTips/entry/the_need_for_bigdecimal – Rahul Tripathi Sep 29 '13 at 14:06
5

In binary 0.1 is 0.00011001100110011001100110011001.....,

As such it cannot be represented exactly in binary. Depending where you round off (float or double) you get different answers.

So 0.1f =0.000110011001100110011001100 And 0.1d=0.0001100110011001100110011001100110011001100110011001

You note that the number repeats on a 1100 cycle. However the float and double precision split it at a different point in the cycle. As such on one the error rounds up and the other rounds down; leading to the difference.

But most importantly; Never assume floating point numbers are exact

Richard Tingle
  • 16,906
  • 5
  • 52
  • 77
  • 2
    “Never trust floating point numbers to be precise” is bad advice. Proper advice is to understanding floating-point arithmetic and use it with proper caution and design. Floating-point arithmetic is well-specified by the IEEE 754 standard and can be used for accurate computation when done with proper knowledge and care. – Eric Postpischil Sep 29 '13 at 14:02
  • @Eric I would like to see one (non contrived) example of where assuming floating point numbers are exact is wise? – Richard Tingle Sep 29 '13 at 14:05
  • @Eric and while "read the docs" is always good advice it is almost never followed. – Richard Tingle Sep 29 '13 at 14:08
  • In e.g. the function at http://proval.lri.fr/gallery/Dekker.en.html , many operations are exact, all of them are “precise” for a certain definition of precise, and they should all wisely be assumed to be respectively exact and precise for the algorithm to work. – Pascal Cuoq Sep 29 '13 at 14:28
  • @Pascal ive edited my answer since erics comments but I stand behind "Never **assume** floating point numbers are **exact** – Richard Tingle Sep 29 '13 at 14:34
  • The edited text is better, but what do you suggest a person use if they want exact arithmetic? If there are 1.34 dollars to the euro, what computer arithmetic should I use to calculate **exactly** how many euros there are to the dollar? – Eric Postpischil Sep 29 '13 at 15:29
  • @EricPostpischil Thats already been attempted to be answered in other answers (and I would feel bad stealing it), you mentioned problems with BigDecimal so I would be very interested to see an answer overcoming those problems – Richard Tingle Sep 29 '13 at 15:34
  • The problem with stating that floating-point is not exact is that it drives people to other numerical arithmetic system (BigDecial, integer,…) with the impression that they are exact. That is not the impression we ought to give. Every practical arithmetic system is inexact, even for common operations. (Often integer arithmetic is recommend as “exact”, but integer `5/3*3` does not produce 5.) The advice we should give is to understand your numerical needs, choose an arithmetic system that matches those needs, understand the system, and use it carefully, with an awareness of its limits. – Eric Postpischil Sep 29 '13 at 17:58
2

Other answers are correct, just to point to a valid reference, I quote oracle doc:

double: The double data type is a double-precision 64-bit IEEE 754 floating point. Its range of values is beyond the scope of this discussion, but is specified in the Floating-Point Types, Formats, and Values section of the Java Language Specification. For decimal values, this data type is generally the default choice. As mentioned above, this data type should never be used for precise values, such as currency

atoMerz
  • 7,534
  • 16
  • 61
  • 101
  • The Oracle document you quote is incorrect. Floating-point arithmetic is well-specified by the IEEE 754 standard and can be used for accurate computation when done with proper knowledge and care. – Eric Postpischil Sep 29 '13 at 14:04
  • Care to elaborate on the term `with proper and care`? – atoMerz Sep 30 '13 at 18:14
  • Read the IEEE 754 standard and texts such as [Handbook of Floating-Point Arithmetic](http://www.amazon.com/Handbook-Floating-Point-Arithmetic-Jean-Michel-Muller/dp/081764704X/ref=sr_1_1?ie=UTF8&qid=1380565932&sr=8-1&keywords=muller+floating-point+arithmetic), and/or take a numerical analysis course. When writing software, use this knowledge either to evaluate bounds on the errors that may occur and/or to understand how to avoid problems caused by those errors (e.g., write software that tolerates them or even that uses them to advantage). – Eric Postpischil Sep 30 '13 at 18:35
  • Then it is inaccurate, you just claim that the programmer can handle the burden. – atoMerz Oct 01 '13 at 12:18
  • Programmers should not write software beyond their abilities if it is intended for any important use. – Eric Postpischil Oct 01 '13 at 13:18