處理后臺(tái)返回?cái)?shù)據(jù)精度失真的問(wèn)題

iOS開(kāi)發(fā)中,接受后臺(tái)的響應(yīng),把json然后轉(zhuǎn)化為模型對(duì)象,最終轉(zhuǎn)化為NSString對(duì)象。

后臺(tái)返回的一個(gè)數(shù)字(這里一般是商品價(jià)格,因?yàn)橹挥懈X相關(guān)的東西才會(huì)特別特別的謹(jǐn)慎,畢畢竟出了事是要負(fù)責(zé)的,還好前端只是展示價(jià)格,真正出錯(cuò)是后臺(tái)),可以定義為NSnumber類型,也可以定義為NSString問(wèn)題。如果后臺(tái)返回的是字符串類型。在iOS json序列化的時(shí)候,會(huì)把字符串類型轉(zhuǎn)化為NSString對(duì)象,這個(gè)一點(diǎn)問(wèn)題沒(méi)有。但是如果后臺(tái)返回的是NSnumber類型。json序列化會(huì)將NSnumber類型轉(zhuǎn)化為NSNumber對(duì)象。使用的時(shí)候,想當(dāng)然的會(huì)將NSNumber轉(zhuǎn)化為NSString對(duì)象(NSString *pricer = [NSString stringWithFormat:@"%@",number] )。這樣做很自然啊,沒(méi)有問(wèn)題,也用一兩個(gè)數(shù)字測(cè)試了,轉(zhuǎn)化是精確的。But問(wèn)題來(lái)了,假如后臺(tái)定義的是double類型數(shù)據(jù)89.6,你轉(zhuǎn)化后的字符串會(huì)發(fā)現(xiàn)就是89.59999999999999,直接用NSString接收后臺(tái)的double就會(huì)有問(wèn)題,double字面數(shù)值和和其存儲(chǔ)的值不一樣。

類型? ? ? ? ? ? ? ? ? ? ? ? 比特?cái)?shù) ? ? ? ?有效數(shù)字? ? ? ? ? ? ? ? 數(shù)值范圍

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的不可變子類。蘋果針對(duì)浮點(diǎn)型計(jì)算時(shí)存在精度計(jì)算誤差的問(wèn)題而提供的一個(gè)計(jì)算類,它是基于10進(jìn)制的定點(diǎn)計(jì)算保證了精度不會(huì)缺失。同時(shí)也可以定制精度的取正類型:向上取正、向下去正、四舍五入等。相對(duì)與浮點(diǎn)類型的計(jì)算,NSDecimalNumber提供了更加精準(zhǔn)的計(jì)算。下面是NSDecimalNumber的一個(gè)類別,主要是加減乘除:



.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) {//有小數(shù)點(diǎn)? ?

?? ? ? ? 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{ //沒(méi)有小數(shù)點(diǎn)

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

}


使用:在使用到處理精度的類導(dǎo)入頭文件#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";

//加法運(yùn)算

num = SNAdd(num1,num2);

//減法運(yùn)算

num = SNSub(num1,num2);

//乘法運(yùn)算

num = SNMul(num1,num2);

//除法運(yùn)算

num = SNDiv(num1,num2);

//加法乘法混合運(yùn)算

num = SNAdd(SNMul(@(數(shù)量),價(jià)格), num2);

//最終結(jié)果

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,030評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,310評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 175,951評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 62,796評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,566評(píng)論 6 407
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 55,055評(píng)論 1 322
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 42,303評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,799評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,683評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,899評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,135評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 34,520評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 35,757評(píng)論 1 282
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,528評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,844評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容