最近項(xiàng)目中遇到金額計(jì)算歌逢,CGFloat類(lèi)型金額計(jì)算的過(guò)程中祈餐,讓我吃了不少苦頭鹃操,先來(lái)看下面幾行代碼:
示例代碼
CGFloat var1 = 120.66;
CGFloat var2 = 120.66;
CGFloat var3 = [@"120.66" floatValue];
CGFloat var4 = [@"120.66" floatValue];
CGFloat var5 = 120.67 - 0.01;
CGFloat var6 = [@"120.67" floatValue] - 0.01;
bool flag1 = var1 == var2;
bool flag2 = var3 == var4;
bool flag3 = var3 == var5;
bool flag4 = var5 == var6;
bool flag5 = var3 == var6;
略去猜答案的過(guò)程仓坞,直接看結(jié)果
![圖一](https://s27.postimg.org/5m7cgftvn/Wechat_IMG1.jpg)
圖一
現(xiàn)象總結(jié)
- var1 和var2相等
- var3 和var4相等
- NSString 的 floatValue 會(huì)讓CGFloat 的精度增加
- 精度確定的float類(lèi)型做運(yùn)算颜说,精度確定 var5 = 120.66
- 不同精度的float類(lèi)型做運(yùn)算购岗,精度會(huì)丟失 var6 = 120.65999816894531
浮點(diǎn)數(shù)相等問(wèn)題
CGFloat x = var5 - var6;
const CGFloat EPSINON = 0.000001;
if (( x >= -EPSINON ) && ( x <= EPSINON ))
{
NSLog("var5 和var6相等");
}
鑒于CGFloat在處理金額過(guò)程中會(huì)遇到精度問(wèn)題,iOS中提供了NSDecimalNumber類(lèi)來(lái)處理精度問(wèn)題,如果要四舍五入的話還要使用另一個(gè)類(lèi) NSDecimalNumberHandler
NSDecimalNumber類(lèi)
/*
講述下參數(shù)的含義:
RoundingMode: 簡(jiǎn)單講就是你要四舍五入操作的標(biāo)準(zhǔn).
typedef NS_ENUM(NSUInteger, NSRoundingMode) {
NSRoundPlain, // 精度位后四舍五入
NSRoundDown, // 精度位后舍去
NSRoundUp, // 精度位后入上去
NSRoundBankers // 精度位后的數(shù)值等于5時(shí)门粪,分兩種情況:5后面還有其他數(shù)字(非0)喊积,則進(jìn)位后舍去;若5后面是0(即5是最后一位)玄妈,則根據(jù)5前一位數(shù)的奇偶性來(lái)判斷是否需要進(jìn)位乾吻,奇數(shù)進(jìn)位,偶數(shù)舍去措近。
};
// Rounding policies :
// Original
// value 1.2 1.21 1.25 1.35 1.27
// Plain 1.2 1.2 1.3 1.4 1.3
// Down 1.2 1.2 1.2 1.3 1.2
// Up 1.2 1.3 1.3 1.4 1.3
// Bankers 1.2 1.2 1.2 1.4 1.3
scale : 需要保留的精度溶弟。
raiseOnExactness : 為YES時(shí)在處理精確時(shí)如果有錯(cuò)誤,就會(huì)拋出異常瞭郑。
raiseOnOverflow : YES時(shí)在計(jì)算精度向上溢出時(shí)會(huì)拋出異常辜御,否則返回。
raiseOnUnderflow : YES時(shí)在計(jì)算精度向下溢出時(shí)會(huì)拋出異常屈张,否則返回.
raiseOnDivideByZero : YES時(shí)擒权。當(dāng)除以0時(shí)會(huì)拋出異常袱巨,否則返回。
*/
保留2位小數(shù)
NSDecimalNumberHandler *roundUp = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain
scale:2
raiseOnExactness:NO
raiseOnOverflow:NO
raiseOnUnderflow:NO
raiseOnDivideByZero:YES];
計(jì)算金額并四舍五入
NSDecimalNumber *originMoney = [NSDecimalNumber decimalNumberWithString:num];//通過(guò)字符串計(jì)算金額
NSDecimalNumber *roundMoney = [subtotal decimalNumberByRoundingAccordingToBehavior:roundUp];//按照設(shè)定的規(guī)則計(jì)算出金額
金額計(jì)算實(shí)例
NSDecimalNumber *varDecimal1 = [NSDecimalNumber decimalNumberWithString:@"120.661"];//120.661
NSDecimalNumber *varDecimal2 = [NSDecimalNumber decimalNumberWithString:@"120.670"];//120.670
//加
[varDecimal1 decimalNumberByAdding:varDecimal2];
//減
NSDecimalNumber *varDecimal3 = [[varDecimal2 decimalNumberBySubtracting:varDecimal1] decimalNumberByRoundingAccordingToBehavior:roundUp];//0.01
//乘
[varDecimal1 decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithString:@"0.005"]];
//除
[varDecimal1 decimalNumberByDividingBy:varDecimal2];
//比較
[varDecimal1 compare:varDecimal2] == NSOrderedAscending //varDecimal1小于varDecimal2
總結(jié)
- 金額相關(guān)碳抄,后臺(tái)要傳字符串到前臺(tái)
- 計(jì)算過(guò)程中要用NSDecimalNumber來(lái)防止計(jì)算過(guò)程中出現(xiàn)精度錯(cuò)誤
- [@"120.67" floatValue] - 0.01 不等于120.66