问题
My assignment is as follows:
Read 20 pairs of numbers (ID number and score respectively) into two separate arrays. Find the average score. Print a table as shown below of the ID, score and difference (score - average) for each student, one student per line. Print the sum, average, and count of score at the head of the table as shown. Round the average and difference to 2 decimal places.
I have a bug in my program that should be really simple, but I just can't figure it out for some reason. I've figured out how to do the whole thing, but for some reason, my subtraction is off. Here's a sample output for reference:
ID Score Difference
115 257.0 14.349999999999994
123 253.0 10.349999999999994
116 246.0 3.3499999999999943
113 243.0 0.3499999999999943
112 239.0 -3.6500000000000057
104 239.0 -3.6500000000000057
110 238.0 -4.650000000000006
218 243.0 0.3499999999999943
208 242.0 -0.6500000000000057
222 223.0 -19.650000000000006
223 230.0 -12.650000000000006
213 229.0 -13.650000000000006
207 228.0 -14.650000000000006
203 224.0 -18.650000000000006
305 265.0 22.349999999999994
306 262.0 19.349999999999994
311 256.0 13.349999999999994
325 246.0 3.3499999999999943
321 245.0 2.3499999999999943
323 245.0 2.3499999999999943
The problem is that when I call my program to just print the average that it's computed, it's a nice rounded 242.65. And since the score[k] is obviously also a round number, I don't understand how this is happening? Any way you can shed some light on what's going wrong here?
import java.util.Scanner;
import java.io.*;
public class prog402a
{
public static void main(String args[])
{
Scanner inFile = null;
try
{
inFile = new Scanner(new File("prog402a.dat"));
}
catch (FileNotFoundException e)
{
System.out.println("File not found!");
System.exit(0);
}
int[] idNumber = new int[20];
double[] score = new double[20];
for(int k = 0; k < idNumber.length; k++)
{
idNumber[k] = inFile.nextInt();
score[k] = inFile.nextDouble();
}
double sum = 0;
for(int k = 0; k < score.length; k++)
{
sum += score[k];
}
double doubSum = (double)sum;
double average = doubSum/20.0;
average=(int)(average*100+.5)/100.0;
System.out.println(average);
System.out.println("ID\tScore\tDifference");
for(int k = 0; k < idNumber.length; k++)
{
System.out.println(idNumber[k] + "\t" + score[k] + "\t" + (score[k] - average));
}
inFile.close();
}
}
回答1:
Floating points use the binary system to represent numbers. That means some numbers that can be represented with a finite amount of digits in the decimal system can't in the binary system. For instance there is no way to correctly represent 0.2
binary. As a result, the algorithm will use the closest value it can represent. Thus it will work with something 0.199999...
-ish or 0.2000...1
-ish. Note the decimal system has problems too, for instance representing 1/3
is done with 0.333333....
so if you would calculate with a limited number of digits. You will always make a (small) error.
There exists however a class - BigDecimal
to that is able to calculate the score with an arbitrary precision, although I think calculating the average for 20
students will only differ on the 7
th digit or so.
Therefore I recommend simply to format the numbers such that for instance, it displays the result precise on two digits. You can do this with:
DecimalFormat myFormatter = new DecimalFormat("0.000"); //the pattern
String output = myFormatter.format(number);
System.out.println(output);
回答2:
Floating point numbers (e.g. float and double numbers in Java) do not
have 100% precision in programming languages as they do in math.
So it may well be that a nice round number (in decimal) like e.g.
242.65
is represented internally (in the JVM e.g) as e.g. 242.64999999997.
I am just speaking roughly here but you get the idea.
Before printing each number just format it to the 2nd decimal digit and you should be fine. Let me try to code a small example for you... Here it is:
import java.text.DecimalFormat;
import java.text.NumberFormat;
public class Test020 {
public static void main(String[] args) {
double d = 13.5 + 0.1 + 0.11;
System.out.println(d);
NumberFormat formatter = new DecimalFormat("#0.00");
System.out.println(formatter.format(d));
}
}
回答3:
As stated previously, the problem is that floats are not 100% accurate. The simplest solution in your case is probably String.format; change your print line to :
System.out.println(
String.format("%d\t%.2f\t%.2f", idNumber[k], score[k], score[k] - average));
This will output the numbers rounded to 2 decimal places.
来源:https://stackoverflow.com/questions/28611252/rounding-in-java