Retain precision with double in Java

前端 未结 22 3135
情歌与酒
情歌与酒 2020-11-21 05:15
public class doublePrecision {
    public static void main(String[] args) {

        double total = 0;
        total += 5.6;
        total += 5.8;
        System.out         


        
相关标签:
22条回答
  • 2020-11-21 06:02
            /*
            0.8                     1.2
            0.7                     1.3
            0.7000000000000002      2.3
            0.7999999999999998      4.2
            */
            double adjust = fToInt + 1.0 - orgV;
            
            // The following two lines works for me. 
            String s = String.format("%.2f", adjust);
            double val = Double.parseDouble(s);
    
            System.out.println(val); // output: 0.8, 0.7, 0.7, 0.8
    
    0 讨论(0)
  • 2020-11-21 06:03

    Observe that you'd have the same problem if you used limited-precision decimal arithmetic, and wanted to deal with 1/3: 0.333333333 * 3 is 0.999999999, not 1.00000000.

    Unfortunately, 5.6, 5.8 and 11.4 just aren't round numbers in binary, because they involve fifths. So the float representation of them isn't exact, just as 0.3333 isn't exactly 1/3.

    If all the numbers you use are non-recurring decimals, and you want exact results, use BigDecimal. Or as others have said, if your values are like money in the sense that they're all a multiple of 0.01, or 0.001, or something, then multiply everything by a fixed power of 10 and use int or long (addition and subtraction are trivial: watch out for multiplication).

    However, if you are happy with binary for the calculation, but you just want to print things out in a slightly friendlier format, try java.util.Formatter or String.format. In the format string specify a precision less than the full precision of a double. To 10 significant figures, say, 11.399999999999 is 11.4, so the result will be almost as accurate and more human-readable in cases where the binary result is very close to a value requiring only a few decimal places.

    The precision to specify depends a bit on how much maths you've done with your numbers - in general the more you do, the more error will accumulate, but some algorithms accumulate it much faster than others (they're called "unstable" as opposed to "stable" with respect to rounding errors). If all you're doing is adding a few values, then I'd guess that dropping just one decimal place of precision will sort things out. Experiment.

    0 讨论(0)
  • 2020-11-21 06:05

    Check out BigDecimal, it handles problems dealing with floating point arithmetic like that.

    The new call would look like this:

    term[number].coefficient.add(co);
    

    Use setScale() to set the number of decimal place precision to be used.

    0 讨论(0)
  • 2020-11-21 06:07

    You can't, because 7.3 doesn't have a finite representation in binary. The closest you can get is 2054767329987789/2**48 = 7.3+1/1407374883553280.

    Take a look at http://docs.python.org/tutorial/floatingpoint.html for a further explanation. (It's on the Python website, but Java and C++ have the same "problem".)

    The solution depends on what exactly your problem is:

    • If it's that you just don't like seeing all those noise digits, then fix your string formatting. Don't display more than 15 significant digits (or 7 for float).
    • If it's that the inexactness of your numbers is breaking things like "if" statements, then you should write if (abs(x - 7.3) < TOLERANCE) instead of if (x == 7.3).
    • If you're working with money, then what you probably really want is decimal fixed point. Store an integer number of cents or whatever the smallest unit of your currency is.
    • (VERY UNLIKELY) If you need more than 53 significant bits (15-16 significant digits) of precision, then use a high-precision floating-point type, like BigDecimal.
    0 讨论(0)
  • 2020-11-21 06:07

    Short answer: Always use BigDecimal and make sure you are using the constructor with String argument, not the double one.

    Back to your example, the following code will print 11.4, as you wish.

    public class doublePrecision {
        public static void main(String[] args) {
          BigDecimal total = new BigDecimal("0");
          total = total.add(new BigDecimal("5.6"));
          total = total.add(new BigDecimal("5.8"));
          System.out.println(total);
        }
    }
    
    0 讨论(0)
  • 2020-11-21 06:08

    Computers store numbers in binary and can't actually represent numbers such as 33.333333333 or 100.0 exactly. This is one of the tricky things about using doubles. You will have to just round the answer before showing it to a user. Luckily in most applications, you don't need that many decimal places anyhow.

    0 讨论(0)
提交回复
热议问题