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

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];

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容