iOS 浮点型四舍五入精确值问题

在开发过程中总是会碰到字符串类型转换成浮点型进行运算。但是每当float—>String 或 Sting —> float 转换四舍五入时总会碰上一堆精度失准的问题。即使转成double型也无济于事。先做个总结和分享。提供几种方法思路来解决这个问题:

  1. 如果涉及到时金额计算时,对数字的精确度要求很高时,最简单也是最粗暴的方法是直接交于后台处理,由后台处理返回字符串。这算是最安全也算客户端最轻松的方法。(就看后台刁不刁你咯~~~)。
  2. 还有一种方式就是在转换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
     */

   
   
   
/*
    
暂时就这么点,
     */





ps: 目前就想到以上的几种方式,如有其它的方法或者文中有何错误。欢迎留言。


猜你喜欢

转载自blog.csdn.net/yuwuchaio/article/details/50637942
今日推荐