0

I have a Float(4.502823e-20) and I pass that to JSONEncoder to encode like,

JSONEncoder().encode(float)

When I inspect the content of the Data returned from above call, I see these values

52 46 53 48 50 56 50 50 57 54 57 48 54 48 53 52 48 54 101 45 50 48

And that translate to ascii:

4.5028229690605406e-20

which has more digitals than my input 3.402823e-20:

4.5028229690605406e-20

Can you please tell me how can we make JSONEncoder not to add digits when encode a Float?

hap497
  • 154,439
  • 43
  • 83
  • 99

1 Answers1

3

First, make sure to read Is floating point math broken? and The Floating-Point Guide. If you need a value that is a specific number of decimal digits, then you do not want Float. Float represents a binary representation of a number, which may not be equal to a decimal representation for a limited number of digits.

Swift has a decimal representation of numbers called Decimal:

let value = Decimal(string: "3.402823e-20")!

JSONEncoder doesn't encode Decimal to scientific notation, so this will be encoded as 0.00000000000000000003402823, but it will be the exact decimal value. To modify the formatting, you would need to reimplement JSONEncoder. It doesn't support arbitrary number formatting.

Alternately, if you want a specific string, you would need to encode this in JSON as a string instead of a number, and use a NumberFormatter to get the number of significant digits you want.

Note that this may bite you on the parsing side, too. JSON defines numbers in terms of decimal digits, but no parser I'm aware of actually decodes them that way. Every parser I know decodes them as some kind of binary floating point number, which may not be exactly equal to the value in the JSON.

If you need the sender and receiver to agree on the exact value of a non-integer number via JSON, you have two pretty good options: use fixed-point encoding by scaling by some value and then encoding as an integer (for example, storing cents as an integer rather than fractional dollars), or encode the number as a string and handle parsing yourself.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610