美文网首页
处理后台返回数据精度失真的问题

处理后台返回数据精度失真的问题

作者: 海边漫步的我 | 来源:发表于2017-08-17 13:40 被阅读255次

    iOS开发中,接受后台的响应,把json然后转化为模型对象,最终转化为NSString对象。

    后台返回的一个数字(这里一般是商品价格,因为只有跟钱相关的东西才会特别特别的谨慎,毕毕竟出了事是要负责的,还好前端只是展示价格,真正出错是后台),可以定义为NSnumber类型,也可以定义为NSString问题。如果后台返回的是字符串类型。在iOS json序列化的时候,会把字符串类型转化为NSString对象,这个一点问题没有。但是如果后台返回的是NSnumber类型。json序列化会将NSnumber类型转化为NSNumber对象。使用的时候,想当然的会将NSNumber转化为NSString对象(NSString *pricer = [NSString stringWithFormat:@"%@",number] )。这样做很自然啊,没有问题,也用一两个数字测试了,转化是精确的。But问题来了,假如后台定义的是double类型数据89.6,你转化后的字符串会发现就是89.59999999999999,直接用NSString接收后台的double就会有问题,double字面数值和和其存储的值不一样。

    类型                        比特数        有效数字                数值范围

    float 类型                 32                6-7                -3.4*10(-38)~3.4*10(38)

    double类型               64              15-16            -1.7*10(-308)~1.7*10(308)

    long double类型      128             18-19          -1.2*10(-4932)~1.2*10(4932)

    NSDecimalNumber是NSNumber的不可变子类。苹果针对浮点型计算时存在精度计算误差的问题而提供的一个计算类,它是基于10进制的定点计算保证了精度不会缺失。同时也可以定制精度的取正类型:向上取正、向下去正、四舍五入等。相对与浮点类型的计算,NSDecimalNumber提供了更加精准的计算。下面是NSDecimalNumber的一个类别,主要是加减乘除:


    .h文件

    typedef NS_ENUM(NSInteger, calculationType) {

    Add,

    Subtract,

    Multiply,

    Divide

    };

    @interface NSDecimalNumber (Addtion)

    +(NSDecimalNumber *)aDecimalNumberWithStringOrNumberOrDecimalNumber:(id)stringOrNumber1 type:(calculationType)type anotherDecimalNumberWithStringOrNumberOrDecimalNumber:(id)stringOrNumber2 andDecimalNumberHandler:(NSDecimalNumberHandler *)handler;

    +(NSComparisonResult)aDecimalNumberWithStringOrNumberOrDecimalNumber:(id)stringOrNumber1 compareAnotherDecimalNumberWithStringOrNumberOrDecimalNumber:(id)stringOrNumber2;

    +(NSString *)stringWithDecimalNumber:(NSDecimalNumber *)str1 scale:(NSInteger)scale;

    extern NSComparisonResult StrNumCompare(id str1,id str2);

    extern NSDecimalNumber *handlerDecimalNumber(id strOrNum,NSRoundingMode mode,int scale);

    extern NSComparisonResult SNCompare(id strOrNum1,id strOrNum2);

    extern NSDecimalNumber *SNAdd(id strOrNum1,id strOrNum2);

    extern NSDecimalNumber *SNSub(id strOrNum1,id strOrNum2);

    extern NSDecimalNumber *SNMul(id strOrNum1,id strOrNum2);

    extern NSDecimalNumber *SNDiv(id strOrNum1,id strOrNum2);

    extern NSDecimalNumber *SNMin(id strOrNum1,id strOrNum2);

    extern NSDecimalNumber *SNMax(id strOrNum1,id strOrNum2);

    extern NSDecimalNumber *SNAdd_handler(id strOrNum1,id strOrNum2,NSRoundingMode mode,int scale);

    extern NSDecimalNumber *SNSub_handler(id strOrNum1,id strOrNum2,NSRoundingMode mode,int scale);

    extern NSDecimalNumber *SNMul_handler(id strOrNum1,id strOrNum2,NSRoundingMode mode,int scale);

    extern NSDecimalNumber *SNDiv_handler(id strOrNum1,id strOrNum2,NSRoundingMode mode,int scale);

    extern NSDecimalNumber *SNMin_handler(id strOrNum1,id strOrNum2,NSRoundingMode mode,int scale);

    extern NSDecimalNumber *SNMax_handler(id strOrNum1,id strOrNum2,NSRoundingMode mode,int scale);

    @end


    .m文件

    +(NSDecimalNumber *)aDecimalNumberWithStringOrNumberOrDecimalNumber:(id)stringOrNumber1 type:(calculationType)type anotherDecimalNumberWithStringOrNumberOrDecimalNumber:(id)stringOrNumber2 andDecimalNumberHandler:(NSDecimalNumberHandler *)handler{

    if (!stringOrNumber2 || !stringOrNumber1) {

    NSLog(@"输入正确类型");

    return nil;

    }

    NSDecimalNumber *one;

    NSDecimalNumber *another;

    NSDecimalNumber *returnNum;

    if ([stringOrNumber1 isKindOfClass:[NSString class]]) {

    one = [NSDecimalNumber decimalNumberWithString:stringOrNumber1];

    }else if([stringOrNumber1 isKindOfClass:[NSDecimalNumber class]]){

    one = stringOrNumber1;

    }else if ([stringOrNumber1 isKindOfClass:[NSNumber class]]){

    one = [NSDecimalNumber decimalNumberWithDecimal:[stringOrNumber1 decimalValue]];

    }else{

    NSLog(@"输入正确的类型");

    return nil;

    }

    if ([stringOrNumber2 isKindOfClass:[NSString class]]) {

    another = [NSDecimalNumber decimalNumberWithString:stringOrNumber2];

    }else if([stringOrNumber2 isKindOfClass:[NSDecimalNumber class]]){

    another = stringOrNumber2;

    }else if ([stringOrNumber2 isKindOfClass:[NSNumber class]]){

    another = [NSDecimalNumber decimalNumberWithDecimal:[stringOrNumber2 decimalValue]];

    }else{

    NSLog(@"输入正确的类型");

    return nil;

    }

    if (type == Add) {

    returnNum = [one decimalNumberByAdding:another];

    }else if (type == Subtract){

    returnNum  = [one decimalNumberBySubtracting:another];

    }else if (type == Multiply){

    returnNum = [one decimalNumberByMultiplyingBy:another];

    }else if (type == Divide){

    if ([NSDecimalNumber aDecimalNumberWithStringOrNumberOrDecimalNumber:another compareAnotherDecimalNumberWithStringOrNumberOrDecimalNumber:@(0)] == 0) {

    returnNum = nil;

    }else

    returnNum = [one decimalNumberByDividingBy:another];

    }else{

    returnNum = nil;

    }

    if (returnNum) {

    if (handler) {

    return [returnNum decimalNumberByRoundingAccordingToBehavior:handler];

    }else{

    return returnNum;

    }

    }else{

    NSLog(@"输入正确的类型");

    return nil;

    }

    }

    +(NSComparisonResult)aDecimalNumberWithStringOrNumberOrDecimalNumber:(id)stringOrNumber1 compareAnotherDecimalNumberWithStringOrNumberOrDecimalNumber:(id)stringOrNumber2{

    if (!stringOrNumber2 || !stringOrNumber1) {

    NSLog(@"输入正确类型");

    return -404;

    }

    NSDecimalNumber *one;

    NSDecimalNumber *another;

    if ([stringOrNumber1 isKindOfClass:[NSString class]]) {

    one = [NSDecimalNumber decimalNumberWithString:stringOrNumber1];

    }else if([stringOrNumber1 isKindOfClass:[NSDecimalNumber class]]){

    one = stringOrNumber1;

    }else if ([stringOrNumber1 isKindOfClass:[NSNumber class]]){

    one = [NSDecimalNumber decimalNumberWithDecimal:[stringOrNumber1 decimalValue]];

    }else{

    NSLog(@"输入正确的类型");

    return -404;

    }

    if ([stringOrNumber2 isKindOfClass:[NSString class]]) {

    another = [NSDecimalNumber decimalNumberWithString:stringOrNumber2];

    }else if([stringOrNumber2 isKindOfClass:[NSDecimalNumber class]]){

    another = stringOrNumber2;

    }else if ([stringOrNumber2 isKindOfClass:[NSNumber class]]){

    another = [NSDecimalNumber decimalNumberWithDecimal:[stringOrNumber2 decimalValue]];

    }else{

    NSLog(@"输入正确的类型");

    return -404;

    }

    return [one compare:another];

    }

    +(NSString *)stringWithDecimalNumber:(NSDecimalNumber *)str1 scale:(NSInteger)scale{   

     if (!str1) {        

    return @"";   

     }    

    NSString *str = [NSString stringWithFormat:@"%@",str1];  

      if (str && str.length) {      

      if ([str rangeOfString:@"."].length == 1) {//有小数点   

             NSArray *arr = [str componentsSeparatedByString:@"."];          

      if (scale > 0) {              

      NSInteger count = [arr[1] length];           

         for (NSInteger i = count; i<scale;i++) {

        str = [str stringByAppendingString:@"0"];

       }

        return str; 

          else{

          return arr[0];

        }

    else{ //没有小数点

    if ([str rangeOfString:@"."].length) {

    return @"";

    }

    if (scale > 0) {

    str = [str stringByAppendingString:@"."];

    for (int i = 0; i<scale;i++){

    str = [str stringByAppendingString:@"0"];

    }

    return str;

    }

    else{

      return str;

    }

    }

    }else{

    return @"";

    }

    NSComparisonResult StrNumCompare(id str1,id str2){

    return [NSDecimalNumber aDecimalNumberWithStringOrNumberOrDecimalNumber:str1 compareAnotherDecimalNumberWithStringOrNumberOrDecimalNumber:str2];

    }

    NSDecimalNumber *handlerDecimalNumber(id strOrNum,NSRoundingMode mode,int scale){

    if (!strOrNum) {

    NSLog(@"输入正确类型");

    return nil;

    }else{

    NSDecimalNumber *one;

    if ([strOrNum isKindOfClass:[NSString class]]) {

    one = [NSDecimalNumber decimalNumberWithString:strOrNum];

    }else if([strOrNum isKindOfClass:[NSDecimalNumber class]]){

    one = strOrNum;

    }else if ([strOrNum isKindOfClass:[NSNumber class]]){

    one = [NSDecimalNumber decimalNumberWithDecimal:[strOrNum decimalValue]];

    }else{

    NSLog(@"输入正确的类型");

    return nil;

    }

    NSDecimalNumberHandler *handler = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:mode scale:scale raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];

    return  [one decimalNumberByRoundingAccordingToBehavior:handler];

    }

    }

    NSDecimalNumber *SNAdd(id strOrNum1,id strOrNum2){

    return [NSDecimalNumber aDecimalNumberWithStringOrNumberOrDecimalNumber:strOrNum1 type:Add anotherDecimalNumberWithStringOrNumberOrDecimalNumber:strOrNum2 andDecimalNumberHandler:nil];

    }

    NSDecimalNumber *SNSub(id strOrNum1,id strOrNum2){

    return [NSDecimalNumber aDecimalNumberWithStringOrNumberOrDecimalNumber:strOrNum1 type:Subtract anotherDecimalNumberWithStringOrNumberOrDecimalNumber:strOrNum2 andDecimalNumberHandler:nil];

    }

    NSDecimalNumber *SNMul(id strOrNum1,id strOrNum2){

    return [NSDecimalNumber aDecimalNumberWithStringOrNumberOrDecimalNumber:strOrNum1 type:Multiply anotherDecimalNumberWithStringOrNumberOrDecimalNumber:strOrNum2 andDecimalNumberHandler:nil];

    }

    NSDecimalNumber *SNDiv(id strOrNum1,id strOrNum2){

    return [NSDecimalNumber aDecimalNumberWithStringOrNumberOrDecimalNumber:strOrNum1 type:Divide anotherDecimalNumberWithStringOrNumberOrDecimalNumber:strOrNum2 andDecimalNumberHandler:nil];

    }

    NSComparisonResult SNCompare(id strOrNum1,id strOrNum2){

    return [NSDecimalNumber aDecimalNumberWithStringOrNumberOrDecimalNumber:strOrNum1 compareAnotherDecimalNumberWithStringOrNumberOrDecimalNumber:strOrNum2];

    }

    NSDecimalNumber *SNMin(id strOrNum1,id strOrNum2){

    return SNCompare(strOrNum1, strOrNum2) > 0 ? strOrNum2 : strOrNum1;

    }

    NSDecimalNumber *SNMax(id strOrNum1,id strOrNum2){

    return SNCompare(strOrNum1, strOrNum2) > 0 ? strOrNum1 : strOrNum2;

    }

    NSDecimalNumber *SNAdd_handler(id strOrNum1,id strOrNum2,NSRoundingMode mode,int scale){

    return handlerDecimalNumber(SNAdd(strOrNum1, strOrNum2), mode, scale);

    }

    NSDecimalNumber *SNSub_handler(id strOrNum1,id strOrNum2,NSRoundingMode mode,int scale){

    return handlerDecimalNumber(SNSub(strOrNum1, strOrNum2), mode, scale);

    }

    NSDecimalNumber *SNMul_handler(id strOrNum1,id strOrNum2,NSRoundingMode mode,int scale){

    return handlerDecimalNumber(SNMul(strOrNum1, strOrNum2), mode, scale);

    }

    NSDecimalNumber *SNDiv_handler(id strOrNum1,id strOrNum2,NSRoundingMode mode,int scale){

    return handlerDecimalNumber(SNDiv(strOrNum1, strOrNum2), mode, scale);

    }

    NSDecimalNumber *SNMin_handler(id strOrNum1,id strOrNum2,NSRoundingMode mode,int scale){

    return handlerDecimalNumber(SNMin(strOrNum1, strOrNum2), mode, scale);

    }

    NSDecimalNumber *SNMax_handler(id strOrNum1,id strOrNum2,NSRoundingMode mode,int scale){

    return handlerDecimalNumber(SNMax(strOrNum1, strOrNum2), mode, scale);

    }

    使用:在使用到处理精度的类导入头文件#import "NSDecimalNumber+Addtion.h"

    NSDecimalNumber *num = [[NSDecimalNumber alloc] initWithString:@"0.00"];

    NSDecimalNumber *num1 = [[NSDecimalNumber alloc] initWithString:@"0.00"];

    NSDecimalNumber *num2 = [[NSDecimalNumber alloc] initWithString:@"0.00"];

    NSString *priceStr = @"89.6";

    //加法运算

    num = SNAdd(num1,num2);

    //减法运算

    num = SNSub(num1,num2);

    //乘法运算

    num = SNMul(num1,num2);

    //除法运算

    num = SNDiv(num1,num2);

    //加法乘法混合运算

    num = SNAdd(SNMul(@(数量),价格), num2);

    //最终结果

    NSString *result = [NSString stringWithFormat:@"%@",num];

    相关文章

      网友评论

          本文标题:处理后台返回数据精度失真的问题

          本文链接:https://www.haomeiwen.com/subject/eyugrxtx.html