關(guān)于NSDecimalNumber
// Immutable with no mutable subclasses
@interface NSDecimalNumber : NSNumber
NSDecimalNumber屬于NSNumber的一個子類锤悄,并且是不可變的
官方介紹
NSDecimalNumber, an immutable subclass of NSNumber, provides an object-oriented wrapper for doing base-10 arithmetic. An instance can represent any number that can be expressed as mantissa x 10^exponent where mantissa is a decimal integer up to 38 digits long, and exponent is an integer from –128 through 127.
翻譯一下
NSDecimalNumber是NSNumber的一個不可變子類隔盛,它提供了一個面向?qū)ο蟮陌b器衙傀,用于執(zhí)行10進制算術(shù)。實例可以表示任何可以表示為尾數(shù)x 10^指數(shù)的數(shù)字被济,其中尾數(shù)是長達38位的十進制整數(shù)偷崩,指數(shù)是從-128到127的整數(shù)谴古。
說白了,就是用于高精度計算
NSDecimalNumber初始化
實例方法初始化
// 使用給定的尾數(shù)认罩、指數(shù)和符號初始化十進制數(shù)箱蝠。
- (instancetype)initWithMantissa:(unsigned long long)mantissa exponent:(short)exponent isNegative:(BOOL)flag;
// 初始化十進制數(shù)以表示給定的十進制數(shù)。
- (instancetype)initWithDecimal:(NSDecimal)dcm NS_DESIGNATED_INITIALIZER;
// 初始化十進制數(shù),使其值等價于給定數(shù)字字符串中的值宦搬。
- (instancetype)initWithString:(nullable NSString *)numberValue;
- (instancetype)initWithString:(nullable NSString *)numberValue locale:(nullable id)locale;
類方法初始化
// 使用給定的尾數(shù)牙瓢、指數(shù)和符號初始化十進制數(shù)。
+ (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;
這么幾個初始化方法间校,看著還是這兩個實用
- (instancetype)initWithString:(nullable NSString *)numberValue;
+ (NSDecimalNumber *)decimalNumberWithString:(nullable NSString *)numberValue;
NSDecimalNumber運算
系統(tǒng)方法中提供了6種運算方式矾克,分別為
// 加
- (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber;
- (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
// 減
- (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)decimalNumber;
- (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
// 乘
- (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)decimalNumber;
- (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
// 除
- (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)decimalNumber;
- (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
// 冪次方
- (NSDecimalNumber *)decimalNumberByRaisingToPower:(NSUInteger)power;
- (NSDecimalNumber *)decimalNumberByRaisingToPower:(NSUInteger)power withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
// 指數(shù)
- (NSDecimalNumber *)decimalNumberByMultiplyingByPowerOf10:(short)power;
- (NSDecimalNumber *)decimalNumberByMultiplyingByPowerOf10:(short)power withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;
關(guān)于NSDecimalNumberBehaviors這個協(xié)議,看看官方解釋
A protocol that declares three methods that control the discretionary aspects of working with decimal numbers.
The scale and roundingMode methods determine the precision of NSDecimalNumber’s return values and the way in which those values should be rounded to fit that precision. The exceptionDuringOperation:error:leftOperand:rightOperand: method determines the way in which an NSDecimalNumber object should handle different calculation errors.
For an example of a class that adopts the NSDecimalBehaviors protocol, see the specification for NSDecimalNumberHandler.
scale和roundingMode方法決定了NSDecimalNumber返回值的精度憔足,以及這些值應該四舍五入以適應該精度的方式胁附。方法決定了NSDecimalNumber對象處理不同計算錯誤的方式。
有關(guān)采用NSDecimalBehaviors協(xié)議的類的示例四瘫,請參閱NSDecimalNumberHandler的規(guī)范汉嗽。
意思就是,NSDecimalNumberBehaviors這個東西可以控制數(shù)字的舍取方式找蜜,和保留的小數(shù)位數(shù)
再看看NSDecimalNumberHandler這個饼暑,官方解釋
A class that adopts the decimal number behaviors protocol.// 采用十進制數(shù)字行為協(xié)議的類。
This class allows you to set the way an NSDecimalNumber object rounds off and handles errors, without having to create a custom class.
You can use an instance of this class as an argument to any of the NSDecimalNumber methods that end with ...Behavior:. If you don’t think you need special behavior, you probably don’t need this class—it is likely that NSDecimalNumber's default behavior will suit your needs.
這個類允許你設置NSDecimalNumber對象舍入和處理錯誤的方式洗做,而不需要創(chuàng)建一個自定義類弓叛。
你可以使用這個類的實例作為任何以…行為結(jié)尾的NSDecimalNumber方法的參數(shù)。如果你認為你不需要特殊的行為诚纸,你可能不需要這個類——NSDecimalNumber的默認行為很可能會滿足你的需求撰筷。
說白了,就是系統(tǒng)給了你一個NSDecimalNumberBehaviors協(xié)議的實例畦徘,直接用這個去實現(xiàn)NSDecimalNumberBehaviors協(xié)議就行了
// 默認的規(guī)則
/*
rounding mode :NSRoundPlain
scale :全精度(是多少位小數(shù)就是多少位)
忽略異常情況
*/
@property (class, readonly, strong) NSDecimalNumberHandler *defaultDecimalNumberHandler;
// 自定義舍取模式毕籽,保留的小數(shù)位數(shù),是否拋溢出等情況
- (instancetype)initWithRoundingMode:(NSRoundingMode)roundingMode scale:(short)scale raiseOnExactness:(BOOL)exact raiseOnOverflow:(BOOL)overflow raiseOnUnderflow:(BOOL)underflow raiseOnDivideByZero:(BOOL)divideByZero NS_DESIGNATED_INITIALIZER;
+ (instancetype)decimalNumberHandlerWithRoundingMode:(NSRoundingMode)roundingMode scale:(short)scale raiseOnExactness:(BOOL)exact raiseOnOverflow:(BOOL)overflow raiseOnUnderflow:(BOOL)underflow raiseOnDivideByZero:(BOOL)divideByZero;
舉個??
// 保留兩位小數(shù)井辆,四舍五入
NSDecimalNumberHandler *handler = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode: NSRoundPlain
scale:2
raiseOnExactness:NO
raiseOnOverflow:NO
raiseOnUnderflow:NO
raiseOnDivideByZero:YES];
這個類介紹完了关筒,接下來就是進行封裝
NSDecimalNumber封裝
說是封裝,還不如說就是把調(diào)用簡化一下
為了方便這里創(chuàng)建一個NSString的分類杯缺,直接將字符串轉(zhuǎn)換成NSDecimalNumber類型的
// .h
/// 轉(zhuǎn)換為NSDecimalNumber數(shù)據(jù)
@property (nonatomic, copy, readonly) NSDecimalNumber *decimalValue;
// .m
- (NSDecimalNumber *)decimalValue {
return [NSDecimalNumber decimalNumberWithString:self];
}
思想是用函數(shù)式編程來實現(xiàn)
首先創(chuàng)建一個NSDecimalNumber的分類就叫DecimalNumber
然后定義一些屬性分別處理加蒸播、減、乘萍肆、除袍榆、冪次方、指數(shù)塘揣、舍入方式
NSDecimalNumber+DecimalNumber.h
/// 加
@property (nonatomic, copy, readonly) NSDecimalNumber *_Nullable(^add)(id number);
/// 減
@property (nonatomic, copy, readonly) NSDecimalNumber *_Nullable(^reduce)(id number);
/// 乘
@property (nonatomic, copy, readonly) NSDecimalNumber *_Nullable(^multiplied)(id number);
/// 除 如果除數(shù)為0包雀,返回自身
@property (nonatomic, copy, readonly) NSDecimalNumber *_Nullable(^divide)(id number);
/// 冪次方
@property (nonatomic, copy, readonly) NSDecimalNumber *_Nullable(^raising)(NSUInteger power);
/// 指數(shù)
@property (nonatomic, copy, readonly) NSDecimalNumber *_Nullable(^multiplyingByPower)(short power);
/// 舍入
@property (nonatomic, copy, readonly) NSDecimalNumber *_Nullable(^rounding)(NSRoundingMode roundingMode, short scale);
NSDecimalNumber+DecimalNumber.m
/// 加
- (NSDecimalNumber * _Nullable (^)(id _Nonnull))add {
return ^NSDecimalNumber *(id number){
if ([number isKindOfClass:[NSDecimalNumber class]]) {
return [self decimalNumberByAdding:(NSDecimalNumber *)number];
} else if ([number isKindOfClass:[NSString class]]) {
return [self decimalNumberByAdding:((NSString *)number).decimalValue];
} else {
return [self decimalNumberByAdding:[number stringValue].decimalValue];
}
};
}
/// 減
- (NSDecimalNumber * _Nullable (^)(id _Nonnull))reduce {
return ^NSDecimalNumber *(id number){
if ([number isKindOfClass:[NSDecimalNumber class]]) {
return [self decimalNumberBySubtracting:(NSDecimalNumber *)number];
} else if ([number isKindOfClass:[NSString class]]) {
return [self decimalNumberBySubtracting:((NSString *)number).decimalValue];
} else {
return [self decimalNumberBySubtracting:[number stringValue].decimalValue];
}
};
}
/// 乘
- (NSDecimalNumber * _Nullable (^)(id _Nonnull))multiplied {
return ^NSDecimalNumber *(id number){
if ([number isKindOfClass:[NSDecimalNumber class]]) {
return [self decimalNumberByMultiplyingBy:(NSDecimalNumber *)number];
} else if ([number isKindOfClass:[NSString class]]) {
return [self decimalNumberByMultiplyingBy:((NSString *)number).decimalValue];
} else {
return [self decimalNumberByMultiplyingBy:[number stringValue].decimalValue];
}
};
}
/// 除
- (NSDecimalNumber * _Nullable (^)(id _Nonnull))divide {
return ^NSDecimalNumber *(id number){
if ([number isKindOfClass:[NSDecimalNumber class]]) {
return [self decimalNumberByDividingBy:(NSDecimalNumber *)number];
} else if ([number isKindOfClass:[NSString class]]) {
return [self decimalNumberByDividingBy:((NSString *)number).decimalValue];
} else {
return [self decimalNumberByDividingBy:[number stringValue].decimalValue];
}
};
}
/// 冪次方
- (NSDecimalNumber * _Nullable (^)(NSUInteger))raising {
return ^NSDecimalNumber *(NSUInteger power){
return [self decimalNumberByRaisingToPower:power];
};
}
/// 指數(shù)
- (NSDecimalNumber * _Nullable (^)(short))multiplyingByPower {
return ^NSDecimalNumber *(short power){
return [self decimalNumberByMultiplyingByPowerOf10:power];
};
}
/// 舍取方式
- (NSDecimalNumber * _Nullable (^)(NSRoundingMode, short))rounding {
return ^NSDecimalNumber *(NSRoundingMode roundingMode, short scale){
NSDecimalNumberHandler *handler = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:roundingMode
scale:scale
raiseOnExactness:NO
raiseOnOverflow:NO
raiseOnUnderflow:NO
raiseOnDivideByZero:YES];
return [self decimalNumberByRoundingAccordingToBehavior:handler];
};
}
這樣就簡單的封裝好了
接下來看看使用
NSDecimalNumber *number = @"10.15".decimalValue;
NSDecimalNumber *newNumber = number.add(@"10.015").reduce(@"0.005").multiplied(@"1.01").divide(@"10").rounding(NSRoundPlain, 2);
解釋:(10.15 + 10.015 - 0.005) x 1.01 / 10的結(jié)果保留兩位小數(shù)四舍五入
結(jié)果:2.040000
DecimalNumber[10561:175487] 2.040000
有需要的,麻煩點個贊亲铡,謝謝
完整代碼
NSDecimalNumber+DecimalNumber.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSString (DecimalNumber)
/// 轉(zhuǎn)換為NSDecimalNumber數(shù)據(jù)
@property (nonatomic, copy, readonly) NSDecimalNumber *decimalValue;
@end
@interface NSDecimalNumber (DecimalNumber)
/// 加
@property (nonatomic, copy, readonly) NSDecimalNumber *_Nullable(^add)(id number);
/// 減
@property (nonatomic, copy, readonly) NSDecimalNumber *_Nullable(^reduce)(id number);
/// 乘
@property (nonatomic, copy, readonly) NSDecimalNumber *_Nullable(^multiplied)(id number);
/// 除 如果除數(shù)為0馏艾,返回自身
@property (nonatomic, copy, readonly) NSDecimalNumber *_Nullable(^divide)(id number);
/// 冪次方
@property (nonatomic, copy, readonly) NSDecimalNumber *_Nullable(^raising)(NSUInteger power);
/// 指數(shù)
@property (nonatomic, copy, readonly) NSDecimalNumber *_Nullable(^multiplyingByPower)(short power);
/// 舍入
@property (nonatomic, copy, readonly) NSDecimalNumber *_Nullable(^rounding)(NSRoundingMode roundingMode, short scale);
@end
NS_ASSUME_NONNULL_END
NSDecimalNumber+DecimalNumber.m
#import "NSDecimalNumber+DecimalNumber.h"
@implementation NSString (DecimalNumber)
- (NSDecimalNumber *)decimalValue {
return [NSDecimalNumber decimalNumberWithString:self];
}
@end
@implementation NSDecimalNumber (DecimalNumber)
/// 加
- (NSDecimalNumber * _Nullable (^)(id _Nonnull))add {
return ^NSDecimalNumber *(id number){
if ([number isKindOfClass:[NSDecimalNumber class]]) {
return [self decimalNumberByAdding:(NSDecimalNumber *)number];
} else if ([number isKindOfClass:[NSString class]]) {
return [self decimalNumberByAdding:((NSString *)number).decimalValue];
} else {
return [self decimalNumberByAdding:[number stringValue].decimalValue];
}
};
}
/// 減
- (NSDecimalNumber * _Nullable (^)(id _Nonnull))reduce {
return ^NSDecimalNumber *(id number){
if ([number isKindOfClass:[NSDecimalNumber class]]) {
return [self decimalNumberBySubtracting:(NSDecimalNumber *)number];
} else if ([number isKindOfClass:[NSString class]]) {
return [self decimalNumberBySubtracting:((NSString *)number).decimalValue];
} else {
return [self decimalNumberBySubtracting:[number stringValue].decimalValue];
}
};
}
/// 乘
- (NSDecimalNumber * _Nullable (^)(id _Nonnull))multiplied {
return ^NSDecimalNumber *(id number){
if ([number isKindOfClass:[NSDecimalNumber class]]) {
return [self decimalNumberByMultiplyingBy:(NSDecimalNumber *)number];
} else if ([number isKindOfClass:[NSString class]]) {
return [self decimalNumberByMultiplyingBy:((NSString *)number).decimalValue];
} else {
return [self decimalNumberByMultiplyingBy:[number stringValue].decimalValue];
}
};
}
/// 除
- (NSDecimalNumber * _Nullable (^)(id _Nonnull))divide {
return ^NSDecimalNumber *(id number){
if ([number isKindOfClass:[NSDecimalNumber class]]) {
return [self decimalNumberByDividingBy:(NSDecimalNumber *)number];
} else if ([number isKindOfClass:[NSString class]]) {
return [self decimalNumberByDividingBy:((NSString *)number).decimalValue];
} else {
return [self decimalNumberByDividingBy:[number stringValue].decimalValue];
}
};
}
/// 冪次方
- (NSDecimalNumber * _Nullable (^)(NSUInteger))raising {
return ^NSDecimalNumber *(NSUInteger power){
return [self decimalNumberByRaisingToPower:power];
};
}
/// 指數(shù)
- (NSDecimalNumber * _Nullable (^)(short))multiplyingByPower {
return ^NSDecimalNumber *(short power){
return [self decimalNumberByMultiplyingByPowerOf10:power];
};
}
/// 舍取方式
- (NSDecimalNumber * _Nullable (^)(NSRoundingMode, short))rounding {
return ^NSDecimalNumber *(NSRoundingMode roundingMode, short scale){
NSDecimalNumberHandler *handler = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:roundingMode
scale:scale
raiseOnExactness:NO
raiseOnOverflow:NO
raiseOnUnderflow:NO
raiseOnDivideByZero:YES];
return [self decimalNumberByRoundingAccordingToBehavior:handler];
};
}
@end