NSDecimalNumber (x) .intValue возвращает -2, 0, 15 и 199, в зависимости от количества десятичных знаков в x (x = 199.999 ... 5) - PullRequest
2 голосов
/ 08 мая 2019

Мы нашли интересный случай в нашей бизнес-логике, который полностью нарушает нашу логику, и мы не понимаем, почему NSDecimalNumber и Decimal ведут себя так, как они.

Моя игровая площадка для случаев такова, какследует:

import Foundation

let pQuantity = Decimal(string: "0.2857142857142857")!
let pPrice = Decimal(string: "7.00000000000000035")!

let calced = NSDecimalNumber(decimal: pQuantity * pPrice * Decimal(integerLiteral: 100))   // 200
let decimal = calced.decimalValue                                                          // 199.9999999999999999999999999999995
let integer = calced.intValue                                                              // 0

NSDecimalNumber(decimal: Decimal(string: "199.9999999999999999999999999999995")!).intValue // 0
NSDecimalNumber(decimal: Decimal(string: "199.9999999999999995")!).intValue                // 199
NSDecimalNumber(decimal: Decimal(string: "199.99999999999999995")!).intValue               // 15
NSDecimalNumber(decimal: Decimal(string: "199.999999999999999995")!).intValue              // -2

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

Нам нужно преобразоватьнаши необработанные десятичные значения, количество и цена, во временные интервалы, при расчете того, насколько равномерно разделить эти количества, чтобы получить привлекательные цены.Однако мы не можем по какой-то причине в этом случае, поскольку первоначальный шаг преобразования завершается неудачно, производя 0 вместо 200 (и да, текущий код выдаст 199, что является ошибкой).

Почему NSDecimalNumber возвращает эти странные значения в зависимости от количества десятичных знаков в диапазоне от -2 до 199?

Нашим решением было бы округлить внутренний расчет, прежде чем поместить его в NSDecimalNumber, но мы хотели бы знать причину этого для начала.Это ошибка или ожидается, и нужно знать, что это может произойти?

1 Ответ

1 голос
/ 08 мая 2019

Это явно фундаментальная ошибка, вероятно , упомянутая Мартином R в комментариях.

Я экспериментировал на игровой площадке (Swift 5) и обнаружил, что комментарий об этой ошибке, int32Value работает правильно, является верным.

import Foundation

let pQuantity = Decimal(string: "0.2857142857142857")!
let pPrice = Decimal(string: "7.00000000000000035")!

let calced = NSDecimalNumber(decimal: pQuantity * pPrice * Decimal(integerLiteral: 100))   // 200
let decimal = calced.decimalValue                                                          // 199.9999999999999999999999999999995
let integer = calced.int32Value                                                              // 200

NSDecimalNumber(decimal: Decimal(string: "199.9999999999999999999999999999995")!).uint32Value // 200
NSDecimalNumber(decimal: Decimal(string: "199.9999999999999995")!).int32Value                // 200
NSDecimalNumber(decimal: Decimal(string: "199.99999999999999995")!).int32Value               // 200
NSDecimalNumber(decimal: Decimal(string: "199.999999999999999995")!).int32Value              // 200

Также, как видите, uint32Value также работает правильно. Однако ни один из 64-битных вариантов не работает.

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

...