iOS端浮点数精度处理

做这么久coder了,才碰到了客户端与服务端传递浮点数的问题,说起来有点惭愧。
场景是这样的:
服务端需要我这边上传一个1位小数位的浮点数,比如@0.6这样,我直接就这样放到字典里传过去,到服务端拿到的变成了0.59999999993或者0.6000000007,出现了精度丢失。我很纳闷,在我这边的log里显示的明明是0.6,开始以为是服务端做了哪些处理,服务端说他们是直接拿到数据就入库,没有别的操作,并且Android那边传的就没问题。我只能一步步调试自己的代码,最终发现问题出现在这一步:NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 error:nil];,就是字典序列化为二进制数据时,浮点数精度出现了丢失,然后我以为是options这个参数的问题,就试了所有的选项

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

结果不如我所愿,不是参数的问题,用以上那些option结果一样。
经过一番查找,发现有NSDecimalNumber这样一个处理浮点数的类,继承自NSNumber,有这么几个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;

网上有很多关于这个类的用法,很多还挺复杂,我直接用这个类方法

+ (NSDecimalNumber *)decimalNumberWithString:(nullable NSString *)numberValue;

搞定。
至于为什么会出现这样的问题,经过跟公司的一个大牛探讨,说是浮点数会有一个上下浮动的微小区间,用浮点数转换时变成这个区间的任何一个数都是正常的,计算机就是这么处理的。PS:大牛还大骂设计这个接口的人不专业,有涉及到浮点数精度问题时不要用double类型,转换成int处理会更好。

你可能感兴趣的:(iOS端浮点数精度处理)