Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
При этом никаких проблем с накоплением ошибки не будет, если округлять только на последнем шагеПроблемы могут быть, так как конечное представление чисел в любом случае требует промежуточных округлений. Если длина мантиссы 23 бита, то при перемножении двух чисел имеющих 20-битную мантису ошибки будут появляться.
float[] floats = new float[100];
Arrays.fill(floats, 0.01f);
double[] doubles = new double[100];
Arrays.fill(doubles, 0.01);
float fsum = 0;
for (float x: floats) {
fsum += x;
}
System.out.println(fsum);
// -> выведет 0.99999934, позорная ошибка округления
double dsum = 0;
for (double x: doubles) {
dsum += x;
}
System.out.println(dsum);
// -> выведет 1.0000000000000007 - уже неплохо
System.out.println(kahanSum(floats));
// -> выведет ровно 1.0 - ура!
static float kahanSum(float... input) {
float sum = 0;
float c = 0;
for (float v : input) {
float y = v - c;
float t = sum + y;
c = (t - sum) - y;
sum = t;
}
return sum;
}
Пара слов о числах с плавающей точкой в Java