做這么久coder了吩坝,才碰到了客戶(hù)端與服務(wù)端傳遞浮點(diǎn)數(shù)的問(wèn)題不恭,說(shuō)起來(lái)有點(diǎn)慚愧。
場(chǎng)景是這樣的:
服務(wù)端需要我這邊上傳一個(gè)1位小數(shù)位的浮點(diǎn)數(shù)解阅,比如@0.6
這樣,我直接就這樣放到字典里傳過(guò)去泌霍,到服務(wù)端拿到的變成了0.59999999993
或者0.6000000007
货抄,出現(xiàn)了精度丟失。我很納悶,在我這邊的log里顯示的明明是0.6
蟹地,開(kāi)始以為是服務(wù)端做了哪些處理积暖,服務(wù)端說(shuō)他們是直接拿到數(shù)據(jù)就入庫(kù),沒(méi)有別的操作怪与,并且Android那邊傳的就沒(méi)問(wèn)題夺刑。我只能一步步調(diào)試自己的代碼,最終發(fā)現(xiàn)問(wèn)題出現(xiàn)在這一步:NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 error:nil];
琼梆,就是字典序列化為二進(jìn)制數(shù)據(jù)時(shí)性誉,浮點(diǎn)數(shù)精度出現(xiàn)了丟失,然后我以為是options
這個(gè)參數(shù)的問(wèn)題茎杂,就試了所有的選項(xiàng)
typedef NS_OPTIONS(NSUInteger, NSJSONWritingOptions) {
NSJSONWritingPrettyPrinted = (1UL << 0),
/* Sorts dictionary keys for output using [NSLocale systemLocale]. Keys are compared using NSNumericSearch. The specific sorting method used is subject to change.
*/
NSJSONWritingSortedKeys API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0)) = (1UL << 1),
NSJSONWritingFragmentsAllowed = (1UL << 2),
NSJSONWritingWithoutEscapingSlashes API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) = (1UL << 3),
} API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
結(jié)果不如我所愿错览,不是參數(shù)的問(wèn)題,用以上那些option結(jié)果一樣煌往。
經(jīng)過(guò)一番查找倾哺,發(fā)現(xiàn)有NSDecimalNumber
這樣一個(gè)處理浮點(diǎn)數(shù)的類(lèi),繼承自NSNumber
刽脖,有這么幾個(gè)api可以用:
- (instancetype)initWithMantissa:(unsigned long long)mantissa exponent:(short)exponent isNegative:(BOOL)flag;
- (instancetype)initWithDecimal:(NSDecimal)dcm NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithString:(nullable NSString *)numberValue;
- (instancetype)initWithString:(nullable NSString *)numberValue locale:(nullable id)locale;
- (NSString *)descriptionWithLocale:(nullable id)locale;
+ (NSDecimalNumber *)decimalNumberWithMantissa:(unsigned long long)mantissa exponent:(short)exponent isNegative:(BOOL)flag;
+ (NSDecimalNumber *)decimalNumberWithDecimal:(NSDecimal)dcm;
+ (NSDecimalNumber *)decimalNumberWithString:(nullable NSString *)numberValue;
+ (NSDecimalNumber *)decimalNumberWithString:(nullable NSString *)numberValue locale:(nullable id)locale;
網(wǎng)上有很多關(guān)于這個(gè)類(lèi)的用法羞海,很多還挺復(fù)雜,我直接用這個(gè)類(lèi)方法
+ (NSDecimalNumber *)decimalNumberWithString:(nullable NSString *)numberValue;
搞定曲管。
至于為什么會(huì)出現(xiàn)這樣的問(wèn)題却邓,經(jīng)過(guò)跟公司的一個(gè)大牛探討,說(shuō)是浮點(diǎn)數(shù)會(huì)有一個(gè)上下浮動(dòng)的微小區(qū)間院水,用浮點(diǎn)數(shù)轉(zhuǎn)換時(shí)變成這個(gè)區(qū)間的任何一個(gè)數(shù)都是正常的腊徙,計(jì)算機(jī)就是這么處理的。PS:大牛還大罵設(shè)計(jì)這個(gè)接口的人不專(zhuān)業(yè)檬某,有涉及到浮點(diǎn)數(shù)精度問(wèn)題時(shí)不要用double
類(lèi)型撬腾,轉(zhuǎn)換成int
處理會(huì)更好。