Android (большой) терпит неудачу на продукте с плавающей запятой

Ситуация драматическая... Мне нужно 5 дней, чтобы решить эту проблему, и я не могу выбраться.

Проблема: простая операция, как продукт, всегда дает неправильный результат. Зачем?

Извлечение кода:

//all vars are float
// resultVec is a vector [3]
// Rs is a vector [3]
// accelerationvalues is a vector [3]
   resultVec[0]=Rs[0]*accelerationvalues[0]+Rs[1]*accelerationvalues[1]+Rs[2]*accelerationvalues[2];

//debug to print result

Log.d("e", "("+Rs[0]+")*("+accelerationvalues[0]+")+("+Rs[1]+")*("+accelerationvalues[1]+")+("+Rs[2]+")*("+accelerationvalues[2]+")="+(resultVec[0]));

И это результат Log Cat:Но вы можете просто попробовать, что это не так: поиск в Google

(0.040147018)*(-0.9942854)+(0.9984244)*(-0.32688835)+(0.039202508)*(9.343558)

И вы обнаружите, что истинный результат - 8,67678679 × 10-9, который очень отличается от других. Эта ошибка повторяется всегда, когда я выполняю программу, иногда также и в знаке!

В чем проблема?

Я пробовал весь путь, чтобы решить это! (некоторые опубликованы ниже):

Вы можете найти полный источник здесь.

  1. сохранить Rs и значения ускорения в массиве и выполнить расчет вне списка. Безрезультатно.
  2. Конвертировать float в double, безрезультатно.
  3. Много других способов

PS Эта проблема происходит только для resultVec[0] а также resultVec[1]вместо resultVec[2] хорошо рассчитан.

4 ответа

Решение

Это не вина андроида, это то, как вы разработали приложение.

Выполните это в простом приложении Java:

public class ArithmTest {

    public static void main(String[] args) {
        double d1 = (0.040147018)*(-0.9942854)+(0.9984244)*(-0.32688835)+(0.039202508)*(9.343558);
        System.out.println(d1);

        float f1 = 0.040147018f;
        float f2 = -0.9942854f;

        float f3 = 0.9984244f;
        float f4 = -0.32688835f;

        float f5 = 0.039202508f;
        float f6 = 9.343558f;

        System.out.println(f1*f2 + f3*f4 + f5*f6);

    }
}

Как видите, первая такая же, как у Google, а вторая распечатка - ценность вашего приложения. Чтобы решить эту проблему, я думаю, что вы должны использовать double вместо float в каждой объявленной вами переменной, например: accelerationvalues а также resultVec,

Вы умножаете числа с плавающей запятой, накапливая ошибки округления до конца. Использование двойной точности не решит основную проблему: двоичные компьютеры не могут точно представлять десятичные числа с плавающей запятой.

Прочитайте это: http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html для обзора проблемы.

Скорее всего, вы обнаружите, что вам нужно выполнить вычисления с использованием класса BigDecimal.

Я думаю, что вы должны использовать двойной тип вместо float

Вы можете столкнуться с ограниченной точностью значений с плавающей запятой. Чтобы подтвердить это, вы можете изменить float в double или использовать BigDecimal,

Другие вопросы по тегам