doubleValue не всегда правильно преобразует объект в двойное значение

У меня есть NSArray, в котором я хотел бы хранить двойные значения. Я определил это следующим образом

NSMutableArray *setOfDoubles;

Я добавляю элементы следующим образом

NSNumber *num;
num = [NSNumber numberWithDouble:someDouble];
[setOfDoubles addObject:num];

И я прочитал элемент следующим образом

num = [setOfDoubles lastObject];  
[setOfDoubles removeLastObject];
doubleValueToUse = [num doubleValue];

Моя проблема иногда (не всегда), например, когда число (как объект) равно 5,1, doubleValueToUse (как двойное значение) равно 5,099999999999996. То, как я понял num (как объект), равно 5.1, заключается в том, что я отлаживаю, и когда я наводил указатель мыши на num в строке num = [setOfDoubles lastObject]; он показывает 5.1, но после преобразования doubleValue он становится числом, которое я упомянул. Кто-нибудь знает, почему это происходит?


person Dogahe    schedule 02.09.2011    source источник


Ответы (2)


Не каждое число может быть точно представлено с помощью переменной с плавающей запятой. Например, вы не можете точно представить, скажем, 1/3, используя конечное число цифр в нашей обычной десятичной системе (с основанием 10), но в троичной (с основанием 3) это будет всего 0,1. Точно так же числа, которые вы можете записать с конечным числом цифр в десятичном виде, могут не обязательно иметь конечное число цифр в их двоичном представлении, отсюда и ошибка.

Несколько ссылок по теме, если интересно:

http://floating-point-gui.de/basic/

http://www.mathworks.com/support/tech-notes/1100/1108.html

http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html

person SVD    schedule 02.09.2011
comment
Спасибо! Теперь я понимаю, в чем проблема. Так как же калькуляторы, будь то физические калькуляторы или, скажем, калькулятор iPhone, решают эту проблему? Используют ли они другой тип данных вместо float? Или они реализуют какое-то округление? - person Dogahe; 07.09.2011
comment
Определенно используется округление (например, попробуйте 2/3) и, возможно, другие методы (например, использование вычисления с фиксированной точкой, если это возможно). - person SVD; 07.09.2011
comment
Спасибо! Присланные вами ссылки очень помогли. Я обнаружил, что выполнение манипуляций с точностью float (или double), а затем представление результата с меньшим числом знаков после запятой путем форматирования строк (например, %g.14) решит проблему. Я не знаю, столкнусь ли я с исключениями из этого, но пока это работает. Еще раз спасибо! - person Dogahe; 07.09.2011

Это нормально для значений float.

Если вы хотите сохранить исходное (одно и то же) представление чисел float во всех местах вашего кода, вы можете сохранить их, например, в NSString. Когда вам понадобится число с плавающей запятой, вы просто напишите [NSString floatValue];. Но это неэффективно, если у вас большое количество значений float.

person Nekto    schedule 02.09.2011