I am confused by NSDecimalNumber and its "behaviors". I have an NSDecimalNumber that represents a dollar value, say $37.50. I'd like to find out how many times say 5.0 goes into that number and then know what's left over. I can get the straight division and get 7.50 but I want 7 mod 2.50. I could convert to an integer but need to save the "cents" so wondering if there's some tricks in the framework?
5 Answers
Using Peter Hoseys example, but with iOS code:
NSDecimalNumber *dividend = [NSDecimalNumber decimalNumberWithDecimal:[[NSNumber numberWithDouble:37.5] decimalValue]];
NSDecimalNumber *divisor = [NSDecimalNumber decimalNumberWithDecimal:[[NSNumber numberWithDouble:5.0] decimalValue]];
NSDecimalNumber *quotient = [dividend decimalNumberByDividingBy:divisor withBehavior:[NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundDown scale:0 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO]];
NSDecimalNumber *subtractAmount = [quotient decimalNumberByMultiplyingBy:divisor];
NSDecimalNumber *remainder = [dividend decimalNumberBySubtracting:subtractAmount];
-
1You have to set right rounding mode if one of dividend or divisor is negative. `NSRoundingMode roundingMode = ((dividend.floatValue < 0) ^ (divisor.floatValue < 0)) ? NSRoundUp : NSRoundDown;` – user500 Aug 13 '12 at 22:39
- Divide the dividend by the divisor, rounding down. This gets you the quotient.
- Multiply the divisor by the quotient.
- Subtract that from the dividend. This gets you the remainder.
(37.50 // 5) == 7; 7 * 5 == 35; 37.50 - 35 = 2.50.
(Note: //
is Python's operator for integral division. I've borrowed it here. Obviously, you should not actually attempt to use //
for division in Objective-C code.)

- 95,783
- 15
- 211
- 370
-
To round down, use floor() from math.h — it takes a double and returns a double. – Quinn Taylor Jul 24 '09 at 05:08
-
If you're using decimal numbers, try to stay within that type as much as possible. Namely, to round use decimalNumberByRoundingAccordingToBehavior:. – Tim Jul 24 '09 at 05:18
-
Better yet, use `decimalNumberByDividingBy:withBehavior:` to do the division. Then you don't need to round separately. – Peter Hosey Jul 24 '09 at 05:19
-
Note that this doesn't work correctly with negative dividend or negative divisor. I've posted a `NSDecimalNumber` category below that takes care of those cases. – Pascal Feb 21 '13 at 17:51
Here's a NSDecimalNumber
category which also works with negative numbers and negative divisors:
- (BOOL)isNegative
{
return (NSOrderedDescending == [[NSDecimalNumber zero] compare:self]);
}
- (NSDecimalNumber *)invertedNumber
{
NSDecimalNumber *negOne = [NSDecimalNumber decimalNumberWithMantissa:1 exponent:0 isNegative:YES];
return [self decimalNumberByMultiplyingBy:negOne];
}
- (NSDecimalNumber *)moduloFor:(NSDecimalNumber *)divisor
{
NSRoundingMode roundingMode = ([self isNegative] ^ [divisor isNegative]) ? NSRoundUp : NSRoundDown;
NSDecimalNumberHandler *rounding = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:roundingMode
scale:0
raiseOnExactness:NO
raiseOnOverflow:NO
raiseOnUnderflow:NO
raiseOnDivideByZero:NO];
// divide and get the remainder
NSDecimalNumber *quotient = [self decimalNumberByDividingBy:divisor withBehavior:rounding];
NSDecimalNumber *subtract = [quotient decimalNumberByMultiplyingBy:divisor];
NSDecimalNumber *modulo = [self decimalNumberBySubtracting:subtract];
if ([divisor isNegative]) {
return [modulo invertedNumber];
}
return modulo;
}

- 16,846
- 4
- 60
- 69
-
I think your conditional inversion of `modulo` at the end is unnecessary. `modulo` already carries the correct sign from the quotient. After removing the inversion and just returning `modulo` the results match Java's `BigDecimal.remainder` operator for all four combinations of dividend/divisor positive/negative. – Chris Hatton Feb 23 '23 at 02:10
Same solution in Swift 4:
let dividend = NSDecimalNumber(string: Price)
let divisor = NSDecimalNumber(decimal: 0.05)
let quotient = dividend.dividing(by: divisor, withBehavior: NSDecimalNumberHandler(roundingMode: .down, scale: 0, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false))
let subtractAmount = quotient?.multiplying(by: divisor)
let remainder = dividend.subtracting(anAmount)
if remainder != 0
{ ...

- 5,486
- 5
- 41
- 66

- 304
- 3
- 18
You could theoretically do some tricks with the NSDecimalNumber methods decimalNumberByDividingBy:
, decimalNumberByMultiplyingBy:
, and decimalValue
. Divide the numbers, grab the decimal number structure, figure out the remainder from the structure, then create a new decimal number with that remainder and multiply that remainder by the original number.
The easier way to do it, however, would probably be to figure out the maximum precision you want (call it N places after the decimal point), multiply the number by 10eN, then just grab the integer value and do your division and mod on that. You run the risk of losing data, especially with very large numbers, however, so check the biggest number you want and figure out what data type - if any - will work for you. NSNumber does support unsignedLongLongValue
.

- 59,527
- 19
- 156
- 165