在iOS的開發中,我們有時需要嚴格處理準確性,比如用戶資金的數量。壹個更好的建議是,服務器直接返回的金額是字符串類型,這樣客戶端就不用擔心顯示的準確性。如果我們需要操作服務器返回的數據,比如服務器上的兩個數,float A = 0.01,int B = 9999999,兩個數相乘的結果是99999.99。再比如平A = 123456789.12,int B = 10000,兩個數相除。
在iOS的開發中,需要註意與貨幣價格計算相關的計算精度。哪怕只是小數點後兩位,也會有誤差。使用浮點型操作是遠遠不夠的。經過壹些測試,我們最終選擇使用系統提供的API的NSDecimalNumber作為更好的解決方案。
作為外部庫,鑒於版本的延續,我們保持外部flaot類型,不改變接口,選擇內部適配。
這裏有壹些基本的測試。
原始資料
float = 0.01;
intb = 99999999
doublec = 0.0
1:使用浮點運算,
c = a * b;
NSLog(@"%f ",c);
NSLog(@"%.2f ",c);
使用雙類型存儲不觸及問題的本質,根本解決不了問題。
2011-12-30 11:04:00.121無標題[2912:207]1000000.00000
2011-12-30 11:04:00.123無標題[2912:207]1000000.00
2.使用類型轉換來提高準確性。
c = a *(double)b;
NSLog(@"%f ",c);
NSLog(@"%.2f ",c);
雙運算的精度提高了,但是浮點數的值已經不準確了,即使存儲空間足夠,也還是不準確。
2011-12-30 11:04:00.123無標題[2912:207]9999999.9676648
2011-12-30 11:04:00.124無標題[2912:207] 999999.97
3.通過與NSString的轉換,將計算的原始數據轉換為純雙精度數據,使計算精度滿足要求。
ns string * objA =[NSStringstringWithFormat:@ " % . 2f ",a];
ns string * objB =[NSStringstringWithFormat:@“% . 2f”,(double)b];
c =[objAdoubleValue]*[objBdoubleValue];
NSLog(@"%.2f ",c);
計算結果相對準確,但需要格式化輸入和打印格式處理。同時使用NSString進行轉換似乎有些奇怪。
2011-12-30 11:04:00.190無標題[2912:207] 999999.99
4.個人更喜歡使用系統提供的類型進行計算。通過NSDecimalNumber提供的計算方法,不使用打印格式也能很好的計算出準確的數據。
它的計算精度比較高,是官方推薦的貨幣計算API,乘法和除法都有單獨的API接口。
ns string * decimalnumbermutiplywitstring(ns string * multiplier Value,ns string *被乘數value)
{
NSDecimalNumber * multiplier number =[NSDecimalNumberdecimalNumberWithString:multiplier value];
NSDecimalNumber *被乘數number =[NSDecimalNumberdecimalNumberWithString:被乘數value];
NSDecimalNumber * product =[被乘數decimalnumberbymultiplyingby:multiplier number];
return[productstringValue];
}
NSLog(@“% @”,decimalNumberMutiplyWithString([NSStringstringWithFormat:@“% f”,a],[NSStringstringWithFormat:@“% d”,b]);
2011-12-30 11:0 4:00.251無標題[2912:207] 999999.99
只是測試,所以接口名稱寫的比較粗略,名稱獲取也沒那麽講究。希望能表達清楚。
壹般來說,要註意貨幣計算的準確性。同時,在操作時,要優先使用框架提供的API,否則要使用足夠精度的類型操作,自己編寫的接口要解釋得足夠清楚,要求開發者按照規範使用。
在不能保證足夠準確的情況下,以適當解釋的要求來逃避責任,還是可以接受的。至少被抱怨幾句總比犯錯好。