0

Why does this code print 2.4099999999999997, instead of just 2.41

public class Main
{
    public static void main(String args[])
    {
        double d = 5.55%3.14;
        System.out.println(d);
    }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
AbhinavChoudhury
  • 1,167
  • 1
  • 18
  • 38
  • 5
    [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html). – Pshemo Feb 22 '13 at 18:49
  • 2
    why are you guys all downvoting this, you need a deep understandig of floating point arithmetics to understand this.. – El Hocko Feb 22 '13 at 18:51
  • 3
    There's nothing very deep in "float/double represents real numbers in a few bytes and they have to do approximations to do so.". That's basic computer science. – Cyrille Ka Feb 22 '13 at 18:54
  • @CyrilleKarmann ok.. knowing that is very easy, understanding that is quite harder.. but it's quiet hard to fully understand the article Pshemo posted... – El Hocko Feb 22 '13 at 18:57
  • I agree that the linked article is quite hard to digest for a beginner. – Cyrille Ka Feb 22 '13 at 19:04
  • The problem is that your CompSci 101 instructor failed, in the second or third day of class, to explain the representation of numbers (not just floating point), and the implications thereof. (Or perhaps you slept through that class?) – Hot Licks Feb 22 '13 at 19:13
  • (And it should be pointed out that 3.14 is a lousy approximation of pi.) – Hot Licks Feb 22 '13 at 19:15
  • @cIph3r Don't worry if you don't understand the article. It's one of those "often linked, rarely read"-kind of things. – phant0m Mar 04 '13 at 10:30

4 Answers4

3

The problem is not the modulo operator, but rather the nature of floating point numbers. A double cannot hold the precise value of either 5.55, 3.14 or 2.41, so you get an approximate answer.

To understand this better, try to write down the value of 1/3 as a decimal, when you only have limited space on the paper to write it. You'll end up with something like 0.33333, which is an approximation of the actual value. The same happens to 5.55 when you write it in binary - it turns into 101.10001100110011001100110011... which gets cut off somewhere to fit the space of the double.

Medo42
  • 3,821
  • 1
  • 21
  • 37
2
import java.text.DecimalFormat;

double d = 5.55%3.14;       
DecimalFormat df = new DecimalFormat("#.##");
System.out.println( df.format( d ));

Add DecimalFormat

Edit:

You can also

    double d = 5.55%3.14;
    System.out.printf("%1$.2f", d);
  • 1
    well, actually this does not really solve the problem, the decimal formatter just rounds the inaccuracy away... `DecimalFormat df = new DecimalFormat("##.###################");` will show you.. – El Hocko Feb 22 '13 at 19:03
  • To be fair, under many circumstances this is a completely acceptable solution. – Medo42 Feb 22 '13 at 19:08
1

Java double can have precision issues.

Why don't you try BigDecimal ?

vikingsteve
  • 38,481
  • 23
  • 112
  • 156
  • 8
    "Precision issues" makes it sound like a bug; it's not an issue, it's a floating point. – LittleBobbyTables - Au Revoir Feb 22 '13 at 18:51
  • And BigDecimal does not solve this: `import java.math.BigDecimal; public class Main { public static void main(String[] args) { final BigDecimal d = new BigDecimal(5.55); final BigDecimal APPROXPI = new BigDecimal(3.14); System.out.println(d.remainder(APPROXPI)); //2.409999999999999698019337301957421004772186279296875 } }` – El Hocko Feb 22 '13 at 19:12
  • 1
    @cIph3r actually BigDecimal solves it, but we need to use String representation of numbers in constructor arguments like `BigDecimal("5.55")` and `BigDecimal("3.14")` to get precise values. Take a look at [this explanation](http://www.youtube.com/watch?feature=player_detailpage&v=wbp-3BJWsU8#t=373s). – Pshemo Feb 22 '13 at 20:36
  • @Pshemo nice, this works: `import java.math.BigDecimal; public class Main { public static void main(String[] args) { final BigDecimal d = new BigDecimal("5.55"); final BigDecimal APPROXPI = new BigDecimal("3.14"); System.out.println(d.remainder(APPROXPI)); } }` And it absolutely makes sense – El Hocko Feb 22 '13 at 21:12
1

the reason is that java doesn't do math the way we do. java uses binary numbers (from chapter 4 of Horstmann's big java book) so to a computer, 435 = 4 * 10^2 + 3 * 10^1 + 5 * 10^0

it does this because binary numbers (1 or 0) are easier to manipulate since switches in the computer are either on or off (1 or 0).

this results in occassional rounding issues. if you want to force it to round, then do things like use a decimal format, or if you just need the displayed value rounded you can use String.format or printf

Jeff Hawthorne
  • 568
  • 2
  • 12