您的位置:首页 > 移动开发 > IOS开发

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: 目前就想到以上的几种方式,如有其它的方法或者文中有何错误。欢迎留言。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: