Подтвердить что ты не робот

Округление NSDecimalNumber

У меня самое сложное время выяснить, что кажется, что это должно быть очень просто. Мне нужно точно округлить NSDecimalNumber до определенного количества десятичных знаков (определяется во время выполнения.) Насколько я могу судить, у меня есть два варианта, ни один из которых мне не нравится.

  • Преобразовать в float и использовать функции округления C: Мне это не нравится, потому что в этом случае важна точность. Поплавки не всегда могут точно представлять десятичные числа, и это может вызвать проблемы.
  • Преобразовать в строку с помощью NSNumberFormatter и затем преобразовать обратно: Мне это не нравится, потому что это кажется уродливым и неэффективным.

Есть ли другой способ, который я пропустил? Там должен быть простой способ сделать округление NSDecimalNumbers, но я не могу понять, насколько я понимаю, что это такое.

4b9b3361

Ответ 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