在开发过程中总是会碰到字符串类型转换成浮点型进行运算。但是每当float—>String 或 Sting —> float 转换四舍五入时总会碰上一堆精度失准的问题。即使转成double型也无济于事。先做个总结和分享。提供几种方法思路来解决这个问题:
- 如果涉及到时金额计算时,对数字的精确度要求很高时,最简单也是最粗暴的方法是直接交于后台处理,由后台处理返回字符串。这算是最安全也算客户端最轻松的方法。(就看后台刁不刁你咯~~~)。
- 还有一种方式就是在转换double 计算完成时,对相应的结果着手。 看你想要的精度情况。这里以保留两位小数为例。举个栗子:
// 用于计算的连个字符串
NSString *strA = @"9.5";
NSString *strB = @"15.11";
NSString *strB = @"15.11";
CGFloat fltA = [strA doubleValue]; /// 转成double时的值:15.109999999999999
CGFloat fltB = [strB doubleValue]; /// 转成double时的值: 9.5
CGFloat mutli = fltA * fltB; /// 断点得到: 143.54499999999999
NSLog(@"Normally unrounding = %f",mutli); /// 输出 143.545000
CGFloat fltB = [strB doubleValue]; /// 转成double时的值: 9.5
CGFloat mutli = fltA * fltB; /// 断点得到: 143.54499999999999
NSLog(@"Normally unrounding = %f",mutli); /// 输出 143.545000
NSLog(@"Normally rounding = %@",[NSString stringWithFormat:@"%.2f",mutli]); //实际输出143.54
跟想要的四舍五入还是存在一定的差距。解决的方法是在得出计算结果时。首先对结果加上 5/( 比想要精度还小一位)。 比如上面例子上面想要的是2位精度。则可以在计算的结果时加上千分之5。即 0.005,然后进行两次字符串取值。第一次先按小数的后三位进行字符串转换。再从字符串的中截取到小数点的后2位。 同样用上面的结果举栗:
///
将计算的数值加千分之五。精度
CGFloat i = mutli + 0.005 ;
/// 首先保留三位小数
NSString *strTemp = [ NSString stringWithFormat : @"%.3f" ,i];
NSRange range = [strTemp rangeOfString : @"." ];
/// 在截取两位小数
CGFloat i = mutli + 0.005 ;
/// 首先保留三位小数
NSString *strTemp = [ NSString stringWithFormat : @"%.3f" ,i];
NSRange range = [strTemp rangeOfString : @"." ];
/// 在截取两位小数
NSString *strLastResult = [strTemp substringWithRange:NSMakeRange(0, range.location+3)];
NSLog(@"first method = %@",strLastResult);
//实际输出143.55
3.直接使用官方自带的货币计算用的类: NSDecimalNumberd
NSDecimalNumber
*numberA = [
NSDecimalNumber
decimalNumberWithString
:strA];
NSDecimalNumber
*numberB = [
NSDecimalNumber
decimalNumberWithString
:strB];
/// 这里不仅包含 Multiply 还有加 减 除。
NSDecimalNumber *numResult = [numberA decimalNumberByMultiplyingBy :numberB];
NSString *strResult = [numResult stringValue ];
NSLog ( @"NSDecimalNumber method unrounding = %@" ,strResult);
/// 如果要四舍五入的话还要使用另一个类 NSDecimalNumberHandler
/*
讲述下参数的含义 :
RoundingMode: 简单讲就是你要四舍五入操作的标准 .
// 原始数据
// 值 1.2 1.21 1.25 1.35 1.27
各个 model 转换后的值
// 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
scale : 需要保留的精度。
raiseOnExactness : 为 YES 时在处理精确时如果有错误,就会抛出异常。
raiseOnOverflow : YES 时在计算精度向上溢出时会抛出异常,否则返回。
raiseOnUnderflow : YES 时在计算精度向下溢出时会抛出异常,否则返回 .
raiseOnDivideByZero : YES 时。当除以 0 时会抛出异常,否则返回。
*/
NSDecimalNumberHandler *roundingBehavior = [ NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode : NSRoundPlain
scale : 2
raiseOnExactness : NO
raiseOnOverflow : NO
raiseOnUnderflow : NO
raiseOnDivideByZero : NO ];
NSString *tempStr =[[numResult decimalNumberByRoundingAccordingToBehavior :roundingBehavior] stringValue ];
NSLog ( @"NSDecimalNumber method rounding = %@" ,tempStr);
/// ps 。计算的结果如果小数的位数不到你的要求精度。系统不会自动添加 “0”, 需自行处理 如用户需要小数点后两位小数但计算结果为 142.5 时。如需后面补 “0” 需用户自己添加
/*
这里主要就展示下怎么使用 NSDecimalNumber 具体的详细用法请戳 https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSDecimalNumber_Class/index.html
*/
/*
暂时就这么点,
/// 这里不仅包含 Multiply 还有加 减 除。
NSDecimalNumber *numResult = [numberA decimalNumberByMultiplyingBy :numberB];
NSString *strResult = [numResult stringValue ];
NSLog ( @"NSDecimalNumber method unrounding = %@" ,strResult);
/// 如果要四舍五入的话还要使用另一个类 NSDecimalNumberHandler
/*
讲述下参数的含义 :
RoundingMode: 简单讲就是你要四舍五入操作的标准 .
// 原始数据
// 值 1.2 1.21 1.25 1.35 1.27
各个 model 转换后的值
// 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
scale : 需要保留的精度。
raiseOnExactness : 为 YES 时在处理精确时如果有错误,就会抛出异常。
raiseOnOverflow : YES 时在计算精度向上溢出时会抛出异常,否则返回。
raiseOnUnderflow : YES 时在计算精度向下溢出时会抛出异常,否则返回 .
raiseOnDivideByZero : YES 时。当除以 0 时会抛出异常,否则返回。
*/
NSDecimalNumberHandler *roundingBehavior = [ NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode : NSRoundPlain
scale : 2
raiseOnExactness : NO
raiseOnOverflow : NO
raiseOnUnderflow : NO
raiseOnDivideByZero : NO ];
NSString *tempStr =[[numResult decimalNumberByRoundingAccordingToBehavior :roundingBehavior] stringValue ];
NSLog ( @"NSDecimalNumber method rounding = %@" ,tempStr);
/// ps 。计算的结果如果小数的位数不到你的要求精度。系统不会自动添加 “0”, 需自行处理 如用户需要小数点后两位小数但计算结果为 142.5 时。如需后面补 “0” 需用户自己添加
/*
这里主要就展示下怎么使用 NSDecimalNumber 具体的详细用法请戳 https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSDecimalNumber_Class/index.html
*/
/*
暂时就这么点,
*/
ps: 目前就想到以上的几种方式,如有其它的方法或者文中有何错误。欢迎留言。