Округление NSDecimalNumber
У меня самое сложное время выяснить, что кажется, что это должно быть очень просто. Мне нужно точно округлить NSDecimalNumber до определенного количества десятичных знаков (определяется во время выполнения.) Насколько я могу судить, у меня есть два варианта, ни один из которых мне не нравится.
- Преобразовать в float и использовать функции округления C: Мне это не нравится, потому что в этом случае важна точность. Поплавки не всегда могут точно представлять десятичные числа, и это может вызвать проблемы.
- Преобразовать в строку с помощью NSNumberFormatter и затем преобразовать обратно: Мне это не нравится, потому что это кажется уродливым и неэффективным.
Есть ли другой способ, который я пропустил? Там должен быть простой способ сделать округление NSDecimalNumbers, но я не могу понять, насколько я понимаю, что это такое.
Ответы
Ответ 1
Вы просто вызываете decimalNumberByRoundingAccordingToBehavior:
с помощью требуемого протокола NSDecimalNumberBehaviors
. См. Ссылку NSDecimalNumberBehaviors
в dev docs.
Обновление: см. http://www.cimgf.com/2008/04/23/cocoa-tutorial-dont-be-lazy-with-nsdecimalnumber-like-me/
Ответ 2
Для тех, кто предпочитает пример кода...
Чтобы округлить до двух знаков после запятой (12345.68):
NSDecimalNumber *originalNumber = [NSDecimalNumber decimalNumberWithString:@"12345.6789"];
NSDecimalNumberHandler *behavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain
scale:2
raiseOnExactness:NO
raiseOnOverflow:NO
raiseOnUnderflow:NO
raiseOnDivideByZero:NO];
NSDecimalNumber *roundedNumber = [originalNumber decimalNumberByRoundingAccordingToBehavior:behavior];
Чтобы округлить до ближайшей тысячи (12000):
NSDecimalNumber *originalNumber = [NSDecimalNumber decimalNumberWithString:@"12345.6789"];
NSDecimalNumberHandler *behavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain
scale:-3
raiseOnExactness:NO
raiseOnOverflow:NO
raiseOnUnderflow:NO
raiseOnDivideByZero:NO];
NSDecimalNumber *roundedNumber = [originalNumber decimalNumberByRoundingAccordingToBehavior:behavior];
Ответ 3
Я работал, используя приведенный ниже код в Swift 3.
let amount = NSDecimalNumber(string: "123.456789")
let handler = NSDecimalNumberHandler(roundingMode: .plain, scale: 2, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false)
let roundedAmount = amount.rounding(accordingToBehavior: handler)
Обратите внимание на параметр масштаба, используемый для определения нужных вам десятичных знаков. Описан здесь: https://developer.apple.com/reference/foundation/nsdecimalnumberhandler/1578295-decimalnumberhandlerwithrounding
Ответ 4
Я использую это решение:
import Foundation
extension NSDecimalNumber {
public func round(_ decimals:Int) -> NSDecimalNumber {
return self.rounding(accordingToBehavior:
NSDecimalNumberHandler(roundingMode: .plain,
scale: Int16(decimals),
raiseOnExactness: false,
raiseOnOverflow: false,
raiseOnUnderflow: false,
raiseOnDivideByZero: false))
}
}
let amount = NSDecimalNumber(string: "123.456")
amount.round(2) --> 123.46
amount.round(1) --> 123.5
amount.round(0) --> 123
amount.round(-1) --> 120
amount.round(-2) --> 100