CoinCircle/py-etherdelta

Convert Scientific Notation to Int Precision Problem

Closed this issue · 2 comments

I was using the client.trade() function to buy Cobinhood, here is the sell order:

  "sells": {
    "amount": "-2.367e+21", 
    "amountFilled": null, 
    "amountGet": "447363000000000000", 
    "amountGive": "2.367e+21", 
    "availableVolume": "2.362e+21", 
    "availableVolumeBase": "446418000000000000", 
    "ethAvailableVolume": "2362", 
    "ethAvailableVolumeBase": "0.446418", 
    "expires": "5292321", 
    "id": "11fe2d956845bb5fc2ca05b6d655f04c43b5caaaac798a95f157d3d1964a853e_sell", 
    "nonce": "3592513099", 
    "price": "0.000189", 
    "r": "0x16a39aa3d4c1494799f5130530425b989a52b82d48e007f8daa1a49e991e528c", 
    "s": "0x3084e4f66ac78795ce688451fda68840e5373e9e2fbcbc613f3208f9e03b766a", 
    "tokenGet": "0x0000000000000000000000000000000000000000", 
    "tokenGive": "0xb2f7eb1f2c37645be61d73953035360e768d81e6", 
    "updated": "2018-03-19T11:02:08.951Z", 
    "user": "0xa330a750abca19b79640ee7db1b9d06226b6486d", 
    "v": 28
  }

As you can see the amount give is 2.367e+21 which should be 2367 cobinhood (18 decimal). However when you convert this scientific notation to int. Here is result:

>>> int(float("2.367e+21"))
2367000000000000262144

This will end up with hex value: 00000000000000000000000000000000000000000000008050b94718b5a00000

The correct amount give should be 2367000000000000000000 with hex value: 00000000000000000000000000000000000000000000008050b94718b59c0000

This leads to a transaction failure.

I do the following precision test:

>>> int(float("2.367e+6"))
2367000
>>> int(float("2.367e+10"))
23670000000
>>> int(float("2.367e+20"))
236700000000000000000
>>> int(float("2.367e+21"))
2367000000000000262144
>>> int(float("2.367e+26"))
236700000000000012188647424

As you can see that starting from 10 to 21 power, the results are wrong.

I found the solution. We should use decimal library Decimal type instead of float:

Decimal numbers can be represented exactly. In contrast, numbers like 1.1 and 2.2 do not have exact representations in binary floating point. End users typically would not expect 1.1 + 2.2 to display as 3.3000000000000003 as it does with binary floating point.