【问题标题】:How do you get the int and modulo (mod) of division with an NSDecimalNumber您如何使用 NSDecimalNumber 获得除法的 int 和模(mod)
【发布时间】:2009-07-24 03:20:27
【问题描述】:

我对 NSDecimalNumber 及其“行为”感到困惑。我有一个代表美元价值的 NSDecimalNumber,比如 37.50 美元。我想知道有多少次说 5.0 进入那个数字,然后知道剩下的是什么。我可以得到直接除法并得到 7.50,但我想要 7 mod 2.50。我可以转换为整数,但需要保存“美分”,所以想知道框架中是否有一些技巧?

【问题讨论】:

    标签: objective-c cocoa cocoa-touch nsnumber


    【解决方案1】:

    使用 Peter Hoseys 示例,但使用 iOS 代码:

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

    【讨论】:

    • 如果被除数或除数之一为负数,则必须设置右舍入模式。 NSRoundingMode roundingMode = ((dividend.floatValue < 0) ^ (divisor.floatValue < 0)) ? NSRoundUp : NSRoundDown;
    【解决方案2】:
    1. 将被除数除以除数,向下取整。这会让你得到商数。
    2. 除数乘以商。
    3. 从股息中减去。剩下的就交给你了。

    (37.50 // 5) == 7; 7 * 5 == 35; 37.50 - 35 = 2.50。

    (注意:// 是 Python 的整数除法运算符。我在这里借用了它。显然,您实际上不应该尝试在 Objective-C 代码中使用 // 进行除法。)

    【讨论】:

    • 要向下舍入,请使用 math.h 中的 floor() - 它需要一个双精度并返回一个双精度。
    • 如果您使用十进制数,请尽量保持在该类型范围内。即,舍入使用 decimalNumberByRoundingAccordingToBehavior:.
    • 更好的是,使用decimalNumberByDividingBy:withBehavior: 进行除法。那么就不需要单独四舍五入了。
    • 请注意,这不适用于负除数或负除数。我在下面发布了一个NSDecimalNumber 类别来处理这些情况。
    【解决方案3】:

    这是一个NSDecimalNumber 类别,它也适用于负数和负除数:

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

    【讨论】:

      【解决方案4】:

      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】:

        理论上,您可以使用 NSDecimalNumber 方法 decimalNumberByDividingBy:decimalNumberByMultiplyingBy:decimalValue 做一些技巧。将数字相除,获取十进制数结构,从结构中找出余数,然后用该余数创建一个新的十进制数,并将该余数乘以原始数。

        然而,更简单的方法可能是计算出您想要的最大精度(称为小数点后 N 位),将数字乘以 10eN,然后获取整数值并进行除法并对此进行修改。但是,您冒着丢失数据的风险,尤其是对于非常大的数字,因此请检查您想要的最大数字并找出适合您的数据类型(如果有的话)。 NSNumber 确实支持unsignedLongLongValue

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-10-29
          • 1970-01-01
          • 2010-10-28
          • 2011-08-01
          • 2023-03-18
          • 2013-06-02
          • 2019-03-24
          • 1970-01-01
          相关资源
          最近更新 更多