5 ms·
Can you explain what's wrong with this? If I had 1 million in $info[ 'balance' ]? Would $bean->Coins overflow?
by negamax 13y ago
Can you explain what's wrong with this? If I had 1 million in $info[ 'balance' ]? Would $bean->Coins overflow?
- reikonomusha 13y agoUsing floats to represent currency is a big no-no. Floats have limited precision, and some numbers aren't representable by floats. Go try adding 0.1 to itself over and over again in your favorite implementation. It is better to represent as integers or fixed-precision numbers. That way, you are dealing with exact quantities.
- negamax 13y agoTo me it seems like floats are being converted to int and then code is working with it. I don't think this will create an issue unless the int is overflowing. Any failing testcase?
- SixSigma 13y ago> some numbers aren't representable by floats an infinite number of them in fact
- deleted 13y ago[deleted]
- SixSigma 13y agoTuring proved there's an uncountable set of numbers that cannot even be computed let alone represented
- skj 13y agoCould make all the same arguments against integers: - Limited precision, - Some numbers aren't representable, - Go try adding 1 to itself over and over again. That said, yes, floats are a bad idea for financial arithmetic.
- thaumasiotes 13y agoYou can make the same arguments against integers, but you'd need to be willfully blind to the context of the discussion. There are no monetary quantities that can't be represented as integers. Using a scheme that can't represent 1/3 to record numbers for which 1/3 is an illegal value doesn't present any practical or theoretical problems.
- skj 13y agoMy point was that the arguments presented were not the reasons that using floats to handle finance was a bad idea. Since, as I showed, they also applied to integers.
- ufo 13y agoSheesh, stop being so pedantic. Unlike computers, humans can infer extra meaning from the context around a sentence.
- andruby 13y agoAs an example in Ruby (2.1.1): x = 0.1 #=> 0.1 10.times { x+=0.1 } #=> 10 x #=> 1.0999999999999999
- klibertp 13y agoWorks in Racket (and should in other Schemes): -> (for/sum ([_ (in-range 10)]) (/ 1 10)) 1 Yeah, I know, I'm cheating - `(/ 1 10)` returns a rational? which is not flonum?. Using `0.1` makes it inexact like it should be: -> (for/sum ([_ (in-range 10)]) 0.1) 0.9999999999999999
- rodgerd 13y agoIt's even better to represent as binary coded decimal, Ulrich Drepper's opinions notwithstanding.
- orthecreedence 13y agoThat's why I like lisp: (/ 10 17) => 10/17 (+ (/ 10 17) (/ 4 9)) => 158/153 =]
- viraptor 13y agoThe main issue is operating on the value intended for display rather than the precise value you get. The floating point value may not be always what you expect. For example you cannot even represent 0.1 precisely. See http://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency http://stackoverflow.com/questions/3730019/why-not-use-doubl... In practice that means you can't be sure if `1/1000000` is higher or lower than the value you expect it to be. (to be pedantic, yes you can, because it's well defined, but it can spoil your calculations) When you deal with money, you want the result to be always precise.
- negamax 13y agoIf Bitcoin has x point precision and I multiply every amount by 1e^x. Won't that in essence gives me correct integer value to work with. Provided I haven't overflowed the integer max?
- viraptor 13y agoSure, you can prove that, then verify your language complies over the whole range, then add validation that your values never go over the range provided and no input outside of the range can be accepted and then figure out a way to guarantee none of that will change in the future. (even controlling inputs/outputs is not enough, since internally they sometimes split the values into 40%/60% for transfers) Or you just stick to ints (or whatever type has unlimited integer range in a given language). Simple solution here is safer than the clever one. Especially if you're sometimes confused about the types and write `round(mt_rand($amount 0.4, $amount 0.6))` even though mt_rand returns ints.
- bennyg 13y agoSo if one of us were to create something dealing with BTC we should just store the data as the smallest discrete amount (satoshis) and then run calculations on that to display info to the user?
- 13y ago
- speleding 13y agoYou never want to put currency in a float because floats cannot accurately represent most base 10 rational numbers. A full explanation can be found here: http://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency http://stackoverflow.com/questions/3730019/why-not-use-doubl...
- kijin 13y agoIf this is 32-bit PHP, any amount above 21 bitcoins will overflow the integer range (2^31) and will be converted to float. That's bad. If this is 64-bit PHP, any realistic bitcoin amount multiplied by 100000000 would still be within the integer range (2^63 - 1) and can be passed around without any loss of precision ... ... unless $info['balance'] has anything below the decimal point. As soon as you're dealing with fractional bitcoins, the amount will be converted to a float before it is multiplied by 100000000 and then back to an integer. So even in 64-bit PHP, the code can't avoid passing bitcoins around as a floating point number. Realistically it is extremely unlikely in 64-bit PHP that the loss of precision caused by this single line of code (and the subsequent casting back into float) will ever round up to a satoshi. The (int)round() just makes sure that you get an integer rather than a double-precision float, because PHP loves to turn your values into other types behind your back. Nonetheless, if the program keeps casting numbers between int and float all over the place, eventually it may begin to lose a satoshi here and there. At the scale of Mt Gox, the errors will definitely add up. That's why you should never touch a float with a ten foot pole if you're dealing with money. The correct way to handle monetary amounts in PHP is to use the bcmath extension, which enables arbitrary precision.
- twistedpair 13y agoI hate it when types get coerced behind my back.