3

I'm writing a program that prints an array containing the sum of the values of two arrays passed as parameters. It all works fine with the exception of the last double value. I want the last value to print as 3.1. Instead it's printing the following:

[5.9, 11.7, 2.4, 3.0999999999999996]

Not sure how to format to print otherwise as I'm not allowed to use a String to solve it. I'm not having that problem with the other values. Here's my code and thanks for the help!

    import java.util.*;

class Sum
{
    public static void main (String [] args)
    {
        double [] a1 = {4.5, 2.8, 3.4, 0.8};
        double [] a2 = {1.4, 8.9, -1.0, 2.3};

        arraySum (a1, a2);

        System.out.println (Arrays.toString (arraySum (a1, a2)));   
    }

    public static double [] arraySum (double [] x, double [] y)
    {
        int length = 0;
        double [] sum = new double [x.length];
        length = x.length;

            for (int i = 0; i <= length - 1; i++)
            {
                sum[i] = x[i] + y[i];
            }

        return sum;

    }
}
srsarkar7
  • 155
  • 5
  • 19
  • this is because of binary floating point, which is one of the most basic things that programmers must know – phuclv Dec 17 '13 at 03:06

4 Answers4

3

You want to use deciaml format

DecimalFormat df=new DecimalFormat("#.#");
String outputString=df.format(sum);
Tomas Bisciak
  • 2,801
  • 5
  • 33
  • 57
3

This is due to the IEEE floating point model. It can't represent exactly 3.1. To print it like you want, you will have to do it manually, instead of using Arrays.toString. Loop over the doubles and format them:

public static String toString(double[] x, DecimalFormat format)
{
    StringBuilder sb = new StringBuilder();
    sb.append("[");
    for (int i = 0; i < x.length; ++i)
    {
        sb.append(format.format(x[i]));
        sb.append(", ");
    }
    sb.delete(sb.length() - 2, sb.length());
    sb.append("]");
    return sb.toString();
}

And then call like:

toString(sum, new DecimalFormat("#.#"));

To do the trick using only doubles, you might try to apply this, but this is dirty and not guaranteed to work:

double x = ...;
x = 0.001 * Math.round(x * 1000.0);
System.out.println(x);
Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287
  • Problem is I can't use a String to solve it... – srsarkar7 Dec 17 '13 at 00:45
  • 1
    Good answer, only criticism is that String.format will have to parse the format string for every element in the array. Perhaps a DecimalFormat will be more efficient. – LINEMAN78 Dec 17 '13 at 00:58
0

The number is still correct if you round to a reasonable amount of sigfigs which is what DecimalFormat and String.format will do for you under the covers. As @neminem said this is caused by the same issue as Strange floating-point behaviour in a Java program. If it really is a big deal to you that the actual number represented be accurate to sigfigs > ~8 than consider using BigDecimal as you will never lose any precision.

Community
  • 1
  • 1
LINEMAN78
  • 2,562
  • 16
  • 19
0

If you are not allowed to use System.out.printf() to solve the problem, then your only choice is to use BigDecimal objects to hold the values. There is no way that you will ever get a 3.1 result out of a double without one of those two methods (or DecimalFormat).

You say that you "can't use String to solve it", but I don't think that doing...

for (double d : arraySum (a1, a2)) {
    System.out.printf("%.1f\n", d);
}

qualifies as "using a String to solve it". Seems perfectly legitimate to me.

brettw
  • 10,664
  • 2
  • 42
  • 59