- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
与所有 IEEE 7540 系统一样,Swift 中的数字如 4.7
被视为类似 4.7000000000000002
的值.所以这并不奇怪:
% swift
Welcome to Apple Swift version 5.2.4 (swiftlang-1103.0.32.9 clang-1103.0.32.53).
Type :help for assistance.
1> 4.7
$R0: Double = 4.7000000000000002
2> 4.7 == 4.7000000000000002
$R1: Bool = true
这是一个很好理解的世界现实,因此不需要通过包含指向浮点精度损失背景文章链接的评论来解决。
JSONEncoder
编码此数字时, 我们看:
4> String(data: JSONEncoder().encode([4.7]), encoding: .utf8)
$R2: String? = "[4.7000000000000002]"
这不是错误的,正如维基百科所说
this关于 JSON 和浮点数:
The JSON standard makes no requirements regarding implementation details such as overflow, underflow, loss of precision, rounding, or signed zeros, but it does recommend to expect no more than IEEE 754 binary64 precision for "good interoperability". There is no inherent precision loss in serializing a machine-level binary representation of a floating-point number (like binary64) into a human-readable decimal representation (like numbers in JSON), and back, since there exist published algorithms to do this exactly and optimally.
% /System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Helpers/jsc
>>> 4.7 == 4.7000000000000002
true
>>> JSON.stringify([4.7000000000000002])
[4.7]
并与节点:
% node
Welcome to Node.js v13.13.0.
Type ".help" for more information.
> 4.7 == 4.7000000000000002
true
> JSON.stringify([4.7000000000000002])
'[4.7]'
对我来说,问题是我有大量的 Swift doubles 集合,当序列化为 JSON 进行存储和/或传输时,包含大量不必要的碎片(“4.7000000000000002”的字符数是“4.7”的 6 倍),从而扩大了大小序列化数据相当多。
最佳答案
您可以扩展 KeyedEncodingContainer 和 KeyedDecodingContainer 并实现自定义编码和解码方法以将 Decimal 作为纯数据发送。您只需要将编码器/解码器 dataEncodingStrategy 设置为 deferredToData。另一种可能性是编码和解码其 base64Data 或将其编码/解码为纯字符串。
extension Numeric {
var data: Data {
var bytes = self
return .init(bytes: &bytes, count: MemoryLayout<Self>.size)
}
}
extension DataProtocol {
func decode<T: Numeric>(_ codingPath: [CodingKey], key: CodingKey) throws -> T {
var value: T = .zero
guard withUnsafeMutableBytes(of: &value, copyBytes) == MemoryLayout.size(ofValue: value) else {
throw DecodingError.dataCorrupted(.init(codingPath: codingPath, debugDescription: "The key \(key) could not be converted to a numeric value: \(Array(self))"))
}
return value
}
}
extension KeyedEncodingContainer {
mutating func encode(_ value: Decimal, forKey key: K) throws {
try encode(value.data, forKey: key)
}
mutating func encodeIfPresent(_ value: Decimal?, forKey key: K) throws {
guard let value = value else { return }
try encode(value, forKey: key)
}
}
extension KeyedDecodingContainer {
func decode(_ type: Decimal.Type, forKey key: K) throws -> Decimal {
try decode(Data.self, forKey: key).decode(codingPath, key: key)
}
func decodeIfPresent(_ type: Decimal.Type, forKey key: K) throws -> Decimal? {
try decodeIfPresent(Data.self, forKey: key)?.decode(codingPath, key: key)
}
}
struct Root: Codable {
let decimal: Decimal
}
// using the string initializer for decimal is required to maintain precision
let root = Root(decimal: Decimal(string: "0.007")!)
do {
let encoder = JSONEncoder()
encoder.dataEncodingStrategy = .deferredToData
let rootData = try encoder.encode(root)
let decoder = JSONDecoder()
decoder.dataDecodingStrategy = .deferredToData
let root = try decoder.decode(Root.self, from: rootData)
print(root.decimal) // prints "0.007\n" instead of "0.007000000000000001024\n" without the custom encoding and decoding methods
} catch {
print(error)
}
extension String {
func decimal(_ codingPath: [CodingKey], key: CodingKey) throws -> Decimal {
guard let decimal = Decimal(string: self) else {
throw DecodingError.dataCorrupted(.init(codingPath: codingPath, debugDescription: "The key \(key) could not be converted to decimal: \(self)"))
}
return decimal
}
}
extension KeyedEncodingContainer {
mutating func encode(_ value: Decimal, forKey key: K) throws {
try encode(String(describing: value), forKey: key)
}
mutating func encodeIfPresent(_ value: Decimal?, forKey key: K) throws {
guard let value = value else { return }
try encode(value, forKey: key)
}
}
extension KeyedDecodingContainer {
func decode(_ type: Decimal.Type, forKey key: K) throws -> Decimal {
try decode(String.self, forKey: key).decimal(codingPath, key: key)
}
func decodeIfPresent(_ type: Decimal.Type, forKey key: K) throws -> Decimal? {
try decodeIfPresent(String.self, forKey: key)?.decimal(codingPath, key: key)
}
}
struct StringDecimal: Codable {
let decimal: Decimal
}
let root = StringDecimal(decimal: Decimal(string: "0.007")!)
do {
let stringDecimalData = try JSONEncoder().encode(root)
print(String(data: stringDecimalData, encoding: .utf8)!)
let stringDecimal = try JSONDecoder().decode(StringDecimal.self, from: stringDecimalData)
print(stringDecimal.decimal) // "0.007\n"
} catch {
print(error)
}
{"decimal":"0.007"}
0.007
关于json - Swift JSONEncoder 数字四舍五入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62995804/
我有这个“科学应用程序”,其中 Single 值在显示在 UI 中之前应该四舍五入。根据this MSDN article ,由于“精度损失”,Math.Round(Double, Int32) 方法
这个问题类似于Chrome 37 calc rounding 但实际问题有点复杂,提供的解决方案不适用于这种情况: #outerDiv, #leftDiv, #middleDiv, #rightDiv
假设有一堆从 pnorm() 返回的数据,这样您就有了 .0003ish 和 .9999ish 之间的数字。 numbers <- round(rnorm(n = 10000, mean =
我想有效地将unsigneda整数除以2的任意幂,然后取整。所以我在数学上想要的是ceiling(p/q)0。在C语言中,不利用q受限域的Strawman实现可能类似于以下function1: /
我正在尝试获取 #value_box 的值以显示 100.5 但它一直在向上舍入。有谁知道我可以做些什么来让它显示小数位? jsfiddle //returns 101 $("#value_box
我有一段 JavaScript 代码 shipingcostnumber * parseInt(tax) / 100 + shipingcostnumber 返回数字为6655.866558,因此我将
我有一个关于 PostgreSQL 9.2 中 float 的新手问题。 是否有直接舍入 float 的函数,即不必先将数字转换为数字类型? 另外,我想知道是否有一个函数可以按任意度量单位舍入,例如最
这个问题已经有答案了: Rounding to nearest 100 (7 个回答) 已关闭10 年前。 我正在尝试将数字四舍五入到 100。 示例: 1340 should become 1400
我试图找出使用整数存储在列表中的其他两个数字之间的任何n在整数列表中找到最接近的值ROUNDED DOWN的最佳方法。在这种情况下,所有整数都将始终是无符号的,以防万一。 假设如下: 列表始终从0开始
我想将一个 BigDecimal 四舍五入到小数点后两位,但是当使用 round 方法时,它似乎没有双舍入: BigDecimal.new('43382.0249').round(2).to_s('F
我正在使用格式如下的财务数据进行计算: . 基本上,在我的程序中我遇到了一个浮点错误。例如,如果我有: 11.09 - (11.09 * 0.005) = 11.03455 我希望能够使用 11.03
有整型变量,电压单位为毫伏。 signed int voltage_mv = 134; //134mV 我有 2 段显示,我想显示百分之一伏特。 如何在一次操作中将毫伏转换为百分之一伏?没有 IF 语
这是我将数字四舍五入到两位小数的函数,但是当四舍五入的数字为 1.50 时,它似乎忽略尾随零并只返回 1.5 public static double roundOff(double number)
您好,我在将数字四舍五入到 -0 而不是 0 时遇到了问题 代码: 输出:-0 预期输出:0 我一直在寻找任何解决方案,但没有找到。 请解释并帮助我为什么它四舍五入为 -0 而不是 0?谢谢 最佳答
我正在使用 Java 的 Random 生成随机数:1.0、1.1 - 10 Random random = new Random(); return (double) ((random.nextIn
基本上,我有一个数字: 我基本上想做一些数学运算来创建这个数字 80。 如果数字是 62.7777777778,则数字将为 60。 我希望数字像这样四舍五入: 20, 40, 60, 80, 100
我希望显示来自 NSDate 对象的月数。 //Make Date Six Months In The Future NSCalendar *calendar = [[NSCalendar alloc
下面是一些小代码来说明我所看到的 float floater = 59.999f; DecimalFormat df = new DecimalFormat("00.0"); System.out.p
我现在开始使用 android 和 java,但遇到了问题。 I have a result x = 206.0548. And y = 206, both of type double How do
我有一个 ruby 散列数组,其中包含两个键,'tier' 和 'price'。对于给定的价格,我想退回等级。 这对于精确匹配来说已经足够简单了,但是我如何通过将我的输入值四舍五入到数组中的下一个
我是一名优秀的程序员,十分优秀!