iOS 浮点型四舍五入精确值问题
2016-02-05 14:27
459 查看
在开发过程中总是会碰到字符串类型转换成浮点型进行运算。但是每当float—>String 或 Sting —> float 转换四舍五入时总会碰上一堆精度失准的问题。即使转成double型也无济于事。先做个总结和分享。提供几种方法思路来解决这个问题:
如果涉及到时金额计算时,对数字的精确度要求很高时,最简单也是最粗暴的方法是直接交于后台处理,由后台处理返回字符串。这算是最安全也算客户端最轻松的方法。(就看后台刁不刁你咯~~~)。
还有一种方式就是在转换double 计算完成时,对相应的结果着手。 看你想要的精度情况。这里以保留两位小数为例。举个栗子:
// 用于计算的连个字符串
NSString
*strA = @"9.5";
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
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:@"."];
///
在截取两位小数
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
*/
/*
暂时就这么点,
*/
具体代码请戳:https://github.com/yuwuchiao/Rounding
ps: 目前就想到以上的几种方式,如有其它的方法或者文中有何错误。欢迎留言。
如果涉及到时金额计算时,对数字的精确度要求很高时,最简单也是最粗暴的方法是直接交于后台处理,由后台处理返回字符串。这算是最安全也算客户端最轻松的方法。(就看后台刁不刁你咯~~~)。
还有一种方式就是在转换double 计算完成时,对相应的结果着手。 看你想要的精度情况。这里以保留两位小数为例。举个栗子:
// 用于计算的连个字符串
NSString
*strA = @"9.5";
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
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:@"."];
///
在截取两位小数
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
*/
/*
暂时就这么点,
*/
具体代码请戳:https://github.com/yuwuchiao/Rounding
ps: 目前就想到以上的几种方式,如有其它的方法或者文中有何错误。欢迎留言。
相关文章推荐
- iOS开发之苹果公司联系邮箱大全
- 深入浅出理解iOS经常使用的正則表達式—基础篇[Foundation]
- [转载]iOS Provisioning Profile(Certificate)与Code Signing详解
- 详解iOS7原生二维码,条码扫描
- iOS系统改变StatusBar的前景色(文字颜色)
- 键盘的弹出与消失(通知)
- Quartz2D绘图
- Growth发布iOS版 — 距今为止最好的开源“Web开发学习”应用
- 应用沙盒
- usaco 3.2 ratios 2008.7.20
- 谈谈 iOS 内存管理机制
- iOS CocoaPods安装和使用图解
- iOS应用开发中图片的拉伸问题解决方案
- iOS 文件路径以及保存
- 高清不加密-小码哥ios大神班视频-小码哥教育
- iOS客户端的APNS服务简介与实现
- iOS 中`联网指示器`的使用
- iOS 应用图标 右上角的数字提示 设置
- iOS 系统状态栏 隐藏 或 显示
- iOS 代码中获取info.plist文件对应的字典对象