Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you get the int and modulo (mod) of division with an NSDecimalNumber

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?

like image 344
Meltemi Avatar asked Jul 24 '09 03:07

Meltemi


3 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];
like image 50
adam Avatar answered Nov 03 '22 00:11

adam


  1. Divide the dividend by the divisor, rounding down. This gets you the quotient.
  2. Multiply the divisor by the quotient.
  3. 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.)

like image 6
Peter Hosey Avatar answered Nov 02 '22 23:11

Peter Hosey


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;
}
like image 6
Pascal Avatar answered Nov 03 '22 00:11

Pascal