Bitcoin Forum
December 10, 2016, 10:24:24 PM *
News: To be able to use the next phase of the beta forum software, please ensure that your email address is correct/functional.
 
   Home   Help Search Donate Login Register  
Pages: [1] 2 »  All
  Print  
Author Topic: 21million BTC is just over 51 bits of precision...  (Read 4084 times)
Gavin Andresen
Legendary
*
qt
Offline Offline

Activity: 1652


Chief Scientist


View Profile WWW
January 29, 2011, 02:28:26 AM
 #1

luke-jr's patches got me thinking about whether or not passing double-precision values over the JSON-RPC api would ever cause problems.  I've convinced myself it isn't an issue:

JSON numbers are 64-bit double-precision floating point values, which have 53 bits of precision.

21 million bitcoins is actually 2,100,000,000,000,000 (2.1 quadrillion) of the smallest possible unit.  That's a bit over 251 -- you need just over 51 bits to represent them.

So, unless your JSON library is buggy, you should never run into rounding errors converting to/from JSON, even if you're sending 0.00000001 bitcoins.

How often do you get the chance to work on a potentially world-changing project?
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction. Advertise here.
1481408664
Hero Member
*
Offline Offline

Posts: 1481408664

View Profile Personal Message (Offline)

Ignore
1481408664
Reply with quote  #2

1481408664
Report to moderator
theymos
Administrator
Legendary
*
expert
Offline Offline

Activity: 2506


View Profile
January 29, 2011, 07:27:13 AM
 #2

I've observed float-type errors (0.9999999, etc.) from bitcoind output (when using bitcoind as the RPC client), though this was in a very old release. Does Bitcoin still do this? (I patched my version to use strings for all numbers.)

1NXYoJ5xU91Jp83XfVMHwwTUyZFK64BoAD
mrb
Legendary
*
Offline Offline

Activity: 1120


View Profile WWW
January 29, 2011, 08:11:14 AM
 #3

gavinandresen: Murphy's Law states that some JSON libs are broken. Use integers, don't use floating point.

Smiley
ribuck
Donator
Legendary
*
Offline Offline

Activity: 826


View Profile
January 29, 2011, 12:05:36 PM
 #4

Murphy's Law states that some JSON libs are broken. Use integers, don't use floating point.
If you have enough bits of floating point precision, you can represent integers safely and exactly. But you can't do the same for decimal fractions, due to the binary representation within the floating point value.

So if you represent the bitcoins as bitdust (2,100,000,000,000,000) rather than as coins (21,000,000.00000000) it should work unless the library is extremely broken (in which case it's likely to be extremely broken for integers too).

But ... what about when the whole world is using bitcoin and the precision gets extended beyond 51 bits?
Mike Hearn
Legendary
*
expert
Offline Offline

Activity: 1526


View Profile
January 29, 2011, 12:31:29 PM
 #5

I really don't think BitCoins should ever be represented as floats except for presentation to humans.

At some point it's quite possible that we'll want to move the decimal place around. If anything it'd be good to start thinking about how to organize that. Having the point hard-coded into APIs would cause issues.
Luke-Jr
Legendary
*
expert
Offline Offline

Activity: 2100



View Profile
January 29, 2011, 03:17:45 PM
 #6

But ... what about when the whole world is using bitcoin and the precision gets extended beyond 51 bits?
As I understand it, precision cannot be extended without rewriting the whole system and starting from a new genesis (which might be a copy of the old "final block" I suppose). In any case, 51 bits of precision does seem to be enough, even for the whole world: Tonal BitCoin is based on 1,0000 (65,536 decimal) base units, which yields a maximum of 7,750,54.00 (32 billion decimal) TBC-- enough for 4 TBC per human, if every human (unlikely the entire world adopts BitCoin anyway) had the same number (which is itself unlikely too). From there, there are still 16 bits of precision left for division into 1,0000 (65,536 decimal) TBCᵇ pieces. Worst case, each of these TBCᵇ should still be small enough for any significant spending, and smaller divisions could be done with a separate micro-transaction network trading 1000:1 with these.

Gavin Andresen
Legendary
*
qt
Offline Offline

Activity: 1652


Chief Scientist


View Profile WWW
January 29, 2011, 03:27:44 PM
 #7

ribuck:

Accuracy/precision is a red-herring unless you're treating numbers as strings, since JSON-RPC numbers ARE ALWAYS double-precision floating point numbers (according to the JavaScript/ECMAScript spec).  Bitcoin could send a number that looks like 2100000000000001, but the code that interprets that JSON-RPC number will convert it into an inexact double-precision floating-point equivalent.  And then the code that displays that number will have to decide how to round and format that inexact floating point number and display it to the user.

When we need more than 51 bits of precision (wouldn't THAT be a fantastic problem to have!), then we'd HAVE to send numbers as strings, and have the JavaScript (or whatever) on the other end feed them into a bignum-type library to handle them.

How often do you get the chance to work on a potentially world-changing project?
Luke-Jr
Legendary
*
expert
Offline Offline

Activity: 2100



View Profile
January 29, 2011, 03:31:36 PM
 #8

JSON-RPC numbers ARE ALWAYS double-precision floating point numbers (according to the JavaScript/ECMAScript spec).
JSON is not defined by the ECMAScript standard. The actual JSON standard does not define any precision, or even that numbers are floating-point.

ribuck
Donator
Legendary
*
Offline Offline

Activity: 826


View Profile
January 29, 2011, 06:21:41 PM
 #9

Bitcoin could send a number that looks like 2100000000000001, but the code that interprets that JSON-RPC number will convert it into an inexact double-precision floating-point equivalent.  And then the code that displays that number will have to decide how to round and format that inexact floating point number and display it to the user.

Gavin, my point is this:

The integer 2100000000000001 is within the range that is represented EXACTLY in double-precision floating point. On the other hand, the number 2100000.000000001 is not (and cannot be) represented exactly in double precision floating point (because it has a decimal fraction part that cannot be exactly represented in the binary encoding used for floating point).

The limit for exact integer representation in a double precision floating point number is 9,007,199,254,740,992 which is sufficient for Bitcoin's needs.

Perhaps you understood that I was saying that, and are pointing out that we are at the mercy of JSON libraries that might not correctly handle the conversion from integer to double-precision.

If the libraries are that buggy, it's pretty sad.
Luke-Jr
Legendary
*
expert
Offline Offline

Activity: 2100



View Profile
January 29, 2011, 08:01:03 PM
 #10

The integer 2100000000000001 is within the range that is represented EXACTLY in double-precision floating point. On the other hand, the number 2100000.000000001 is not (and cannot be) represented exactly in double precision floating point (because it has a decimal fraction part that cannot be exactly represented in the binary encoding used for floating point).

The limit for exact integer representation in a double precision floating point number is 9,007,199,254,740,992 which is sufficient for Bitcoin's needs.
But so long as we are working in base units, there is no reason to use floating-point rather than a simple int64...

ribuck
Donator
Legendary
*
Offline Offline

Activity: 826


View Profile
January 29, 2011, 08:36:17 PM
 #11

...there is no reason to use floating-point rather than a simple int64...
JSON-RPC doesn't support an Integer type. So it's floating-point or string.
Luke-Jr
Legendary
*
expert
Offline Offline

Activity: 2100



View Profile
January 29, 2011, 08:52:12 PM
 #12

...there is no reason to use floating-point rather than a simple int64...
JSON-RPC doesn't support an Integer type. So it's floating-point or string.
Actually, JSON-RPC doesn't support integer nor floating-point. It supports "number", which is not necessarily either.

jgarzik
Legendary
*
qt
Offline Offline

Activity: 1470


View Profile
January 29, 2011, 09:12:22 PM
 #13

Actually, JSON-RPC doesn't support integer nor floating-point. It supports "number", which is not necessarily either.

Irrelevant distinction.  The definition of "number" requires support for decimal numbers.

That said, many libraries are smart -- such as jansson -- and will evaluate a number directly into an integer.

Jeff Garzik, bitcoin core dev team and BitPay engineer; opinions are my own, not my employer.
Donations / tip jar: 1BrufViLKnSWtuWGkryPsKsxonV2NQ7Tcj
Gavin Andresen
Legendary
*
qt
Offline Offline

Activity: 1652


Chief Scientist


View Profile WWW
January 29, 2011, 09:30:37 PM
 #14

That said, many libraries are smart -- such as jansson -- and will evaluate a number directly into an integer.
From the jansson docs:

"integer numbers whose absolute values are too large to be represented in the int type will result in an overflow error"

As I said in the thread about possibly changing the ECDSA curve bitcoin uses, programmers like to solve "problems" that they know they can solve and that they think will make things a little bit better.  But, in my humble opinion, unless you're solving an important problem changing things because you think you know how is often a bad idea.

This is a perfect example:  change the RPC to spit out 64-bit integers (or move to a new RPC that spits out integers) and anybody using jansson on a 32-bit-int platform will get an overflow error.

I kind of like tcatm's suggestion to define new RPC methods that specify a base unit using strings... but then I thought more about it:

We could use scientific notation, so 1 BTC would be 1e08 base units; then if we ever needed more precision the JSON interface wouldn't change, you could just specify 1e-03 as a value....
... but that's exactly what we have now.  1 BTC is 1e00, 1 base unit is 1e-08, and if we ever needed more precision the JSON interface is ready.

How often do you get the chance to work on a potentially world-changing project?
Luke-Jr
Legendary
*
expert
Offline Offline

Activity: 2100



View Profile
January 29, 2011, 11:52:51 PM
 #15

As I said in the thread about possibly changing the ECDSA curve bitcoin uses, programmers like to solve "problems" that they know they can solve and that they think will make things a little bit better.  But, in my humble opinion, unless you're solving an important problem changing things because you think you know how is often a bad idea.

This is a perfect example:  change the RPC to spit out 64-bit integers (or move to a new RPC that spits out integers) and anybody using jansson on a 32-bit-int platform will get an overflow error.
OR, anyone using jansson would simply have to use (non-fractional) floats. As mentioned earlier, float types can represent the full range of base bitcoins fine, so long as they're not represented as decimal values.
I kind of like tcatm's suggestion to define new RPC methods that specify a base unit using strings... but then I thought more about it:

We could use scientific notation, so 1 BTC would be 1e08 base units; then if we ever needed more precision the JSON interface wouldn't change, you could just specify 1e-03 as a value....
... but that's exactly what we have now.  1 BTC is 1e00, 1 base unit is 1e-08, and if we ever needed more precision the JSON interface is ready.
1e8 is a perfectly legal JSON number. 1 BTC shouldn't be 1e00, it should be 1e8. And no matter how it is written (0.001 or 1e-03), the fractional-floating-point issues remain.

This works fine with the neutral branch: ./bitcoind -rpcversion=1 sendtoaddress 1KczVqwopWXQdFLe5sNQbpCq7yGSmXx2oo 1e8

mrb
Legendary
*
Offline Offline

Activity: 1120


View Profile WWW
January 30, 2011, 12:06:40 AM
 #16

ribuck makes a valid point why double-precision floating point does not work. To make my own example, if the exact value 3000000.00000001 (about 3M) is stored in a double-precision floating point number, it will be stored as approximately as 3000000.0000000098. Therefore doing any math on this number risks amplifying the rounding error (eg. calculating compounded interest, etc).

To quote an adage from the embedded development world: "if you are using floating point, you probably have not yet understood the problem you are trying to solve".

Do not use floating point to ever store BTC quantities. Use a single 64-bit integer. Or two 32-bit integers to represent the decimal and fractional parts.

Don't store non-fractional values in floating point either. It's not even more developer-friendly than using integers. And it is a dangerous way to either accidentally forget to use double-precision everywhere, or to entice developers receiving such a value from an API to divide by 100000000 to get the decimal point in the right place, leading to inaccurate results.
jgarzik
Legendary
*
qt
Offline Offline

Activity: 1470


View Profile
January 30, 2011, 12:09:57 AM
 #17

If I were to rewrite the JSON-RPC interface from scratch, I would probably use strings to represent the full int64 bitcoin value, without any decimals.

But perfect is the enemy of good.

Our current interface works just fine, and all this is making a mountain out of a molehill.  I do not see the value in changing what is currently in use.

Jeff Garzik, bitcoin core dev team and BitPay engineer; opinions are my own, not my employer.
Donations / tip jar: 1BrufViLKnSWtuWGkryPsKsxonV2NQ7Tcj
ribuck
Donator
Legendary
*
Offline Offline

Activity: 826


View Profile
January 30, 2011, 10:06:48 AM
 #18

ribuck makes a valid point why double-precision floating point does not work. To make my own example, if the exact value 3000000.00000001 (about 3M) is stored in a double-precision floating point number, it will be stored as approximately as 3000000.0000000098. Therefore doing any math on this number risks amplifying the rounding error (eg. calculating compounded interest, etc).
Sure that's true, but it's trivially worked around by storing it within the double-precision as 300000000000001 and inserting the decimal when displaying the number.

Cute quote, but the embedded world has true integers to work with; JSON-RPC does not.
Luke-Jr
Legendary
*
expert
Offline Offline

Activity: 2100



View Profile
January 30, 2011, 06:42:26 PM
 #19

Our current interface works just fine, and all this is making a mountain out of a molehill.  I do not see the value in changing what is currently in use.
It doesn't work just fine. It is impossible to send values with sub-cent precision, and therefore also impossible to send almost any TBC coins. And just because you personally don't care about TBC is not an excuse to make life more difficult for those who do. It's no different than Windows developers trying to prevent a Linux (or Mac) port of their open source software simply by stating "it works fine for us on Windows" as an excuse to not merge patches that make it work on both platforms. The BitCoin community is growing, and not everyone is going to have the same ideals or even basic reasons for being part of the community; don't force your narrow subset of interests on everyone else whose interests might or might not overlap with yours.

jgarzik
Legendary
*
qt
Offline Offline

Activity: 1470


View Profile
January 30, 2011, 06:43:34 PM
 #20

Problem is, "TBC" is your own invention, no matter how many times you repeat it.

Jeff Garzik, bitcoin core dev team and BitPay engineer; opinions are my own, not my employer.
Donations / tip jar: 1BrufViLKnSWtuWGkryPsKsxonV2NQ7Tcj
Pages: [1] 2 »  All
  Print  
 
Jump to:  

Sponsored by , a Bitcoin-accepting VPN.
Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!