FRMSKI開発ブログ

プログラミング、UI / UX、仕事、読書のことなど、日々の記録を綴ります

JSONEncoderで小数点以下が正確な数値にエンコードされない問題の解決法

JSONEncoderで文字列を出力する時に、Doubleで値を持つと小数点以下の桁数が正確に出力されない場合があります。こういった問題はDecimal型で出力すると解決できます。 下記のソースはDouble型で出力した例です。

struct SaveData{
        save_number:Double
}
    
class Test{
        func testEncode(){
            let number:Double = 12.345678
            let savedata:SaveData = SaveData(
                save_number:number
            )
            let encoder = JSONEncoder()
            let data = encoder.encode(savedata)
            let str:String(data,encoding:.utf8)
            print(str) //出力 { "number" : 12.34567800000000002 }
        }
}

本来小数点以下は6桁のはずが0000~と不要な数字が入っています。
解決策としては、下記のようにStringからDecimal型に変換することで正確に出力されます。

struct SaveData{
        save_number:Decimal
}
    
class Test{
        func testEncode(){
            let number:String = "12.345678"
            let savedata:SaveData = SaveData(
                save_number:Decimal(string:number)
            )
            let encoder = JSONEncoder()
            let data = encoder.encode(savedata)
            let str:String(data,encoding:.utf8)
            print(str) //出力 { "number" : 12.345678 }
        }
}

Double型は2の累乗を用いて値を表すため、10進数の小数を扱うと誤差が出ます。 Decimal型は10の累乗を用いて値を表すため、10進数を誤差なく表すことができます。
小数点以下を正確に表示する場合はDecimal型を使いましょう。