由于后台接口返回的和金额相关的字段是NSString类型,这时候就遇到了NSString类型数据转换成float或double类型时,会丢失精度。为了数据计算不失真确保精度,使用了NSDecimalNumber,并且写了(NSString+DecimalsCalculation)分类方便使用。
NSString+DecimalsCalculation.h
// NSString+DecimalsCalculation.h
//
// Created by YXY on 2017/11/13.
// Copyright © 2017年 Techwis. All rights reserved.
#import <Foundation/Foundation.h>
/**
// 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, // 四舍五入
NSRoundDown, // 向下取舍
NSRoundUp, // 向上入
NSRoundBankers // 同四舍五入。但是当需要进位的数字是5时根据前一位的奇偶性,奇数向上取值、偶数向下取值
};
*/
@interface NSString (DecimalsCalculation)
// 加
/**
加法计算,默认保留两位小数,默认采用四舍五入的方式处理计算结果,
roundingModel决定四舍五入的方式,scale决定保留小数个数
@param stringNumber 被加数
@return 返回结果
*/
- (NSString *)yxy_stringByAdding:(NSString *)stringNumber;
- (NSString *)yxy_stringByAdding:(NSString *)stringNumber withRoundingMode:(NSRoundingMode)roundingModel;
- (NSString *)yxy_stringByAdding:(NSString *)stringNumber withRoundingMode:(NSRoundingMode)roundingModel scale:(NSInteger)scale;
// 减
/**
减法计算,默认保留两位小数,默认采用四舍五入的方式处理计算结果
roundingModel决定四舍五入的方式,scale决定保留小数个数
@param stringNumber 减数
@return 返回结果
*/
- (NSString *)yxy_stringBySubtracting:(NSString *)stringNumber;
- (NSString *)yxy_stringBySubtracting:(NSString *)stringNumber withRoundingMode:(NSRoundingMode)roundingModel;
- (NSString *)yxy_stringBySubtracting:(NSString *)stringNumber withRoundingMode:(NSRoundingMode)roundingModel scale:(NSInteger)scale;
// 乘
/**
乘法计算,默认保留两位小数,默认采用四舍五入的方式处理计算结果
roundingModel决定四舍五入的方式,scale决定保留小数个数
@param stringNumber 减数
@return 返回结果
*/
- (NSString *)yxy_stringByMultiplyingBy:(NSString *)stringNumber;
- (NSString *)yxy_stringByMultiplyingBy:(NSString *)stringNumber withRoundingMode:(NSRoundingMode)roundingModel;
- (NSString *)yxy_stringByMultiplyingBy:(NSString *)stringNumber withRoundingMode:(NSRoundingMode)roundingModel scale:(NSInteger)scale;
// 除
/**
除法计算,默认保留两位小数,默认采用四舍五入的方式处理计算结果
roundingModel决定四舍五入的方式,scale决定保留小数个数
@param stringNumber 减数
@return 返回结果
*/
- (NSString *)yxy_stringByDividingBy:(NSString *)stringNumber;
- (NSString *)yxy_stringByDividingBy:(NSString *)stringNumber withRoundingMode:(NSRoundingMode)roundingModel;
- (NSString *)yxy_stringByDividingBy:(NSString *)stringNumber withRoundingMode:(NSRoundingMode)roundingModel scale:(NSInteger)scale;
/**
比较两个字符串大小
@return 返回结果
*/
- (NSComparisonResult )yxy_comparey:(NSString *)stringNumber;
// 不四舍五入
- (NSString *)yxy_notRoundingAfterPoint:( NSInteger )position;
@end
NSString+DecimalsCalculation.m
// NSString+DecimalsCalculation.m
// YXYDecimalNumberHandler
//
// Created by YXY on 2017/11/13.
// Copyright © 2017年 Techwis. All rights reserved.
//
#import "NSString+DecimalsCalculation.h"
// CalculationType
typedef NS_ENUM(NSInteger,CalculationType){
CalculationAdding,
CalculationSubtracting,
CalculationMultiplying,
CalculationDividing,
};
@implementation NSString (DecimalsCalculation)
// Adding
- (NSString *)yxy_stringByAdding:(NSString *)stringNumber {
return [self yxy_stringByAdding:stringNumber withRoundingMode:NSRoundPlain scale:2];
}
- (NSString *)yxy_stringByAdding:(NSString *)stringNumber withRoundingMode:(NSRoundingMode)roundingModel {
return [self yxy_stringByAdding:stringNumber withRoundingMode:roundingModel scale:2];
}
- (NSString *)yxy_stringByAdding:(NSString *)stringNumber withRoundingMode:(NSRoundingMode)roundingModel scale:(NSInteger)scale {
return [self stringByCalculationType:CalculationAdding by:stringNumber roundingMode:roundingModel scale:scale];
}
// Substracting
- (NSString *)yxy_stringBySubtracting:(NSString *)stringNumber {
return [self yxy_stringBySubtracting:stringNumber withRoundingMode:NSRoundPlain scale:2];
}
- (NSString *)yxy_stringBySubtracting:(NSString *)stringNumber withRoundingMode:(NSRoundingMode)roundingModel {
return [self yxy_stringBySubtracting:stringNumber withRoundingMode:roundingModel scale:2];
}
- (NSString *)yxy_stringBySubtracting:(NSString *)stringNumber withRoundingMode:(NSRoundingMode)roundingModel scale:(NSInteger)scale {
return [self stringByCalculationType:CalculationSubtracting by:stringNumber roundingMode:roundingModel scale:scale];
}
// Multiplying
- (NSString *)yxy_stringByMultiplyingBy:(NSString *)stringNumber {
return [self yxy_stringByMultiplyingBy:stringNumber withRoundingMode:NSRoundPlain scale:2];
}
- (NSString *)yxy_stringByMultiplyingBy:(NSString *)stringNumber withRoundingMode:(NSRoundingMode)roundingModel {
return [self yxy_stringByMultiplyingBy:stringNumber withRoundingMode:roundingModel scale:2];
}
- (NSString *)yxy_stringByMultiplyingBy:(NSString *)stringNumber withRoundingMode:(NSRoundingMode)roundingModel scale:(NSInteger)scale {
return [self stringByCalculationType:CalculationMultiplying by:stringNumber roundingMode:roundingModel scale:scale];
}
// Dividing
- (NSString *)yxy_stringByDividingBy:(NSString *)stringNumber {
return [self yxy_stringByDividingBy:stringNumber withRoundingMode:NSRoundPlain scale:2];
}
- (NSString *)yxy_stringByDividingBy:(NSString *)stringNumber withRoundingMode:(NSRoundingMode)roundingModel {
return [self yxy_stringByDividingBy:stringNumber withRoundingMode:roundingModel scale:2];
}
- (NSString *)yxy_stringByDividingBy:(NSString *)stringNumber withRoundingMode:(NSRoundingMode)roundingModel scale:(NSInteger)scale {
return [self stringByCalculationType:CalculationDividing by:stringNumber roundingMode:roundingModel scale:scale];
}
- (NSString *)stringByCalculationType:(CalculationType)type by:(NSString *)stringNumber roundingMode:(NSRoundingMode)roundingModel scale:(NSUInteger)scale{
NSDecimalNumber *selfNumber = [NSDecimalNumber decimalNumberWithString:self];
NSDecimalNumber *calcuationNumber = [NSDecimalNumber decimalNumberWithString:stringNumber];
NSDecimalNumberHandler *handler = [[NSDecimalNumberHandler alloc] initWithRoundingMode:roundingModel scale:scale raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:YES];
NSDecimalNumber *result = nil;
switch (type) {
case CalculationAdding:
result = [selfNumber decimalNumberByAdding:calcuationNumber withBehavior:handler];
break;
case CalculationSubtracting:
result = [selfNumber decimalNumberBySubtracting:calcuationNumber withBehavior:handler];
break;
case CalculationMultiplying:
result = [selfNumber decimalNumberByMultiplyingBy:calcuationNumber withBehavior:handler];
break;
case CalculationDividing:
result =[selfNumber decimalNumberByDividingBy:calcuationNumber withBehavior:handler];
break;
}
// 如果自定义了结果格式化工具使用自定义formatter
NSNumberFormatter *numberFormatter = [self numberFormatterWithScale:scale];
return [numberFormatter stringFromNumber:result];
}
- (NSNumberFormatter *)numberFormatterWithScale:(NSInteger)scale{
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
numberFormatter.alwaysShowsDecimalSeparator = YES;
numberFormatter.minimumIntegerDigits = 1;
numberFormatter.numberStyle = kCFNumberFormatterNoStyle;
numberFormatter.minimumFractionDigits = scale;
return numberFormatter;
}
/**
比较两个字符串大小
@return 返回结果
*/
-(NSComparisonResult )yxy_comparey:(NSString *)stringNumber {
NSDecimalNumber *selfNumber = [NSDecimalNumber decimalNumberWithString:self];
NSDecimalNumber *calcuationNumber = [NSDecimalNumber decimalNumberWithString:stringNumber];
NSComparisonResult type = [selfNumber compare:calcuationNumber];
return type;
}
// 不四舍五入
- (NSString *)yxy_notRoundingAfterPoint:( NSInteger )position{
NSDecimalNumberHandler* roundingBehavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundDown scale:position raiseOnExactness: NO raiseOnOverflow: NO raiseOnUnderflow: NO raiseOnDivideByZero: NO ];
NSDecimalNumber *ouncesDecimal = [NSDecimalNumber decimalNumberWithString:self];
NSDecimalNumber* roundedOunces = [ouncesDecimal decimalNumberByRoundingAccordingToBehavior:roundingBehavior];
return roundedOunces.stringValue;
}
@end