2016-08-24 5 views
8

Почему-то некоторые двойники в моем приложении Swift приносят мне проблемы при преобразовании в NSNumber, а некоторые нет. Моему приложению нужно преобразовать двойные числа с двумя десятичными знаками (цены) в NSNumbers, чтобы их можно было хранить и извлекать с помощью Core Data. Например, несколько конкретных цен, таких как 79.99, будут оцениваться до 99.98999999999999, если они специально не форматируются с использованием метода doubleValue NSNumber.Преобразование Double в NSNumber в Swift Точность потери

Здесь selectedWarranty.price = 79,99, как показано в отладчике

// item.price: NSNumber?  
// selectedWarranty.price: Double? 

item.price = NSNumber(double: selectedWarranty.price!) 

Я запрограммировал некоторые операторы печати, чтобы показать, как преобразование работает

Original double: 79.99 
Converted to NSNumber: 79.98999999999999 
.doubleValue Representation: 79.99 

Может кто-нибудь объяснить, если есть причина, почему Инициализатор не может наверняка сохранить 2 десятичных знака для каждого номера? Я действительно хотел бы хранить цены в Core Data, как они должны быть. Форматирование каждый раз, когда оно отображается, не очень удобно.

UPDATE: Преобразованный объект основных данных для типа NSDecimalNumber по модели данных, 79,99 и 99,99 больше не является проблемой, но теперь более управляемы проблема с разными номерами ...

Original double: 39.99 
Converted to NSDecimalNumber: 39.99000000000001024 
+1

Можете ли вы сделать [минимальный, полный и проверяемый пример] (http://stackoverflow.com/help/mcve)? – Alexander

+1

Используйте 'NSDecimalNumber' вместо' NSNumber' для валюты. – rmaddy

+0

Я не могу воспроизвести эту проблему. http://swiftlang.ng.bluemix.net/#/repl/57bdc2590dcf4abf47da28c2 – Alexander

ответ

9

Во-первых, вы» перепутав некоторые термины. 79.98999999999999 - это более высокая точность, чем 79.99 (имеет более длинное десятичное расширение), но более низкая точность (она отличается от истинного значения).

Во-вторых, NSNumber не хранит ни 79.99, ни 79.98999999999999. Он сохраняет величину значения в соответствии со стандартом IEEE 754. То, что вы видите, вероятно, является следствием логики печати, которая применяется для преобразования этой величины в читаемый человеком номер. В любом случае вам не следует полагаться на Float или Double для хранения значений с фиксированной точностью. По самой своей природе они жертвуют точностью, чтобы получить более широкий диапазон представимых значений.

Вам будет намного лучше представлять цены как Int центов, или как NSDecimalNumber.

Пожалуйста, обратитесь к Why not use Double or Float to represent currency?

+0

Спасибо за объяснение. Маршрут NSDecimalNumber кажется лучшим. Мой единственный вопрос - как я могу заставить модель Core Data позволить мне использовать это вместо NSNumber? Я не очень опытен в этой области – joelrorseth

+0

Я не знаю, попробуйте открыть для него новый вопрос. Если вы чувствуете, что этот ответ удовлетворяет вашему непосредственному вопросу, отметьте его как принятый :) – Alexander

1

Вот как двойные работает везде. Если вам нужно всего 2 десятичных знака, подумайте об использовании integer/long вместо добавления точки после второй цифры, когда нужно отобразить значение.

 Смежные вопросы

  • Нет связанных вопросов^_^