-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gRPC SubscribeAddedOrders
+ SubscribeRemovedOrders
float issue
#740
Comments
Can you check this one? @sangaman |
Sorry this slipped by me. I think this is a shortcoming of using This is also partly a shortcoming of whatever tool was used to create that output, but if we're seeing it there it will probably pop up elsewhere too. It's written in python right? I can think of two possible approaches:
Would be good to see if anyone else has other ideas or cleaner approaches. @moshababo @offerm Being able to see the code for the tool that created that output might help too. |
|
Getting the code of the application into our organization asap... |
Here it is: https://github.com/ExchangeUnion/xud-exchange-integration-example @sangaman , a full environment setup and ready to use in our glcoud |
Lnd is using satoshis everywhere amounts are concerned, sub-satoshis are mostly used internally. Let's discuss this on the call today since I don't think there's an obvious solution here. |
As discussed on the call we aim for integers as internal representation without decimals. As default, 9 digits form one "full" unit = we have a default precision of 8 decimals. Also this needs to be made crystal clear in the documentation (as part of this issue). |
Decimal precision with sensible defaults (10^8) sounds good to me. |
Let's discuss this on the call again since it's been a little while, although now I'm again questioning whether this is an issue worth dealing with at the moment. Changing all the internal types is a pretty big change, and it may make more sense to have clients round for display purposes. Rounding/formatting the number will have likely need to happen anyway, especially for prices. Python uses the same IEEE 754 double precision floating numbers that javascript does. |
@michael1011 as discussed in the call we stick with what we have, just add a line about this in the wiki. |
I'm very sorry to reopen this after we switched back and forth twice already, but I got a db-experienced friend over and the first thing he screamed when I showed him the And it seems he is right, floats are only a approximation of a decimal number but never precise because it's stored as binary. Currently it's not a big problem because we don't perform (many/any?) operations on prices or quantities but as soon as we do rounding errors become a real issue. So I suggest to redefine the scope of this issue to:
Source: https://husobee.github.io/money/float/2016/09/23/never-use-floats-for-currency.html |
Wei won't work I'm pretty sure because it's too small a unit to represent with 64 bit numbers. I'd say if we go this route we should stick to using 10^-8 (satoshi size) for all base units internally. It's standard for exchanges to have minimum order size increments and I think similar logic applies. Currently we track amounts of coins by integer satoshis, and order quantity/prices with floating point numbers. When we calculate amounts of satoshis, we do the multiplication/division, move the decimal point over, and round to the nearest integer. I'm still not convinced that representing price as an integer is a good idea. It's not intuitive and it won't entirely eliminate the need for rounding for times when we have to divide a number by the price. For quantities though I'm on board to switch to using satoshi integers as the base unit everywhere internally. |
Quickly checked that, you are right, even
Not intuitive, maybe. Doesn't eliminate the need for rounding: definitely not. What it DOES though is forcing everyone to perform & think about rounding when storing a result of an arithmetic operation. With float numbers one might forget that very easily. And the result becomes more inaccurate the more arithmetic operations are performed on a float value which wasn't rounded corrected manually on each step. Check another example (here)[https://dzone.com/articles/never-use-float-and-double-for-monetary-calculatio]. I just think that might seem like a small problem now, but it will be a very weird "wrong price" bug in future and hard to debug. An alternative could be BigDecimal instead of BigInt to keep the intuitivity of decimals for price. Got to pay attention how to use the constructor though as described in here. So for me there are 3 ways forward:
Actually 3. does sound like the cleanest. |
There is no native JS big integer/big decimal. We could use something like https://www.npmjs.com/package/big-js, but I believe this just does the rounding for us and I'm not familiar with this package and not sure it'd help enough to warrant another dependency. But gRPC does not have anything like big decimal, if we want a precise decimal number we'd have to use a string I'm pretty sure. We already round the result of the arithmetic operations to calculate amount based on quantity & price, and I think in this case it would be making the amount a big decimal type that would enforce rounding, not the price. You can divide two decimal numbers and wind up with a floating number. Here's what I propose:
|
Ok. Please check if you agree with Daniel and if so go ahead with his approach. @michael1011 |
Thanks. I think another key point here is that the price, once set, does not change. I suspect that the quantity may have been going off by microscopic amounts when we updated it. I created a jsfiddle to recreate a similar error: https://jsfiddle.net/sangaman/rce4kx30/ const x = 1.3498;
const y = x - 1.1111;
const z = y - 0.2387; It simulates an order with a quantity of |
LGTM @michael1011 |
This commit changes all `quantity` values to be represented by integer satoshi amounts (10 ^ -8 of a full unit) rather than fractional/floating full units. This applies both to the internal representations as well as the gRPC API definition. This is done to prevent any rounding errors when adding or subtracting fractional units. Output and arguments for the cli remain unchanged and still deal with full units. Closes #740. BREAKING CHANGE: Database and p2p field type changes
This commit changes all `quantity` values to be represented by integer satoshi amounts (10 ^ -8 of a full unit) rather than fractional/floating full units. This applies both to the internal representations as well as the gRPC API definition. This is done to prevent any rounding errors when adding or subtracting fractional units. Output and arguments for the cli remain unchanged and still deal with full units. Fixes #740. BREAKING CHANGE: Database and p2p field type changes
This commit changes all `quantity` values to be represented by integer satoshi amounts (10 ^ -8 of a full unit) rather than fractional/floating full units. This applies both to the internal representations as well as the gRPC API definition. This is done to prevent any rounding errors when adding or subtracting fractional units. Output and arguments for the cli remain unchanged and still deal with full units. Fixes #740. BREAKING CHANGE: Database and p2p field type changes
This commit changes all `quantity` values to be represented by integer satoshi amounts (10 ^ -8 of a full unit) rather than fractional/floating full units. This applies both to the internal representations as well as the gRPC API definition. This is done to prevent any rounding errors when adding or subtracting fractional units. Output and arguments for the cli remain unchanged and still deal with full units. Fixes #740. BREAKING CHANGE: Database and p2p field type changes
should be
23.9781
The text was updated successfully, but these errors were encountered: