Потеря точности при преобразовании 'float' в NSNumber, обратно в 'float' - PullRequest
9 голосов
/ 29 октября 2011

Кажется, я столкнулся со странной проблемой в Objective-C: преобразовать число с плавающей точкой в ​​NSNumber (обернуть его для удобства) и затем преобразовать его обратно в число с плавающей точкой.

В двух словах, мой классимеет свойство red, которое представляет собой число с плавающей запятой от 0.0 до 1.0:

@property (nonatomic, assign) float red;

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

Вот интересный фрагмент, в котором сравниваются два значения:

if (localObject.red != remoteObject.red) {
    NSLog(@"Local red: %f Remote red: %f", localObject.red, remoteObject.red);
}

Вот что я вижу в журналах:

2011-10-28 21:07:02.356 MyApp[12826:aa63] Local red: 0.205837 Remote red: 0.205837

Странно.Правильно?Как выполняется этот фрагмент кода?

Фактическое значение, хранящееся в файле:

...red="0.205837"...

Преобразуется в float с использованием:

currentObject.red = [[attributeDict valueForKey:@"red"] floatValue];

В другой точке кода я смог получить скриншот из GDB.Он был распечатан в NSLog как: (Это также точность, с которой он появляется в файле на диске.)

2011-10-28 21:21:19.894 MyApp[13214:1c03] Local red: 0.707199 Remote red: 0.707199

Но в отладчике он выглядит как:

GDB Screenshot

Как этот уровень точности получается на уровне свойств, но не сохраняется в файле или печатается должным образом в NSLog? А почему оно кажется разным?

Ответы [ 4 ]

5 голосов
/ 29 октября 2011

Если вы в любой момент преобразуете его в / из строки, попробуйте использовать %0.16f вместо %f (или любой другой точности, которую вы хотите вместо .16).

Для получения дополнительной информации см. IEEE Std форматирование .


Также используйте objectForKey вместо valueForKey (valueForKey не предназначен для использования в словарях):

currentObject.red = [[attributeDict objectForKey:@"red"] floatValue];

См. Этот SO-ответ для лучшего объяснения objectForKey против valueForKey:

Разница между objectForKey и valueForKey?

4 голосов
/ 29 октября 2011

Проблема, с которой вы столкнулись - проблема с плавающей запятой.Число с плавающей запятой не совсем соответствует сохраненному числу (за исключением некоторых особых случаев, которые здесь не имеют значения).Пример в ссылке Craig разместил является отличным примером этого.

В вашем коде, когда вы записываете значение в свой файл, вы пишете приближение того, что хранится в плавающейномер точки.Когда вы загружаете его обратно, другое приближение сохраняется в буфере.Однако эти два числа вряд ли будут равны.

Лучшее решение - использовать нечеткое сравнение двух чисел с плавающей запятой.Я не являюсь программистом c, поэтому я не знаю, включают ли языки встроенные функции для предварительного сравнения.Однако эта ссылка предоставляет хороший набор примеров различных способов выполнить это сравнение.

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

2 голосов
/ 29 октября 2011

Вы говорите, что «удаленное» значение «загружено с диска». Я предполагаю, что представление на диске - это не значение бита с плавающей запятой IEEE, а скорее какое-то символьное представление или что-то подобное. Таким образом, неизбежны ошибки преобразования, идущие в и из этого представления, учитывая то, как работает IEEE float. Вы не получите точный результат, учитывая, что в значении с плавающей запятой есть только около 6 цифр десятичной точности, но оно редко отображается точно на 6 десятичных цифр, но вместо этого похоже на представление 1/3 в десятичной дроби - точной нет отображение.

0 голосов
/ 29 октября 2011

Читать это: http://floating -point-gui.de /

...