我尝试在Double
生成的某些JSON中包含0.81
NSJSONSerialization
值let jsonInput = [ "value": 0.81 ]
let data = try NSJSONSerialization.dataWithJSONObject(jsonInput, options: NSJSONWritingOptions.PrettyPrinted)
let json = NSString(data: data, encoding: NSUTF8StringEncoding)!
print( json )
。代码如下:
{
"value" : 0.8100000000000001
}
输出结果为:
{
"value" : 0.81
}
但我希望看到的是:
NSJSONSerialization
如何让Double
执行此操作?
另一件令我困惑的事情是Swift对64位let eightOne:Double = 0.81
"\(eightOne)"
print( eightOne )
的处理。在操场上我也可以这样做:
0.81
然后根据需要输出:
eightOne
即使在操场上,就内部表示而言,0.8100000000000001
显示为BigDecimals
。然而,当它转换为字符串时,它会切断其余部分。
我确实已经解决了这个问题,因为您需要对任何类型的财务处理进行排序(例如,在Java中,我们知道在财务价值方面我们只使用NSString( format: "%\(0.2)f", 0.81)
)
请帮忙。 :)
注意:此处的重点是序列化为JSON。不只是简单地致电dynamicType
。
答案 0 :(得分:2)
用于精确的base-10算术(最多38位有效数字)
你可以使用NSDecimalNumber
:
let jsonInput = [ "value": NSDecimalNumber(string: "0.81") ]
或
let val = NSDecimalNumber(integer: 81).decimalNumberByDividingBy(NSDecimalNumber(integer: 100))
let jsonInput = [ "value": val ]
然后
let data = try NSJSONSerialization.dataWithJSONObject(jsonInput, options: NSJSONWritingOptions.PrettyPrinted)
let json = NSString(data: data, encoding: NSUTF8StringEncoding)!
print( json )
产生输出
{
"value" : 0.81
}
答案 1 :(得分:0)
您需要将Double
转换为Decimal
以在序列化时保留其预期的字符串表示形式。一种方法是:
(0.81 as NSNumber).decimalValue
要自动和递归地对JSON对象中的所有Double
值执行此操作,无论是Dictionary还是Array,您都可以使用:
import Foundation
/// https://stackoverflow.com/q/35053577/1033581
extension JSONSerialization {
/// Produce Double values as Decimal values.
open class func decimalData(withJSONObject obj: Any, options opt: JSONSerialization.WritingOptions = []) throws -> Data {
return try data(withJSONObject: decimalObject(obj), options: opt)
}
/// Write Double values as Decimal values.
open class func writeDecimalJSONObject(_ obj: Any, to stream: OutputStream, options opt: JSONSerialization.WritingOptions = [], error: NSErrorPointer) -> Int {
return writeJSONObject(decimalObject(obj), to: stream, options: opt, error: error)
}
fileprivate static func decimalObject(_ anObject: Any) -> Any {
let value: Any
if let n = anObject as? [String: Any] {
// subclassing children
let dic = DecimalDictionary()
n.forEach { dic.setObject($1, forKey: $0) }
value = dic
} else if let n = anObject as? [Any] {
// subclassing children
let arr = DecimalArray()
n.forEach { arr.add($0) }
value = arr
} else if let n = anObject as? NSNumber, CFNumberGetType(n) == .float64Type {
// converting precision for correct decimal output
value = n.decimalValue
} else {
value = anObject
}
return value
}
}
private class DecimalDictionary: NSDictionary {
let _dictionary: NSMutableDictionary = [:]
override var count: Int {
return _dictionary.count
}
override func keyEnumerator() -> NSEnumerator {
return _dictionary.keyEnumerator()
}
override func object(forKey aKey: Any) -> Any? {
return _dictionary.object(forKey: aKey)
}
func setObject(_ anObject: Any, forKey aKey: String) {
let value = JSONSerialization.decimalObject(anObject)
_dictionary.setObject(value, forKey: aKey as NSString)
}
}
private class DecimalArray: NSArray {
let _array: NSMutableArray = []
override var count: Int {
return _array.count
}
override func object(at index: Int) -> Any {
return _array.object(at: index)
}
func add(_ anObject: Any) {
let value = JSONSerialization.decimalObject(anObject)
_array.add(value)
}
}
JSONSerialization.decimalData(withJSONObject: [ "value": 0.81 ], options: [])
如果您需要对小数格式进行微调,可以在Specify number of decimals when serializing currencies with JSONSerialization上查看Eneko Alonso的答案。
答案 2 :(得分:0)
如果您使用了' NSDecimalNumber'需求时,建议封装以方便使用并减少错误。
这里是Demo供您参考,使用简单。希望可以帮助您!
switch (operatorType) {
case 0:
resultNumber = SNAdd(_cardinalNumberTextField.text, _complementNumberTextField.text);
break;
case 1:
resultNumber = SNSub(_cardinalNumberTextField.text, _complementNumberTextField.text);
break;
case 2:
resultNumber = SNMul(_cardinalNumberTextField.text, _complementNumberTextField.text);
break;
case 3:
resultNumber = SNDiv(_cardinalNumberTextField.text, _complementNumberTextField.text);
break;
}