0

I have an ArrayList of Double. Here I am trying to update one value at specific index using set method.

It is behaving weird. When number of decimal bits are high (15) and I change only last digit, it's not updating the data.

And if I change second last digit, it's updating the data but truncating the last digit.

And if there is any change in third last digit, everything works fine.

Why it is behaving like this?

public static void main(String[] args) {

    List<Double> myList = new ArrayList<>();
    myList.add(67.635783590864854);
    myList.add(47.635783590864854);
    
    System.out.println(myList); // Output : [67.63578359086486, 47.635783590864854]
    
    // Updated worked fine in 3rd last digit change
    myList.set(1, 47.635783590864754);
    System.out.println(myList); // Output : [67.63578359086486, 47.635783590864754]
    
    // Data not updated in last digit change
    myList.set(1, 47.635783590864753);
    System.out.println(myList); // Output : [67.63578359086486, 47.635783590864754]
    
    // Last Bit Truncated in 2nd last digit change
    myList.set(1, 47.635783590864763);
    System.out.println(myList); // Output : [67.63578359086486, 47.63578359086476]
  }
Gaurav Jeswani
  • 4,410
  • 6
  • 26
  • 47
  • 2
    This is not a problem with `ArrayList` but with double precision. Try passing those values to `System.out.println()` and you'll get the same. – Thomas Jul 12 '21 at 12:55
  • This is just how `double` numbers are defined. Floating point math takes a while to get used to. – Hulk Jul 12 '21 at 12:57
  • 2
    This famous document explains most of the things to know about fixed-width floating point numbers and their representation in memory: [What Every Computer Scientist Should Know About Floating-Point Arithmetic](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – Hulk Jul 12 '21 at 13:01
  • @Hulk Thanks for the link. It's really helpful. – Gaurav Jeswani Jul 12 '21 at 13:02
  • Does this answer your question? [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Hulk Jul 12 '21 at 13:47

1 Answers1

0

You could use BigDecimal and do it like this.

List<BigDecimal> myList = new ArrayList<>();
myList.add(new BigDecimal("67.635783590864854"));
myList.add(new BigDecimal("47.635783590864854"));

System.out.println(myList); // Output : [67.63578359086486, 47.635783590864854]

// Updated worked fine in 3rd last digit change
myList.set(1, new BigDecimal("47.635783590864754"));
System.out.println(myList); // Output : [67.63578359086486, 47.635783590864754]

// Data not updated in last digit change
myList.set(1, new BigDecimal("47.635783590864753"));
System.out.println(myList); // Output : [67.63578359086486, 47.635783590864754]

// Last Bit Truncated in 2nd last digit change
myList.set(1, new BigDecimal("47.635783590864763"));
System.out.println(myList); // Output : [67.63578359086486, 47.63578359086476]

prints

[67.635783590864854, 47.635783590864854]
[67.635783590864854, 47.635783590864754]
[67.635783590864854, 47.635783590864753]
[67.635783590864854, 47.635783590864763]

But that may not be sufficient for your application. You could even make the List a List<String> and use the String value of BigDecimal. But using something like a decimal number (with its upredictable precision) in a List, Map, or Set where you need to use it based upon its current or computed value can be fraught with problems. This problem even manifests itself in simple comparisons.
e.g. System.out.println(0 == .00000000000000000001) will print false.

WJS
  • 36,363
  • 4
  • 24
  • 39