iOS NSDecimalNumber的基本知识

一、简介

在iOS中需要精确计算时,double, float类型往往会出现不可预料的问题:
这里写代码片
这里写图片描述
在调试过程中可以看到 doule 类型 d3 在计算过程中值不是预计的9999.99。
如果在要用中计算涉及到金额等重要数据,不建议使用这种不可控结果的方式,可以采用iOS提供的另外一种支持准确精度计算的数据类型 NSDecimalNumber.
NSDecimalNumber是NSNumber的子类,比NSNumber的功能更为强大,可以指定一个数的幂,四舍五入等操作。由于NSDecimalNumber精度较高,所以会比基本数据类型费时,所以需要权衡考虑,苹果官方建议在货币以及要求精度很高的场景下使用。
所有NSDecimalNumber对象是不可变的,这意味着已经被创建后不能改变它们的值

二、NSDecimalNumber.h
NS_ASSUME_NONNULL_BEGIN

/***** Exceptions
*/

FOUNDATION_EXPORT NSString * const NSDecimalNumberExactnessException;
FOUNDATION_EXPORT NSString * const NSDecimalNumberOverflowException;
FOUNDATION_EXPORT NSString * const NSDecimalNumberUnderflowException;
FOUNDATION_EXPORT NSString * const NSDecimalNumberDivideByZeroException;

/***** Rounding and Exception behavior
*/

@class NSDecimalNumber;

@protocol NSDecimalNumberBehaviors

  • (NSRoundingMode)roundingMode;

  • (short)scale;
    // The scale could return NO_SCALE for no defined scale.

  • (nullable NSDecimalNumber )exceptionDuringOperation:(SEL)operation error:(NSCalculationError)error leftOperand:(NSDecimalNumber )leftOperand rightOperand:(nullable NSDecimalNumber *)rightOperand;
    // Receiver can raise, return a new value, or return nil to ignore the exception.

@end

/***** NSDecimalNumber: the class
*/

@interface NSDecimalNumber : NSNumber {
@private
signed int _exponent:8;
unsigned int _length:4;
unsigned int _isNegative:1;
unsigned int _isCompact:1;
unsigned int _reserved:1;
unsigned int _hasExternalRefCount:1;
unsigned int _refs:16;
unsigned short _mantissa[0]; /* GCC */
}

  • (instancetype)initWithMantissa:(unsigned long long)mantissa exponent:(short)exponent isNegative:(BOOL)flag;
  • (instancetype)initWithDecimal:(NSDecimal)dcm NS_DESIGNATED_INITIALIZER;
  • (instancetype)initWithString:(nullable NSString *)numberValue;
  • (instancetype)initWithString:(nullable NSString *)numberValue locale:(nullable id)locale;

  • (NSString *)descriptionWithLocale:(nullable id)locale;

@property (readonly) NSDecimal decimalValue;
/*
以 -a×10ⁿ 为例:
mantissa:无符号长整型。表示a
exponent:短整形。幂级数n
flag:符号,YES:前面带负号。-a×10ⁿ
NO:前面无符号。a×10ⁿ
eg:
NSDecimalNumber*num20=[NSDecimalNumber decimalNumberWithMantissa:12 exponent:2 isNegative:YES];//-1200
NSDecimalNumber*num21=[NSDecimalNumber decimalNumberWithMantissa:12 exponent:2 isNegative:NO];//1200
NSDecimalNumber*num22=[NSDecimalNumber decimalNumberWithMantissa:12.6 exponent:2 isNegative:YES];//-1200
NSDecimalNumber*num23=[NSDecimalNumber decimalNumberWithMantissa:12.6 exponent:2 isNegative:NO];//1200
*/
+ (NSDecimalNumber *)decimalNumberWithMantissa:(unsigned long long)mantissa exponent:(short)exponent isNegative:(BOOL)flag;
+ (NSDecimalNumber *)decimalNumberWithDecimal:(NSDecimal)dcm;
//字符串值转NSDecimalNumber
+ (NSDecimalNumber )decimalNumberWithString:(nullable NSString )numberValue;
+ (NSDecimalNumber )decimalNumberWithString:(nullable NSString )numberValue locale:(nullable id)locale;

  • (NSDecimalNumber *)zero;//0
  • (NSDecimalNumber *)one;//1
  • (NSDecimalNumber *)minimumDecimalNumber;//平台所能表达的最小数(有符号)
  • (NSDecimalNumber *)maximumDecimalNumber;//平台所能表达的最大数(有符号)
  • (NSDecimalNumber *)notANumber;
    //加法运算
  • (NSDecimalNumber )decimalNumberByAdding:(NSDecimalNumber )decimalNumber;
  • (NSDecimalNumber )decimalNumberByAdding:(NSDecimalNumber )decimalNumber withBehavior:(nullable id )behavior;
    //减法运算
  • (NSDecimalNumber )decimalNumberBySubtracting:(NSDecimalNumber )decimalNumber;
  • (NSDecimalNumber )decimalNumberBySubtracting:(NSDecimalNumber )decimalNumber withBehavior:(nullable id )behavior;
    //乘法运算
  • (NSDecimalNumber )decimalNumberByMultiplyingBy:(NSDecimalNumber )decimalNumber;
  • (NSDecimalNumber )decimalNumberByMultiplyingBy:(NSDecimalNumber )decimalNumber withBehavior:(nullable id )behavior;
    //除法运算
  • (NSDecimalNumber )decimalNumberByDividingBy:(NSDecimalNumber )decimalNumber;
  • (NSDecimalNumber )decimalNumberByDividingBy:(NSDecimalNumber )decimalNumber withBehavior:(nullable id )behavior;
    //power次幂计算(power表示几次幂)
  • (NSDecimalNumber *)decimalNumberByRaisingToPower:(NSUInteger)power;
  • (NSDecimalNumber *)decimalNumberByRaisingToPower:(NSUInteger)power withBehavior:(nullable id )behavior;
    //乘以10的power次幂(power表示幂级)
  • (NSDecimalNumber *)decimalNumberByMultiplyingByPowerOf10:(short)power;
  • (NSDecimalNumber *)decimalNumberByMultiplyingByPowerOf10:(short)power withBehavior:(nullable id )behavior;

//指定一些有效信息,例如四舍五入的情况,小数后保留位数的情况以及数据溢出或除以零的情况等。这里写代码片
- (NSDecimalNumber *)decimalNumberByRoundingAccordingToBehavior:(nullable id )behavior;

//比较(返回NSComparisonResult的枚举值)
- (NSComparisonResult)compare:(NSNumber *)decimalNumber;

  • (void)setDefaultBehavior:(id )behavior;

  • (id )defaultBehavior;
    // One behavior per thread - The default behavior is
    // rounding mode: NSRoundPlain
    // scale: No defined scale (full precision)
    // ignore exactnessException
    // raise on overflow, underflow and divide by zero.

@property (readonly) const char *objCType NS_RETURNS_INNER_POINTER;
// return ‘d’ for double

@property (readonly) double doubleValue;
// return an approximate double value

@end
/*******************A class for defining common behaviors ***********************************/
//用于指定一些有效信息,例如四舍五入的情况,小数后保留位数的情况以及数据溢出或除以零的情况等。
//当exact,overflow,underflow,divideByZero为NO时,在出现上溢,下溢,除数为零时,返回NaN(可能是notANumber的意思),程序不会崩溃。
//当值为YES时,出现对应的情况程序直接崩掉。
@interface NSDecimalNumberHandler : NSObject

@private
signed int _scale:16;
unsigned _roundingMode:3;
unsigned _raiseOnExactness:1;
unsigned _raiseOnOverflow:1;
unsigned _raiseOnUnderflow:1;
unsigned _raiseOnDivideByZero:1;
unsigned _unused:9;
void *_reserved2;
void *_reserved;
}
+ (NSDecimalNumberHandler *)defaultDecimalNumberHandler;
// rounding mode: NSRoundPlain
// scale: No defined scale (full precision)
// ignore exactnessException (return nil)
// raise on overflow, underflow and divide by zero.
- (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;

@end

/*********************************Extensions to other classes****************************/
@interface NSNumber (NSDecimalNumberExtensions)

@property (readonly) NSDecimal decimalValue;
// Could be silently inexact for float and double.
@end

@interface NSScanner (NSDecimalNumberScanning)

  • (BOOL)scanDecimal:(nullable NSDecimal *)dcm;

@end

NS_ASSUME_NONNULL_END

三、用法
(1)四舍五入截取指定小数位的值
//四舍五入截取指定小数位的值(price:目标数据 position:有效小数位), 返回截取后数据

/*
typedef NS_ENUM(NSUInteger, NSRoundingMode) {
NSRoundPlain, //用于四舍五入
NSRoundDown, //只舍不入
NSRoundUp, //不舍只入
NSRoundBankers //。。。取最精确的,当遇到5时,舍和入是一样的,所以可以有两个值。(待指教)
};
*/
+(NSString *)notRounding:(float)price afterPoint:(NSInteger)position
{
NSDecimalNumberHandler* roundingBehavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain scale:position raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];
NSDecimalNumber *ouncesDecimal;
NSDecimalNumber *roundedOunces;

ouncesDecimal = [[NSDecimalNumber alloc] initWithFloat:price];
roundedOunces = [ouncesDecimal decimalNumberByRoundingAccordingToBehavior:roundingBehavior];
return [NSString stringWithFormat:@"%@",roundedOunces];

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值