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

≡放荡痞女 提交于 2019-12-21 12:16:29

问题


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?


回答1:


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];



回答2:


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;
}



回答3:


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




回答4:


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.




回答5:


Same solution in Swift 4:

    let dividend = NSDecimalNumber(string: Price)
    let divisor = NSDecimalNumber(decimal: 0.05)
    let quotient: NSDecimalNumber? = dividend.dividing(by: divisor, withBehavior: NSDecimalNumberHandler(roundingMode: .down, scale: 0, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false))
    let subtractAmount: NSDecimalNumber? = quotient?.multiplying(by: divisor)
    var remainder: NSDecimalNumber? = nil
    if let anAmount = subtractAmount {
        remainder = dividend.subtracting(anAmount)
    }


来源:https://stackoverflow.com/questions/1175595/how-do-you-get-the-int-and-modulo-mod-of-division-with-an-nsdecimalnumber

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!