iOS浮点数精度丢失问题及处理方案

2016-12-21  本文已影响4035人  叫我大表弟吧

为什么浮点数精度会丢失

浮点十进制值通常没有完全相同的二进制表示形式。 这是 CPU 所采用的浮点数据表示形式的副作用。 为此,可能会经历一些精度丢失,并且一些浮点运算可能会产生意外的结果。

导致此行为的原因是下面之一:
十进制数的二进制表示形式可能不精确。
使用的数字之间类型不匹配(例如,混合使用浮点型和双精度型)。

&&
代码之谜(五)- 浮点数(谁偷了你的精度?)

解决方案

如果你通读了上面的为什么就会知道,这是IEEE 754标准中二进制浮点数的缺陷,没有解决方案。

处理方案

使用系统提供的NSDecimalNumber API进行计算,最后转换为字符串输出显示。NSDecimalNumber转换方法:

#import "NSDecimalNumber+Y_Add.h"

@implementation NSDecimalNumber (Y_Add)

+ (NSDecimalNumber *)y_decimalNumberWithFloat:(float)value{
    
    return [self y_decimalNumberWithFloat:value scale:2];
}

+ (NSDecimalNumber *)y_decimalNumberWithFloat:(float)value scale:(short)scale{
    
    return [self y_decimalNumberWithFloat:value roundingMode:NSRoundBankers scale:scale];
}

+ (NSDecimalNumber *)y_decimalNumberWithFloat:(float)value roundingMode:(NSRoundingMode)roundingMode scale:(short)scale{
    
    return [[[NSDecimalNumber alloc] initWithFloat:value] y_decimalNumberHandlerWithRoundingMode:roundingMode scale:scale];
}

+ (NSDecimalNumber *)y_decimalNumberWithDouble:(double)value{
    
    return [self y_decimalNumberWithDouble:value scale:2];
}

+ (NSDecimalNumber *)y_decimalNumberWithDouble:(double)value scale:(short)scale{
    
    return [self y_decimalNumberWithDouble:value roundingMode:NSRoundBankers scale:scale];
}

+ (NSDecimalNumber *)y_decimalNumberWithDouble:(double)value roundingMode:(NSRoundingMode)roundingMode scale:(short)scale{
    
    return [[[NSDecimalNumber alloc] initWithFloat:value] y_decimalNumberHandlerWithRoundingMode:roundingMode scale:scale];
}




/**
 *  <#Description#>
 *
 *  @return <#return value description#>
 */
- (NSDecimalNumber *)y_decimalNumberHandler{
    
    return [self y_decimalNumberHandlerWithRoundingMode:NSRoundBankers scale:2];
}

- (NSDecimalNumber *)y_decimalNumberHandlerWithRoundingMode:(NSRoundingMode)roundingMode scale:(short)scale{
    
    NSDecimalNumberHandler *handler = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:roundingMode
                                                                                             scale:scale
                                                                                  raiseOnExactness:NO
                                                                                   raiseOnOverflow:YES
                                                                                  raiseOnUnderflow:YES
                                                                               raiseOnDivideByZero:YES];
    return [self decimalNumberByRoundingAccordingToBehavior:handler];
}


@end

使用系统提供的数学运算进行计算,最后转换为字符串输出显示。保留小数点后N位的方法:

/**
 *  formatterNumber .00 小数点后两位
 *
 *  @param number <#number description#>
 *
 *  @return <#return value description#>
 */
+ (NSString *)y_formatterNumber:(NSNumber *)number{
    
    return [self y_formatterNumber:number fractionDigits:2];
}

+ (NSString *)y_formatterNumber:(NSNumber *)number fractionDigits:(NSUInteger)fractionDigits{
        
    NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
    [numberFormatter setMaximumFractionDigits:fractionDigits];
    [numberFormatter setMinimumFractionDigits:fractionDigits];
    
    return [numberFormatter stringFromNumber:number];
}
上一篇下一篇

猜你喜欢

热点阅读