0

I have a double var

public double votes(){
    double votexp = 0;

      for(Elettore e:docenti.values()){
        if(e.getVoto()==true)          //everytime this is true increment by 1
        {
            votexp+=1.0;
        }   
    }
    for(Elettore e:studenti.values()){
        if(e.getVoto()==true)         //everytime this is true increment by 0.2
        {
            votexp+=0.2;
        }
    }
    for(Elettore e:pta.values()){
        if(e.getVoto()==true)        //everytime this is true increment by 0.2
        {
            votexp+=0.2;
        }
    }
    return votexp;
}

In my case the variable shoud be incremented to 2.6 but votexp returns 2.6000000000000005 how can i fix this by using the same double var and return a double precision number ?

Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287
Lucian Enache
  • 2,510
  • 5
  • 34
  • 59
  • 5
    exact duplicate of _so_ many questions about floating point precision. TL;DR version - you can't represent 2.6 exactly in IEEE754 floating point format. – Alnitak Feb 23 '12 at 13:24
  • 1
    Similar question: [Floating point arithmetic not producing exact results in Java](http://stackoverflow.com/questions/1661273/floating-point-arithmetic-not-producing-exact-results-in-java) – Devendra D. Chavan Feb 23 '12 at 13:26
  • @T.J.Crowder how could i find out where the 0.000000005 sneaks in and maybe avoid that ? – Lucian Enache Feb 23 '12 at 13:34
  • @LucianEnache: You'd be best off waiting until you're done, and then trying to deal with it. See my (updated) answer. But again: Fast computer floating point numbers (like IEEE 754 and the like) sacrifice a **very** small amount of inaccuracy for speed, that's just the way they are. – T.J. Crowder Feb 23 '12 at 13:37
  • @Alnitak: Actually, you can (or at least, it looks that way to me; I'm no guru!). It seems to be one of the intermediate values where the inaccuracy is being introduced. – T.J. Crowder Feb 23 '12 at 13:38
  • @T.J.Crowder http://babbage.cs.qc.cuny.edu/IEEE-754/ suggests otherwise, showing the mantissa as a recurring binary fraction. Likewise 0.2 – Alnitak Feb 23 '12 at 15:14
  • 1
    @Alnitak: Now, *that* link goes in my tools list. Nifty! Glad I said I wasn't a guru. :-) But at least you can get the significance down to the point where the `toString` ignores it. – T.J. Crowder Feb 23 '12 at 15:22

5 Answers5

6

You are accumulating a rounding error. The simplest thing to do is to use an long (or int and only use a double at the end. (Or a BigDecimal and double at the end, but this is overly complicated)

public double votes() {
    long votexp = 0;
    for (Elettore e : docenti.values())
        if (e.getVoto())          //everytime this is true increment by 1
            votexp += 10;
    for (Elettore e : studenti.values())
        if (e.getVoto())         //everytime this is true increment by 0.2
            votexp += 2;
    for (Elettore e : pta.values())
        if (e.getVoto())        //everytime this is true increment by 0.2
            votexp += 2;
    return votexp / 10.0;
}

double a = 26 / 10.0;
System.out.println(a);

prints

2.6

As the Double.toString() "knows" values can be imprecise, it will do a small amount of rounding. This rounding is limited so the result of operating on two double can have an error too large to hide. If you round your last result correctly, the error will be small enough it won't cause a problem.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
2

Try using java.math.BigDecimal class.

latestVersion
  • 458
  • 1
  • 6
  • 17
0

You have to round the result, floating point numbers in Java (and basically every other environment) are not perfect, and sometimes small inaccuracies creep in.

If you're dealing with decimal numbers, there's BigDecimal, which can precisely represent what you've shown (it just can't precisely represent other things, like 1 / 3).

Alternately, you can multiply by 10, use Math.round, and divide by 10 if the problem isn't with the actual end value, but with inaccuracies that have crept in during the time you've built up that value. That happens to be case with 2.6 built up like this:

double n = 0;

n += 1;
n += 0.2;
n += 1;
n += 0.2;
n += 0.2;

System.out.println("n = " + n);     // "2.6000000000000005"
n = (double)Math.round(n * 10) / 10;
System.out.println("n = " + n);     // "2.6"

...but I don't think there's a guarantee that it will necessarily be the case with all values. (I'm not a floating point guru.)

Or just worry about it when you do the output, by truncating the output result to the appropriate level of precision.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • _very_ small imprecisions - if "2.6" was the distance from the earth to the sun then the error is approximately equal to the size of one gnat's ass. – Alnitak Feb 23 '12 at 13:27
0

Some numbers cannot be represented by double-precision floating point format exactly. Looks like an intermediate number in your calculation has this flaw, which is included in the final result.

m0skit0
  • 25,268
  • 11
  • 79
  • 127
0

You could try this

(double)Math.round(value * 10) / 10

but you will never get the good result by doing addition of doubles like this

Marc
  • 16,170
  • 20
  • 76
  • 119