Раунд с проблемой пола в Objective-C - PullRequest
3 голосов
/ 13 февраля 2010

Я вычисляю g с e и s, которые все удваиваются. После этого я хочу обрезать все цифры после секунды и сохранить результат в x, например:

г = 2,123 => х = 2,12

г = 5,34995 => х = 5,34

и так далее. Я пользуюсь ...

g = 0.5*e + 0.5*s;
x = floor(g*100)/100;

... и большую часть времени работает нормально. Но иногда я получаю странные результаты. Например:

е = 3,0 с = 1,6 г = 2,30 но х = 2,29 !!!

Итак, я попытался отследить ошибку:

g = 0.5*e + 0.5*s;
NSLog(@"%f",g);

дает мне г = 2,30

g = g * 100;
NSLog(@"%f",g);

дает мне г = 230,0

x = floor(g);
NSLog(@"%f",x);

приводит к х = 229,0 !!!

Я не понимаю! Помогите, пожалуйста! : -)

Ответы [ 3 ]

3 голосов
/ 13 февраля 2010

Это будет связано с вычислениями с плавающей запятой.

Ваш расчет

g * 100

уже возвращает

+229,99999999999997

Откуда твоя проблема.

Взгляните на ИНФОРМАЦИЯ: Точность и точность в вычислениях с плавающей точкой

Также взгляните на С плавающей точкой

Проблемы точности

Тот факт, что числа с плавающей точкой не может точно представить все реальное числа, и что с плавающей точкой операции не могут точно представлять истинные арифметические операции, приводит к много удивительных ситуаций. Это связанные с конечной точностью с какие компьютеры обычно представляют число.

2 голосов
/ 25 августа 2011

Как уже упоминали другие, это связано с ограниченной точностью чисел с плавающей запятой в компьютерах. Эти неточности обнаруживаются везде, где принимается жесткое решение «да / нет» относительно числа с плавающей запятой. Чтобы решить проблему, вы можете добавить / вычесть небольшое число, чтобы найти правильный ответ с определенной точностью.

Вы можете найти такие функции, как эти:

#define ACC 1e-7

double floorAcc( double x ) { return floor(x + ACC);}
double ceilAcc( double x ) { return ceil(x - ACC); }
bool isLessThanAcc( double x, double y ) { return (x + ACC) < y; }
bool isEqualAcc( double x, double y ) { return (x + ACC) > y && (x - ACC) < y; }

Конечно, они работают только в ограниченном диапазоне номеров. При работе с очень маленькими или очень большими числами вам нужно выбрать другое значение для ACC.

Обратите внимание, что значение ACC, как правило, зависит от точности чисел в вашем приложении, не от значения x. Например, сравнить два числа a и b на равенство можно двумя способами: isEqualAcc(a, b) и isEqualAcc(a-b, 0). Вы хотели бы получить один и тот же результат в обоих случаях, хотя во втором случае число x, вероятно, намного меньше.

0 голосов
/ 13 июня 2013

Вот возможный подход с использованием промежуточных целочисленных результатов:

double e = 3.0;
double s = 1.6;

NSInteger e1 = e * .5 * 100.0; // 150
NSInteger s1 = s * .5 * 100.0; // 80

double x = (e1 + s1)/100.0; // 2.3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...