iOS 兩個數(shù)相乘導致 NSDecimalNumber overflow exception 錯誤的分析及解決

先上一段代碼,這段代碼會導致overflow錯誤,使APP發(fā)生crash:

NSString *priceStr = @"";
NSDecimalNumber *number = [NSDecimalNumber decimalNumberWithString:priceStr];
NSDecimalNumber *countNum = [NSDecimalNumber decimalNumberWithString:stringWithNSInteger(NSIntegerMax)];
number = [number decimalNumberByMultiplyingBy:countNum];

在這段代碼中,number的值為:NaN,即:not a number ,非數(shù)值;
而countNum 是一個最大的整數(shù),
最后,將NaN和最大的整數(shù)相乘,導致了overflow的crash。

解決方案代碼如下:

//定義數(shù)值處理的行為
    NSDecimalNumberHandler *roundUp = [NSDecimalNumberHandler
                                      decimalNumberHandlerWithRoundingMode:NSRoundBankers
                                      scale:2
                                      raiseOnExactness:NO
                                      raiseOnOverflow:NO
                                      raiseOnUnderflow:NO
                                      raiseOnDivideByZero:NO];
    
    NSString *priceStr = @"";
    NSDecimalNumber *number = [NSDecimalNumber decimalNumberWithString:priceStr];
    NSDecimalNumber *countNum = [NSDecimalNumber decimalNumberWithString:stringWithNSInteger(NSIntegerMax)];

//使用數(shù)據(jù)處理行為的約定來進行運算,防止crash
    number = [number decimalNumberByMultiplyingBy:countNum withBehavior:roundUp];

上面這個例子不會crash了,但是最終number的值為NaN,需要后續(xù)的業(yè)務邏輯進行判斷處理;

NSDecimalNumberHandler 用到的參數(shù),其中:

NSRoundBankers

枚舉,截斷的方式;完整的定義如下:

// Rounding policies :
// Original
//    value 1.2  1.21  1.25  1.35  1.27
// Plain    1.2  1.2   1.3   1.4   1.3
// Down     1.2  1.2   1.2   1.3   1.2
// Up       1.2  1.3   1.3   1.4   1.3
// Bankers  1.2  1.2   1.2   1.4   1.3

typedef NS_ENUM(NSUInteger, NSRoundingMode) {
    NSRoundPlain,   // Round up on a tie
    NSRoundDown,    // Always down == truncate
    NSRoundUp,      // Always up
    NSRoundBankers  // on a tie round so last digit is even
};

scale

小數(shù)點后面的位數(shù)(精度)

raiseOnExactness

The exception raised if there is an exactness error.

raiseOnOverflow

是否拋出溢出錯誤,如果為YES,則APP會捕獲溢出錯誤,這會導致APPcrash;

The exception raised on overflow.

raiseOnUnderflow

The exception raised on underflow.

raiseOnDivideByZero

The exception raised on divide by zero.


補充知識:

  • 判斷一個數(shù)值是否為NaN可以使用系統(tǒng)方法:isnan(x);注:x為數(shù)值類型,不是NSDecimalNumber,更不是NSNumber;

  • 如果要判斷一個NSDecimalNumber 是否為 NAN ,則使用下面的方法:

    if([number isEqualToNumber:NSDecimalNumber.notANumber]){
        NSLog(@"number is nan");
    }else{
        NSLog(@"number:%@",number);
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容