issue when i parsing with double

Hi many thanks for the help till now.


i got an strange result after parsing. i use this code:


import Foundation


struct CurrencyStore {
    var name: String
    var currencies: [Currency]

    struct Currency: Codable{
        var symbol1: String
        var symbol2: String
        var minLotSize: Double
        var minLotSizeS2: Double
        var maxLotSize: Double?
        var maxPrice: String
        var minPrice: String
    }
}

let json = """
{"e":"currency_limits","ok":"ok","data":{"pairs":[{"symbol1":"BTC","symbol2":"USD","minLotSize":0.01,"minLotSizeS2":2.5,"maxLotSize":30,"minPrice":"100","maxPrice":"35000"},{"symbol1":"ETH","symbol2":"USD","minLotSize":0.1,"minLotSizeS2":2.5,"maxLotSize":1000,"minPrice":"2.5","maxPrice":"1024"},{"symbol1":"BCH","symbol2":"USD","minLotSize":0.01,"minLotSizeS2":2.5,"maxLotSize":30,"minPrice":"50","maxPrice":"5128"},{"symbol1":"BTG","symbol2":"USD","minLotSize":0.01,"minLotSizeS2":2.5,"maxLotSize":null,"minPrice":"2.5","maxPrice":"2048"},{"symbol1":"DASH","symbol2":"USD","minLotSize":0.01,"minLotSizeS2":2.5,"maxLotSize":null,"minPrice":"2.5","maxPrice":"1024"},{"symbol1":"XRP","symbol2":"USD","minLotSize":10,"minLotSizeS2":2.5,"maxLotSize":null,"minPrice":"0.005","maxPrice":"50"},{"symbol1":"ZEC","symbol2":"USD","minLotSize":0.01,"minLotSizeS2":2.5,"maxLotSize":null,"minPrice":"2.5","maxPrice":"1024"},{"symbol1":"BTC","symbol2":"EUR","minLotSize":0.01,"minLotSizeS2":2.2,"maxLotSize":30,"minPrice":"100.00","maxPrice":"35000"}]}}
""".data(using: .utf8)!

struct CurrencyStoreService: Decodable {

    let e: String
    let ok: String
    let data: NestedData

    struct NestedData: Decodable {
        let pairs: [CurrencyStore.Currency]
    }
}

extension CurrencyStore {
    init(from CurrencyStoreService: CurrencyStoreService) {
        name = CurrencyStoreService.ok
        currencies = []
    }
}

do {
    let decoder = JSONDecoder()
    let serverData = try decoder.decode(CurrencyStoreService.self, from: json)
    print(serverData.data.pairs)

} catch let jsonErr {
    print(jsonErr)

}


this gives me this output:

[xxst.CurrencyStore.Currency(symbol1: "BTC", symbol2: "USD", minLotSize: 0.01, minLotSizeS2: 2.5, maxLotSize: Optional(30.0), maxPrice: "35000", minPrice: "100"), xxst.CurrencyStore.Currency(symbol1: "ETH", symbol2: "USD", minLotSize: 0.10000000000000001, minLotSizeS2: 2.5, maxLotSize: Optional(1000.0), maxPrice: "1024", minPrice: "2.5"), xxst.CurrencyStore.Currency(symbol1: "BCH", symbol2: "USD", minLotSize: 0.01, minLotSizeS2: 2.5, maxLotSize: Optional(30.0), maxPrice: "5128", minPrice: "50"), xxst.CurrencyStore.Currency(symbol1: "BTG", symbol2: "USD", minLotSize: 0.01, minLotSizeS2: 2.5, maxLotSize: nil, maxPrice: "2048", minPrice: "2.5"), xxst.CurrencyStore.Currency(symbol1: "DASH", symbol2: "USD", minLotSize: 0.01, minLotSizeS2: 2.5, maxLotSize: nil, maxPrice: "1024", minPrice: "2.5"), xxst.CurrencyStore.Currency(symbol1: "XRP", symbol2: "USD", minLotSize: 10.0, minLotSizeS2: 2.5, maxLotSize: nil, maxPrice: "50", minPrice: "0.005"), xxst.CurrencyStore.Currency(symbol1: "ZEC", symbol2: "USD", minLotSize: 0.01, minLotSizeS2: 2.5, maxLotSize: nil, maxPrice: "1024", minPrice: "2.5"), xxst.CurrencyStore.Currency(symbol1: "BTC", symbol2: "EUR", minLotSize: 0.01, minLotSizeS2: 2.2000000000000002, maxLotSize: Optional(30.0), maxPrice: "35000", minPrice: "100.00")]

Program ended with exit code: 0


the undelined bold is the strange thing...

it seems that some times the real value will be extended with some numbers.

i see no reason why...


has some one an hint for me?

Accepted Reply

If you feel the result as strange thing , you need to learn about how numbers are represented in computers.


Shortly, binary floating point system (Float or Double in Swift) cannot represent decimal `0.1` or `2.2` exactly as expected from the decimal point of view.


A little more compact example will show you the strange thing. No parsing nor codable is needed:

struct DoubleHolder {
    var value: Double
}
let dh1 = DoubleHolder(value: 0.1)
print(dh1, dh1.value) //->DoubleHolder(value: 0.10000000000000001) 0.1
let dh2 = DoubleHolder(value: 2.2)
print(dh2, dh2.value) //->DoubleHolder(value: 2.2000000000000002) 2.2


When you write a numeric literal `0.1` as Double, the actual value cannot be the exact number 0.1 .

Some binary floating point to decimal conversion shows it as 0.10000000000000001, and another conversion would show it as 0.1.


You may need to use Decimal type, or just need a controlled binary floating point to decimal conversion, which depends on your requirement.


And remember, usually JSON numbers are treated as Double (or equivalent binary floating point numbers), so using Decimal with JSON may cause unexpected result. If you want to represent a precise number in JSON, use only integer or string.

Replies

If you feel the result as strange thing , you need to learn about how numbers are represented in computers.


Shortly, binary floating point system (Float or Double in Swift) cannot represent decimal `0.1` or `2.2` exactly as expected from the decimal point of view.


A little more compact example will show you the strange thing. No parsing nor codable is needed:

struct DoubleHolder {
    var value: Double
}
let dh1 = DoubleHolder(value: 0.1)
print(dh1, dh1.value) //->DoubleHolder(value: 0.10000000000000001) 0.1
let dh2 = DoubleHolder(value: 2.2)
print(dh2, dh2.value) //->DoubleHolder(value: 2.2000000000000002) 2.2


When you write a numeric literal `0.1` as Double, the actual value cannot be the exact number 0.1 .

Some binary floating point to decimal conversion shows it as 0.10000000000000001, and another conversion would show it as 0.1.


You may need to use Decimal type, or just need a controlled binary floating point to decimal conversion, which depends on your requirement.


And remember, usually JSON numbers are treated as Double (or equivalent binary floating point numbers), so using Decimal with JSON may cause unexpected result. If you want to represent a precise number in JSON, use only integer or string.