Bitcoin Forum

Bitcoin => Development & Technical Discussion => Topic started by: bitcoinhelper on June 09, 2011, 03:15:45 AM



Title: Stop using floating point!
Post by: bitcoinhelper on June 09, 2011, 03:15:45 AM
Can we stop with this nonsense?

+    if (params[0].get_real() != 0.0)
+        nAmount = AmountFromValue(params[0]);        // rejects 0.0 amounts


          if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
+        if (strMethod == "settxfee"               && n > 0) ConvertTo<double>(params[0]);


Please learn to use fixed-point arithmetic, people... this is not a pet project anymore, it's a financial application that at the moment holds $181 million USD worth of people's savings.

I think you might need a lesson on how floating point works.
In short, results of rounding, calculations and comparisons may vary depending on compiler, optimizations, or architecture used.
Furthermore, there are other non-obvious semantics, such as negative zeros, infinities, NaNs, etc.

I know in this case the comparison with 0.0 is probably not problematic, but for instance, you don't want someone to send a transaction of 0.12345678 bitcoins and then due to rounding conversions you actually send 0.12345679 bitcoins instead. Or someone to set a transaction fee of 0.2 and instead it gets set to 0.19999999.

It is NOT acceptable for financial applications to use floating point numbers to represent monetary values.
Governments have strict regulations against this for banks, for obvious reasons.

Please, please avoid using floating point arithmetic and educate yourselves why you should do that.

For example, there's a reason why Satoshi avoided floating point calculations in many places (e.g. difficulty calculations... you really don't want different machines having a different concept of what the difficulty is).

What you really want is to convert strings directly to fixed-point numbers (probably with BigDecimals if uint64 is not enough for 21,000,000*10^8 individual units) and vice-versa.
Always do calculations, comparisons and range checks with fixed-point arithmetic.

http://objectopia.com/2009/07/03/stop-using-floating-poin/ (http://objectopia.com/2009/07/03/stop-using-floating-poin/)
http://programmers.stackexchange.com/questions/62948/what-can-be-done-to-programming-languages-to-avoid-floating-point-pitfalls (http://programmers.stackexchange.com/questions/62948/what-can-be-done-to-programming-languages-to-avoid-floating-point-pitfalls)
http://www.theregister.co.uk/2006/08/12/floating_point_approximation/ (http://www.theregister.co.uk/2006/08/12/floating_point_approximation/)
http://hal.archives-ouvertes.fr/docs/00/28/14/29/PDF/floating-point-article.pdf (http://hal.archives-ouvertes.fr/docs/00/28/14/29/PDF/floating-point-article.pdf)

... and so on and on...

Same advice goes for the code of any website that deals with bitcoins (MtGox and mining pools come to mind...).


Title: Re: Stop using floating point!
Post by: WilliamJohnson on June 09, 2011, 05:54:21 AM
Good point.
Where did you find this piece of code? In the client?


Title: Re: Stop using floating point!
Post by: bitcoinhelper on June 09, 2011, 06:03:44 AM
Good point.
Where did you find this piece of code? In the client?

Yes, v0.3.22.


Title: Re: Stop using floating point!
Post by: Enochian on June 09, 2011, 06:09:43 AM
Please learn to use fixed-point arithmetic, people... this is not a pet project anymore, it's a financial application that at the moment holds $181 million USD worth of people's savings.

I think you might need a lesson on how floating point works.
In short, results of rounding, calculations and comparisons may vary depending on compiler, optimizations, or architecture used.
Furthermore, there are other non-obvious semantics, such as negative zeros, infinities, NaNs, etc.

Double precision IEEE numbers have more than enough precision to represent any possible bitcoin amount.

As long as you represent things as integer nanocoins, and do only addition and subtraction, none of the things mentioned are going to have any effect.

BASIC used double precision floats for everything for decades, and it worked just fine for integer calculations, within a reasonable range.

If you multiply and divide, and want things like banker's rounding, then floating point can be a bit problematical, but for tallying transactions, it works fine.

 


Title: Re: Stop using floating point!
Post by: bitcoinhelper on June 09, 2011, 06:38:27 AM
Quote
Double precision IEEE numbers have more than enough precision to represent any possible bitcoin amount.

As long as you represent things as integer nanocoins, and do only addition and subtraction, none of the things mentioned are going to have any effect.

If you're representing "things" as integer nanocoins, then why don't you use an integer type?!

An uint64 would work just fine!!

UINT64_MAX = 18446744073709551615
BITCOIN_MAX = 21000000 * 10^ 8 = 2100000000000000

BITCOIN_MAX < INT64_MAX

So you want to do that just because you like to get yourself into trouble?

Do you know what optimizations the compiler is allowed to do in intermediate values of floating point calculations?

Do you know that certain compilation flags affect the precision of the results (downwards or upwards)?

Do you know that when you enable some optimizations in some compilers, they don't follow the standards?
Such as when you use -fast with the Sun Studio compiler or -ffast-math in gcc?

Do you know that many Linux Gentoo users use -ffast-math by default?

Also, I didn't see any place in the code where "integer nanocoins" are represented as floating point values (granted, I only read a fraction of the code). What I saw was integer nanocoins being used as integers, and floating point bitcoins being used in floating point variables...

Please, just use integer (i.e. fixed point) arithmetic for financial data and stop writing shoddy code. It's a no brainer, really...


Title: Re: Stop using floating point!
Post by: bitcoinhelper on June 09, 2011, 06:51:19 AM
Double precision IEEE numbers have more than enough precision to represent any possible bitcoin amount.

Not to mention that the C++ standard allows the 'double' type to have only 4 bytes.... sigh  :-\


Title: Re: Stop using floating point!
Post by: Enochian on June 09, 2011, 08:38:07 AM
Please, just use integer (i.e. fixed point) arithmetic for financial data and stop writing shoddy code. It's a no brainer, really...

Floating point arithmetic which can represent the integer values exactly isn't going to give a different answer than fixed point arithmetic.  Look at all the actuarial  programs written in APL, whose numeric prototype is a double precision float or complex.

The alleged horrors of float for financial math are mostly FUD.  Lots of COBOL programs use a comp-3 floating type because it is faster than character or packed decimal arithmetic. 

As with all things, it helps if you know what you're doing, and one can always construct examples of failure that are poor programming practice or don't occur in real life.

On the list of things that need fixing in Bitcoin, floating compares to double 0.0 aren't anywhere near the top of the list.





Title: Re: Stop using floating point!
Post by: mintymark on June 09, 2011, 08:49:57 AM
I would like to chip in here and say I agree with bitcoinhelper.

Integers should be used for internal representation.

Integers have the property that they give the same result on every computer or an overflow occurs.
Floating point has the property that if the amount goes outside what can be represented on that particular computer approximation occurs.
Sometimes this is useful.

In this situation an error is way better than an approximation.

That is the point!


Title: Re: Stop using floating point!
Post by: realnowhereman on June 09, 2011, 09:39:20 AM
Please, just use integer (i.e. fixed point) arithmetic for financial data and stop writing shoddy code. It's a no brainer, really...

Floating point arithmetic which can represent the integer values exactly isn't going to give a different answer than fixed point arithmetic.  Look at all the actuarial  programs written in APL, whose numeric prototype is a double precision float or complex.

So you're saying as long as we stick to representing integers with floats, there will be no problem with inaccuracy?  (You're quite right in this assertion).

If it's true though, why bother using floats at all?  They are only exact when not using fractional parts, so why not remove the danger and used fixed point integers and save ourselves the wasted bits of the exponent in the float representation?


Title: Re: Stop using floating point!
Post by: Silverpike on June 09, 2011, 09:53:58 AM
Please, just use integer (i.e. fixed point) arithmetic for financial data and stop writing shoddy code. It's a no brainer, really...

Floating point arithmetic which can represent the integer values exactly isn't going to give a different answer than fixed point arithmetic.  Look at all the actuarial  programs written in APL, whose numeric prototype is a double precision float or complex.

The alleged horrors of float for financial math are mostly FUD.  Lots of COBOL programs use a comp-3 floating type because it is faster than character or packed decimal arithmetic. 
Statements like this make me wonder if you have ever written portable floating point code. 

You might be ok if the system you run on implements IEEE-754 rules.  However, this day & age the Bitcoin client is being run on more & more small devices, some of which might not even have an FPU.  Not only that, but those which do are very likely not to follow 754 rules in particular, making their output theoretically differ from the result on a 754-based machine.  Those bugs are so much fun to find.  :P

The bottom line is that quality programming starts with good discipline, and financial software should always use fixed point representations.  Some companies will literally fire you if they see floating point in your code, and it's not because they are stupid.


Title: Re: Stop using floating point!
Post by: Pieter Wuille on June 09, 2011, 10:05:04 AM
Internally, everything is represented using 64-bit integers. It's only some of the interfacing code that uses floating point for convenience. I agree this should change to as much exact code as possible, but as currently all supported platforms of the main client support 64-bit IEEE 754 floats, all roundings should be exact.


Title: Re: Stop using floating point!
Post by: sentry on June 09, 2011, 03:06:06 PM
Thank you for this thread, I have learned a lot because of it and will fix my projects accordingly.


Title: Re: Stop using floating point!
Post by: Enochian on June 09, 2011, 05:51:50 PM
If it's true though, why bother using floats at all? 

I have no problem with requiring new code to be fixed point.  I am simply pointing out that removing existing floating point code isn't an emergency, that floating point arithmetic is exact when integers having less bits than the mantissa are involved, that panic over imagined precision or rounding issues when using floats for financial software is overblown, and that several Very High Level Languages popular for financial and actuarial work use floats internally, as does COBOL when performance is maximized.

People seem to have the idea that all float operations involve some sort of random fuzziness which causes monetary calculations to drift from their actual values the more floating operations are performed.  In reality, floats represent exact values on the real number line, and the result of a floating operation is the nearest machine number to the value that would have resulted had the operation been performed to infinite precision if one exists, and a value systematically chosen with zero bias if the exact value lies halfway between two machine numbers.

So floating operations which yield machine numbers are as exact as integer operations.  Since double floats are big enough to represent all Bitcoin amounts, discussion of whether or not to ban floating arithmetic in the source code of the default client is a philosophical one, and not one related to an actual danger the code will "break, or that Bitcoin amounts will become imprecise, if this is not done.

Comments like "such and such a company burns coders at the stake if they use floating point in financial apps," while interesting, make points orthogonal to the points I am making.



Title: Re: Stop using floating point!
Post by: bitcoinhelper on June 09, 2011, 07:25:57 PM
I have no problem with requiring new code to be fixed point.

Great!

  I am simply pointing out that removing existing floating point code isn't an emergency, that floating point arithmetic is exact when integers having less bits than the mantissa are involved, that panic over imagined precision or rounding issues when using floats for financial software is overblown, and that several Very High Level Languages popular for financial and actuarial work use floats internally, as does COBOL when performance is maximized.

It's exact for additions and subtractions (of values that were never divided).

If you divide one value by another, and now you add the result multiple times, you will likely obtain different results than if you had used fixed-point arithmetic (unless it was an exact division).

This can lead to results that are unexpected. It may also lead to different results depending on how the compiler optimized your code (e.g. whether it used SSE2 or the FPU), the architecture you're using, etc.

People seem to have the idea that all float operations involve some sort of random fuzziness which causes monetary calculations to drift from their actual values the more floating operations are performed.  In reality, floats represent exact values on the real number line, and the result of a floating operation is the nearest machine number to the value that would have resulted had the operation been performed to infinite precision if one exists, and a value systematically chosen with zero bias if the exact value lies halfway between two machine numbers.

It's not as obvious and simple as you seem to imply, as I just proved to you.

The code is also non-portable because the 'double' type in C++ is not required to have 64 bits, in fact it can have only 32 bits which is obviously not enough to represent all bitcoin values (not even close).
The size of double does not only depend on the architecture and compiler that you are using, but also on the compilation flags.
The double type is only required to not be smaller than float.


Title: Re: Stop using floating point!
Post by: gigitrix on June 09, 2011, 07:40:43 PM
My view is that a steady migration to fixed integers is needed. We don't need to rush, but it needs to happen. What's going on right now is perfectly correct, but it's not ideal from a semantic view and feels like a kludge.


Title: Re: Stop using floating point!
Post by: bitcoinhelper on June 09, 2011, 07:45:35 PM
In reality, floats represent exact values on the real number line, and the result of a floating operation is the nearest machine number to the value that would have resulted had the operation been performed to infinite precision if one exists, and a value systematically chosen with zero bias if the exact value lies halfway between two machine numbers.

And BTW, in most financial calculations you don't want to perform operations to infinite precision.

What you want is to have predictable results that do not depend on the environment used to compile and/or run the application.


Title: Re: Stop using floating point!
Post by: speeder on June 09, 2011, 07:48:07 PM
After seeing that, I almost felt the urge of selling all my BTC..

Seriously O.o floating point?

I am a game programmer (among other stuff programmer), and I had MANY bugs that were "theoretically to not happen" with floating point.

A infamous one for example, was in a game that I made using LUA, that 5998 + 3 resulted into 6010 (yes, way wrong).

After a while, I found out, that LUA use floating point to all internal math, and the game engine I used, triggered the stupid floating point bug of directx (directx sometimes change the settings of CPU and GPU floating point, making them non-complient with the floating point standard).

So, DO NOT ASSUME YOU CAN WORK WITH INTEGER VALUES USING FLOAT! IT WILL SOMEHOW BREAK WHEN YOU DO NOT EXPECT!


Title: Re: Stop using floating point!
Post by: dayfall on June 09, 2011, 09:12:36 PM
No one would ever use double to represent nanocoins.  This whole issue is probably because people think of 0.00000001BTC rather than 1Satoshi.  Don't use floats with indivisible units.



Title: Re: Stop using floating point!
Post by: Gavin Andresen on June 10, 2011, 03:55:26 AM
See https://en.bitcoin.it/wiki/Proper_Money_Handling_(JSON-RPC) for relevant advice.

As Pieter says, bitcoin converts all user-entered values and JSON-RPC values to fixed-point 64-bit integers as soon as it gets them. All calculations except for that conversion are done using 64-bit integers.

Bitcoin does not "use floating point", it parses numbers-containing-a-decimal-point values that come from JSON (the Number type in JSON is double-precision float; let's not restart the "we should pass numbers as strings in JSON" debate, please, there are several long threads from a couple of months ago about that) or from the GUI.


Title: Re: Stop using floating point!
Post by: dunand on February 13, 2012, 02:23:02 AM
See https://en.bitcoin.it/wiki/Proper_Money_Handling_(JSON-RPC) for relevant advice.

The url from Gavin was missing the last )
https://en.bitcoin.it/wiki/Proper_Money_Handling_%28JSON-RPC%29 (https://en.bitcoin.it/wiki/Proper_Money_Handling_%28JSON-RPC%29)


Title: Re: Stop using floating point!
Post by: racerguy on February 13, 2012, 03:07:33 AM


The url from Gavin was missing the last )
https://en.bitcoin.it/wiki/Proper_Money_Handling_%28JSON-RPC%29 (https://en.bitcoin.it/wiki/Proper_Money_Handling_%28JSON-RPC%29)

Thanks I've been waiting over 7months to click that link.


Title: Re: Stop using floating point!
Post by: grue on February 13, 2012, 03:28:59 AM
From what i can tell, bitcoinhelper (lol @ "helper") is just randomly quoting pieces of code and ranting about how we shouldn't use floats for everything. but for some reason, he didn't realize that floats are only used in GUI related stuff.

something tells me that he is either a kid who gets really hyped up about small issues (looks like he made an account just to post this topic ::)), or a troll.

See https://en.bitcoin.it/wiki/Proper_Money_Handling_(JSON-RPC) for relevant advice.

The url from Gavin was missing the last )
https://en.bitcoin.it/wiki/Proper_Money_Handling_%28JSON-RPC%29 (https://en.bitcoin.it/wiki/Proper_Money_Handling_%28JSON-RPC%29)
and he's a necro  >:(


Title: Re: Stop using floating point!
Post by: genjix on February 13, 2012, 04:29:54 PM
I think bitcoin using floats/doubles is frankly stupid.

https://bitcointalk.org/index.php?topic=4086.0
http://bitcoinmedia.com/merchant-developer-tutorial/


Title: Re: Stop using floating point!
Post by: Steve on February 17, 2012, 04:50:48 AM
This debate is silly.  If you're really a purist, forget scaled decimal and use integers and fractions.  Smalltalk was invented in the 70's and by default, it preserves the original representation of numbers...  "1 / 2" yields a fraction with the integer 1 as the numerator and 2 as the denominator.  Multitply it by 3 and you get another fraction, "3 / 2".  Multiply that by 2 and you get the integer "3" (yes, it reduces fractions).  You don't get better precision than that.  A 64bit floating point number has plenty of precision to deal with anything bitcoin needs…try "21000000.00000002 / 2" …it works.  When working with floating point within its bounds of precision, you only need to know enough about math to know when it's appropriate to round.


Title: Re: Stop using floating point!
Post by: 2112 on February 17, 2012, 06:44:10 PM
This thread is very sad. Bitcoin is seriously affected with not-invented-here-itis. I personally started to think that the current milieu here is hopeless. The only hope is that the currently involved software designers fall of the face of the Earth's Internet and get replaced by a new blood.

On the other hand I also know that a lot of bright young people read this forum. So for the benefit of the young blood:

1) please learn the difference between binary floating point and decimal floating point. The good starting point is: http://speleotrove.com/decimal/

2) please compile this little C program using your recent C compiler:
Code:
#include <stdio.h>
int main()
{
        _Decimal32 x,y;

        x = 1.df;
        x /= 10.df;
        y = x;
        y *= 10.df;
        printf("%Hf %Hf\n",x,y);
        return 0;
}
For example: "gcc d.c -ldfp". If you get "library not found for -ldfp" error, then read the following and complain to your software vendor.

3) You became a collateral damage in the mortal combat between IBM and Intel. They are both pushing two incompatible implementations of decimal floating point: IBM's DPD (densely packed decimal) and Intel's BID (binary integer decimal). The libdfp code is out there on the Internet, you'll need to search for it in places that aren't easily accessible to lawyers of the two concerns that I named above.