Bitcoin Forum
October 30, 2024, 03:44:12 PM *
News: Latest Bitcoin Core release: 28.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1] 2 »  All
  Print  
Author Topic: Stop using floating point!  (Read 28391 times)
bitcoinhelper (OP)
Newbie
*
Offline Offline

Activity: 10
Merit: 1


View Profile
June 09, 2011, 03:15:45 AM
Last edit: June 09, 2011, 06:04:46 AM by bitcoinhelper
Merited by dbkeys (1)
 #1

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://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://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...).
WilliamJohnson
Newbie
*
Offline Offline

Activity: 47
Merit: 0


View Profile
June 09, 2011, 05:54:21 AM
 #2

Good point.
Where did you find this piece of code? In the client?
bitcoinhelper (OP)
Newbie
*
Offline Offline

Activity: 10
Merit: 1


View Profile
June 09, 2011, 06:03:44 AM
 #3

Good point.
Where did you find this piece of code? In the client?

Yes, v0.3.22.
Enochian
Full Member
***
Offline Offline

Activity: 327
Merit: 124



View Profile
June 09, 2011, 06:09:43 AM
 #4

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.

 
bitcoinhelper (OP)
Newbie
*
Offline Offline

Activity: 10
Merit: 1


View Profile
June 09, 2011, 06:38:27 AM
 #5

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...
bitcoinhelper (OP)
Newbie
*
Offline Offline

Activity: 10
Merit: 1


View Profile
June 09, 2011, 06:51:19 AM
 #6

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  Undecided
Enochian
Full Member
***
Offline Offline

Activity: 327
Merit: 124



View Profile
June 09, 2011, 08:38:07 AM
 #7

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.



mintymark
Sr. Member
****
Offline Offline

Activity: 286
Merit: 251


View Profile
June 09, 2011, 08:49:57 AM
 #8

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!

[[ All Tips gratefully received!!  ]]
15ta5d1N8mKkgC47SRWmnZABEFyP55RrqD
realnowhereman
Hero Member
*****
Offline Offline

Activity: 504
Merit: 502



View Profile
June 09, 2011, 09:39:20 AM
 #9

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?

1AAZ4xBHbiCr96nsZJ8jtPkSzsg1CqhwDa
Silverpike
Newbie
*
Offline Offline

Activity: 54
Merit: 0



View Profile
June 09, 2011, 09:53:58 AM
 #10

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.  Tongue

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.
Pieter Wuille
Legendary
*
qt
Offline Offline

Activity: 1072
Merit: 1181


View Profile WWW
June 09, 2011, 10:05:04 AM
 #11

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.

I do Bitcoin stuff.
sentry
Newbie
*
Offline Offline

Activity: 88
Merit: 0


View Profile
June 09, 2011, 03:06:06 PM
 #12

Thank you for this thread, I have learned a lot because of it and will fix my projects accordingly.
Enochian
Full Member
***
Offline Offline

Activity: 327
Merit: 124



View Profile
June 09, 2011, 05:51:50 PM
 #13

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.

bitcoinhelper (OP)
Newbie
*
Offline Offline

Activity: 10
Merit: 1


View Profile
June 09, 2011, 07:25:57 PM
 #14

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.
gigitrix
Hero Member
*****
Offline Offline

Activity: 630
Merit: 500



View Profile
June 09, 2011, 07:40:43 PM
 #15

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.
bitcoinhelper (OP)
Newbie
*
Offline Offline

Activity: 10
Merit: 1


View Profile
June 09, 2011, 07:45:35 PM
 #16

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.
speeder
Hero Member
*****
Offline Offline

Activity: 994
Merit: 501


PredX - AI-Powered Prediction Market


View Profile
June 09, 2011, 07:48:07 PM
 #17

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!

dayfall
Sr. Member
****
Offline Offline

Activity: 312
Merit: 250



View Profile
June 09, 2011, 09:12:36 PM
 #18

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.

Gavin Andresen
Legendary
*
qt
Offline Offline

Activity: 1652
Merit: 2301


Chief Scientist


View Profile WWW
June 10, 2011, 03:55:26 AM
 #19

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.

How often do you get the chance to work on a potentially world-changing project?
dunand
Hero Member
*****
Offline Offline

Activity: 637
Merit: 502



View Profile
February 13, 2012, 02:23:02 AM
 #20


The url from Gavin was missing the last )
https://en.bitcoin.it/wiki/Proper_Money_Handling_%28JSON-RPC%29
Pages: [1] 2 »  All
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!