Swift发送HTTP请求时数值精度异常:实际值被追加000000000000001
这个问题本质是浮点数精度不匹配导致的:Swift的Double是64位双精度浮点数,而Java的float是32位单精度浮点数,两者能精确表示的数值范围和精度不同。当你用JSONSerialization序列化Double类型的1.6时,由于二进制浮点数无法精确表示1.6这个十进制小数,会被存储为近似值1.6000000000000001,而Java的float无法识别这个超出自身精度范围的数值,导致请求被拒绝。
下面给你几个可行的解决方案:
1. 将Double转换为Swift Float后再序列化
Swift的Float和Java的float都是32位单精度浮点数,精度完全匹配。把你的amount从Double转成Float后再放入JSON对象,序列化后的数值会被自动舍入到Javafloat能识别的精度范围内:
// 假设原amount是Double类型 let originalAmount: Double = 1.6 // 转换为与Java float兼容的单精度浮点数 let compatibleAmount = Float(originalAmount) var jsonObject = ["amount": compatibleAmount] let jsonData = try! JSONSerialization.data(withJSONObject: jsonObject) // 后续请求代码不变 var request = URLRequest(url: url) request.httpBody = jsonData let task = URLSession.shared.dataTask(with: request) task.resume()
这样序列化后的JSON里,amount的值会是1.6,而不是那个超长的近似值,完美适配后端的float类型。
2. 使用Codable配合Float类型(更现代的方案)
如果你项目中用Codable做JSON序列化(推荐替代JSONSerialization),只需要在数据模型中把amount的类型定义为Float即可:
struct PaymentRequest: Codable { let amount: Float // 用Float替代Double } // 构造请求数据 let requestData = PaymentRequest(amount: Float(1.6)) let jsonData = try! JSONEncoder().encode(requestData) // 后续请求逻辑同上 var request = URLRequest(url: url) request.httpBody = jsonData let task = URLSession.shared.dataTask(with: request) task.resume()
这种方式类型更安全,也能避免手动处理JSON字典的麻烦。
3. 针对货币/高精度场景的补充方案
如果你的amount是货币类的数值(需要精确到分),建议先使用Decimal类型来保证精确性,再转换为Float:
// 用Decimal精确表示十进制数值 let amountDecimal = Decimal(string: "1.6")! // 转换为Float(适配后端类型) let compatibleAmount = Float(truncating: amountDecimal as NSNumber) var jsonObject = ["amount": compatibleAmount] let jsonData = try! JSONSerialization.data(withJSONObject: jsonObject)
这个方法能避免在计算过程中出现精度丢失,再转成Float适配后端。
备选建议(如果能修改后端)
如果有条件的话,建议后端把API的amount类型从float改成double(Java的double是64位双精度,和Swift的Double完全匹配),这样从根源上解决精度不兼容的问题,后续也不用在客户端做额外处理。
内容的提问来源于stack exchange,提问作者AleGiovane

