Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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. Floats 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.

like image 739
Nate Thorn Avatar asked Oct 20 '10 18:10

Nate Thorn


People also ask

How to round numbers to the nearest hundredths?

Rounding Numbers. Say you wanted to round the number 838.274. Depending on which place value you'll round to, the final result will vary. Rounding 838.274: Rounding to the nearest hundred is 800. Rounding to the nearest ten is 840. Rounding to the nearest one is 838. Rounding to the nearest tenth is 838.3. Rounding to the nearest hundredth is ...

What is the purpose of rounding decimals?

As you add place values to a decimal number after the decimal point, rounding decimals becomes an effective tool for working with long chains of place values in mathematical calculations. Understanding how to round decimals quickly is an effective skill for many applications.

What does it mean to round up a number?

For example, when rounding to the ones place: Rounding up, sometimes referred to as "taking the ceiling" of a number means rounding up towards the nearest integer. For example, when rounding to the ones place, any non-integer value will be rounded up to the next highest integer, as shown below:

How do you round decimals to the thousandth place?

To round a decimal value, look at the last place value of the number with which you're working. For instance, in the number 76.287, the last place value after the decimal point is the thousandth place.


4 Answers

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/

like image 160
CuriousRabbit Avatar answered Oct 03 '22 09:10

CuriousRabbit


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];
like image 31
Dave Batton Avatar answered Oct 03 '22 09:10

Dave Batton


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

like image 33
Harry Bloom Avatar answered Oct 03 '22 07:10

Harry Bloom


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
like image 22
MarcioElizeu Avatar answered Oct 03 '22 09:10

MarcioElizeu