开发者

Rounding NSDecimalNumber

I'm having the hardest time figuring out something that seems like it should be very simple. I need to accurately round an NSDecimalNumber to a particular number of decimal places (determined at runtime.) So far as I can tell, I have two options, neither of which I like.

  1. Convert to a float, and use C rounding functions: I don't like this because accuracy matters in this case. Float开发者_如何学Cs can't always accurately represent decimal numbers, and this could cause problems.
  2. Convert to a string using NSNumberFormatter and then convert back: I don't like this one because it just seems ugly and inefficient.

Is there another way that I've missed? There has got to be an easy way to do rounding of NSDecimalNumbers, but I can't seem to figure out for the life of me what it is.


You simply call decimalNumberByRoundingAccordingToBehavior:with the desired NSDecimalNumberBehaviors protocol. See the NSDecimalNumberBehaviors reference in the dev docs.

Update: See http://www.cimgf.com/2008/04/23/cocoa-tutorial-dont-be-lazy-with-nsdecimalnumber-like-me/


For those that prefer example code...

To round to 2 decimal places (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];

To round to the nearest thousand (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];


I got it working using the below code in 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)

Note the scale parameter, used to define the decimal places you need. Outlined here: https://developer.apple.com/reference/foundation/nsdecimalnumberhandler/1578295-decimalnumberhandlerwithrounding


I'm using this solution:

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜