場景:
我們在做金錢計算的時候會遇到一個問題,就是精確的問題,許多項目尤其是電商類項目都會涉及到,就是當(dāng)我們對價格用float或者double進行處理的時候,有的時候總是會出現(xiàn)一些誤差,還有就是假如我們精確小數(shù)點后面兩位,就有可能出現(xiàn)xxx.00或者xx.x0的問題,這些都是我們在處理價格的時候可能會遇到的坑!!而且涉及到錢的問題,不管什么app都要做到特別的精確,不能出現(xiàn)任何的誤差!
NSDecimalNumber簡介
顧名思義這是一個十進制數(shù)字類,繼承自NSNumber鞍陨,蘋果針對浮點類型計算精度問題提供出來的計算類碘裕,基于十進制的科學(xué)計數(shù)法來計算,同時可以指定舍入模式捕传,一般用于貨幣計算为迈。
非靜態(tài)初始化方法
/**
mantissa:長整形丹壕;
exponent:指數(shù);
flag:正負(fù)數(shù)沃疮。
**/
- (instancetype)initWithMantissa:(unsigned long long)mantissa exponent:(short)exponent isNegative:(BOOL)flag;
例子:
NSDecimalNumber *firstNumber = [[NSDecimalNumber alloc] initWithMantissa:1275 exponent:-3 isNegative:NO];//1.275
/**
NSDecimal是一個結(jié)構(gòu)體
typedef struct {
signed int _exponent:8;
unsigned int _length:4; // length == 0 && isNegative -> NaN
unsigned int _isNegative:1;
unsigned int _isCompact:1;
unsigned int _reserved:18;
unsigned short _mantissa[NSDecimalMaxSize];
} NSDecimal;
**/
- (instancetype)initWithDecimal:(NSDecimal)dcm NS_DESIGNATED_INITIALIZER;
例子:
NSDecimal asStruct = {2,1,0,0,1,8};
NSDecimalNumber *asNewObject = [[NSDecimalNumber alloc] initWithDecimal:asStruct];//800
/**
numericString:除了數(shù)字字符串,numericString可以包括一個“+”或“-”,一個“E”或“E”,用科學(xué)記數(shù)法表示一個數(shù)的指數(shù)
**/
- (instancetype)initWithString:(nullable NSString *)numberValue;
例子:
NSDecimalNumber *discountAmount = [[NSDecimalNumber alloc] initWithString:@"-25E3"];//-25000
/**
locale:一個NSLocaleDecimalSeparator劃分的部分?jǐn)?shù)的有效組成部分盒让。
**/
- (instancetype)initWithString:(nullable NSString *)numberValue locale:(nullable id)locale;
例子:
NSDictionary *locale = @{NSLocaleDecimalSeparator :@","};//以","當(dāng)做分隔符格式
NSDecimalNumber *discountAmount = [[NSDecimalNumber alloc] initWithString:@"123,40" locale:locale];//123.4
靜態(tài)初始化方法
+ (NSDecimalNumber *)decimalNumberWithMantissa:(unsigned long long)mantissa exponent:(short)exponent isNegative:(BOOL)flag;
+ (NSDecimalNumber *)decimalNumberWithDecimal:(NSDecimal)dcm;
+ (NSDecimalNumber *)decimalNumberWithString:(nullable NSString *)numberValue;
+ (NSDecimalNumber *)decimalNumberWithString:(nullable NSString *)numberValue locale:(nullable id)locale;
加:
- (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber;
//behavior:NSDecimalNumberHandler對象
- (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
例子:
NSDecimalNumber *oneNumber = [NSDecimalNumber decimalNumberWithString:@"1.5"];
NSDecimalNumber *twoNumber = [NSDecimalNumber decimalNumberWithString:@"3"];
NSDecimalNumber *resultNumber = [oneNumber decimalNumberByAdding:twoNumber];//4.5
減:
- (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)decimalNumber;
//behavior:NSDecimalNumberHandler對象
- (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
例子:
NSDecimalNumber *oneNumber = [NSDecimalNumber decimalNumberWithString:@"1.5"];
NSDecimalNumber *twoNumber = [NSDecimalNumber decimalNumberWithString:@"3"];
NSDecimalNumber *resultNumber = [twoNumber decimalNumberBySubtracting:oneNumber];//1.5
乘:
- (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)decimalNumber;
//behavior:NSDecimalNumberHandler對象
- (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
例子:
NSDecimalNumber *oneNumber = [NSDecimalNumber decimalNumberWithString:@"1.5"];
NSDecimalNumber *twoNumber = [NSDecimalNumber decimalNumberWithString:@"3"];
NSDecimalNumber *resultNumber = [oneNumber decimalNumberByMultiplyingBy:twoNumber];//4.5
除:
- (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)decimalNumber;
//behavior:NSDecimalNumberHandler對象
- (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
例子:
NSDecimalNumber *oneNumber = [NSDecimalNumber decimalNumberWithString:@"1.5"];
NSDecimalNumber *twoNumber = [NSDecimalNumber decimalNumberWithString:@"3"];
NSDecimalNumber *resultNumber = [twoNumber decimalNumberByDividingBy:oneNumber];//2
a的n次方:
- (NSDecimalNumber *)decimalNumberByRaisingToPower:(NSUInteger)power;
//behavior:NSDecimalNumberHandler對象
- (NSDecimalNumber *)decimalNumberByRaisingToPower:(NSUInteger)power withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
例子:
NSDecimalNumber *twoNumber = [NSDecimalNumber decimalNumberWithString:@"3"];
NSDecimalNumber *resultNumber = [twoNumber decimalNumberByRaisingToPower:3];//27
指數(shù)運算:
- (NSDecimalNumber *)decimalNumberByMultiplyingByPowerOf10:(short)power;
//behavior:NSDecimalNumberHandler對象
- (NSDecimalNumber *)decimalNumberByMultiplyingByPowerOf10:(short)power withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
例子:
NSDecimalNumber *twoNumber = [NSDecimalNumber decimalNumberWithString:@"3"];
NSDecimalNumber *resultNumber = [twoNumber decimalNumberByMultiplyingByPowerOf10:3];//3000
四舍五入運算:
//behavior:NSDecimalNumberHandler對象
- (NSDecimalNumber *)decimalNumberByRoundingAccordingToBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
例子:
NSDecimalNumber *oneNumber = [NSDecimalNumber decimalNumberWithString:@"1.5"];
NSDecimalNumber *resultNumber = [oneNumber decimalNumberByRoundingAccordingToBehavior:nil];//2
比較運算:
-(NSComparisonResult)compare:(NSNumber *)decimalNumber;
例子1:
NSDecimalNumber *oneNumber = [NSDecimalNumber decimalNumberWithString:@"1.5"];
NSDecimalNumber *twoNumber = [NSDecimalNumber decimalNumberWithString:@"3"];
NSComparisonResult comparisonResult = [oneNumber compare:@(twoNumber.floatValue)];//NSOrderedAscending
例子2:
NSDecimal discount1 = [[NSDecimalNumber decimalNumberWithString:@".85"] decimalValue];
NSDecimal discount2 = [[NSDecimalNumber decimalNumberWithString:@".9"] decimalValue];
NSComparisonResult result = NSDecimalCompare(&discount1, &discount2);//NSOrderedAscending
NSDecimalNumberHandler
這是一個NSDecimalNumber的公共協(xié)議處理類梅肤,可以設(shè)置舍入模式以及計算錯誤的處理;配合NSDecimalNumber來使用邑茄,將這個類的實例當(dāng)做NSDecimalNumber相應(yīng)API的參數(shù)來控制數(shù)字處理的結(jié)果姨蝴。
/**
初始化方法
@param roundingMode 舍入方式
@param scale 小數(shù)點后舍入值的位數(shù)。
@param exact 精度錯誤處理肺缕;YES:如果出現(xiàn)錯誤左医,將引發(fā)異常,NO:忽略錯誤并將控制權(quán)放回給調(diào)用者同木。
@param overflow 溢出錯誤處理浮梢;YES:如果出現(xiàn)錯誤,將引發(fā)異常彤路,NO:忽略錯誤并將控制權(quán)放回給調(diào)用者秕硝。
@param underflow 下溢錯誤處理;YES:如果出現(xiàn)錯誤洲尊,將引發(fā)異常远豺,NO:忽略錯誤并將控制權(quán)放回給調(diào)用者。
@param divideByZero 除以0的錯誤處理坞嘀;YES:如果出現(xiàn)錯誤憋飞,將引發(fā)異常,NO:忽略錯誤并將控制權(quán)放回給調(diào)用者姆吭。
@return NSDecimalNumberHandler對象
*/
+ (instancetype)decimalNumberHandlerWithRoundingMode:(NSRoundingMode)roundingMode
scale:(short)scale
raiseOnExactness:(BOOL)exact
raiseOnOverflow:(BOOL)overflow
raiseOnUnderflow:(BOOL)underflow
raiseOnDivideByZero:(BOOL)divideByZero
/**
快速構(gòu)造方法
roundingMode:NSRoundPlain
scale:全精度
exact:NO
overflow:NO
underflow:NO
divideByZero:NO
*/
+ (NSDecimalNumberHandler *)defaultDecimalNumberHandler;
NSRoundingMode的幾種方式:
- NSRoundPlain:四舍五入
- NSRoundDown:只舍不入
- NSRoundUp:只入不舍
- NSRoundBankers: 在四舍五入的基礎(chǔ)上加了一個判斷:當(dāng)最后一位為5的時候,只會舍入成偶數(shù)唁盏。比如:1.25不會返回1.3而是1.2内狸,因為1.3不是偶數(shù)。
image.png
NSDecimalNumber *oneNumber = [NSDecimalNumber decimalNumberWithString:@"1.567"];
NSDecimalNumberHandler *handlerTwo = [[NSDecimalNumberHandler alloc] initWithRoundingMode:NSRoundPlain scale:2 raiseOnExactness:NO raiseOnOverflow:YES raiseOnUnderflow:YES raiseOnDivideByZero:YES];
NSDecimalNumber *resultNumber = [oneNumber decimalNumberByRoundingAccordingToBehavior:handlerTwo];//1.57