{"items": [{"author": "Michael", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851553767302", "anchor": "fb-851553767302", "service": "fb", "text": "Well, the \"floor\" function *should* let you pre-set a value of eps (e.g. .000001) which is always added to anything you're about to take the \"floor\" of.  But apparently it doesn't, so you should always do it yourself throughout your code.  This sort of \"error\" can happen when taking the \"floor\" of any floating point value, apparently including python's unusual \"decimal\" type of values.  So is this a bug you found -- or is it just how floating point arithmetic works, and you have to deal with it.", "timestamp": "1488470160"}, {"author": "Jeff&nbsp;Kaufman", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851553767302&reply_comment_id=851558208402", "anchor": "fb-851553767302_851558208402", "service": "fb", "text": "&rarr;&nbsp;Sorry, I wasn't trying to say this was a bug in how floating point worked, instead that it was a bug in my code caused by floating point being complicated.", "timestamp": "1488471812"}, {"author": "Michael", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851554705422", "anchor": "fb-851554705422", "service": "fb", "text": "\"and 53 bits of precision is 50 decimal digits of precision\"<br><br>Isn't 53 bits of precision only 16 digits of precision? 2^53 ~= 10^16", "timestamp": "1488470919"}, {"author": "Jeff&nbsp;Kaufman", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851554705422&reply_comment_id=851557360102", "anchor": "fb-851554705422_851557360102", "service": "fb", "text": "&rarr;&nbsp;You're right.  I was thinking of log(10)/log(2) but that's not the right way to figure this.  I'm not sure why Decimal is using so much precision here.", "timestamp": "1488471741"}, {"author": "Alex", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851554705422&reply_comment_id=851565518752", "anchor": "fb-851554705422_851565518752", "service": "fb", "text": "&rarr;&nbsp;At a guess, when you construct a Decimal (e.g., using Decimal(100/101)) it is using the least number of digits necessary to represent the binary fraction exactly as a decimal. I.e., it is converting a/2^b to (5^b*a)/(10^b). Here b&lt;=53 since this is the input precision of a float.<br><br>When you actually do an operation on the numbers, it then appears to truncate to its current precision (default 28). This leads to the slightly weird:<br>a=Decimal(1/3)<br>b=1*a<br>a==b -&gt; False<br>a+0==a -&gt; False<br><br>and accounts for your Decimal(100)/Decimal(101)  being 28 digits.", "timestamp": "1488472966"}, {"author": "Alex", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851554705422&reply_comment_id=851565962862", "anchor": "fb-851554705422_851565962862", "service": "fb", "text": "&rarr;&nbsp;Personally I'd be wary of a system with these properties (hidden temporary extra precision, multiplication by 1 changing a number).", "timestamp": "1488473028"}, {"author": "Daniel", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851554705422&reply_comment_id=851569570632", "anchor": "fb-851554705422_851569570632", "service": "fb", "text": "&rarr;&nbsp;When you multiply by or add a number to a decimal, does it stay a decimal?", "timestamp": "1488475439"}, {"author": "Jeff&nbsp;Kaufman", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851554705422&reply_comment_id=851577185372", "anchor": "fb-851554705422_851577185372", "service": "fb", "text": "&rarr;&nbsp;@Daniel: yes", "timestamp": "1488478786"}, {"author": "Daniel", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851554705422&reply_comment_id=851578382972", "anchor": "fb-851554705422_851578382972", "service": "fb", "text": "&rarr;&nbsp;Huh. I thought that the arithmetic operators preferred floats. <br><br>But the last time I had to look up behavior of numbers outside normal parameters was when I had to multiply and divide by a factorial that could be up to 1000! . The end solution was to add and subtract the logarithms of the terms rather than multiply and divide by them.", "timestamp": "1488479406"}, {"author": "Michael", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851554705422&reply_comment_id=851649031392", "anchor": "fb-851554705422_851649031392", "service": "fb", "text": "&rarr;&nbsp;Daniel floats are preferred over integers; but Decimal is not a built-in type, it's a standard library type, so its behavior is different.", "timestamp": "1488510686"}, {"author": "Michael", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851567604572", "anchor": "fb-851567604572", "service": "fb", "text": "If you want to write bulletproof code, start by being aware of the slight inaccuracies present in the hardware specification for the CPU you are running on, primarily this is number of bits kept for floating point representation.  Then allow for additional inaccuracies caused by compiler optimization that may in some cases re-order operations.  Then allow for variations with other CPUs (including those whose specifications have not yet been released), and other compilers (some of which you don't know about yet).  And don't use compilers in ways that most people don't, or you may be the one who encounters the compiler bugs that no one else has found yet.  Just write out your calculations in a manner that uses only straightforward CPU calculations, straightforwardly understood by the compiler.  You can do this with floating point, understanding the general limitations thereof.  Or you can use integer arithmetic, dealing with a fixed number of decimal places which you keep track of -- this is rarely worth the trouble, but keep in mind that it is an option.", "timestamp": "1488473953"}, {"author": "Andrew", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851576446852", "anchor": "fb-851576446852", "service": "fb", "text": "Data should be converted from exact representations to inexact representations and never vice versa. If you want an exact fraction, do the division in exact-land, not float-land.", "timestamp": "1488478237"}, {"author": "Jeff&nbsp;Kaufman", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851576446852&reply_comment_id=851577130482", "anchor": "fb-851576446852_851577130482", "service": "fb", "text": "&rarr;&nbsp;In this case I moved from doing a calculation in float land to exact land (which I knew I was doing) but that caused the bug!  The problem was that a*(b/c) in float land got the correct answer but doing d=b/c in float land and then a*d in exact land got the wrong answer.  (And the fix was to move it all into exact land.)", "timestamp": "1488478745"}, {"author": "Andrew", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851576446852&reply_comment_id=851578073592", "anchor": "fb-851576446852_851578073592", "service": "fb", "text": "&rarr;&nbsp;No - in your code, the (inexact, float) division 100/101 happens before the call to the Decimal constructor. Compare:<br><br>&gt;&gt;&gt; Decimal(100/101)<br>Decimal('0.99009900990099009021605525049380958080291748046875')<br>&gt;&gt;&gt; Decimal(100)/Decimal(101)<br>Decimal('0.9900990099009900990099009901')", "timestamp": "1488479275"}, {"author": "Jeff&nbsp;Kaufman", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851576446852&reply_comment_id=851578797142", "anchor": "fb-851576446852_851578797142", "service": "fb", "text": "&rarr;&nbsp;Right.  So the existing code did something like:<br><br>```<br>d=b/c [float division]<br>...<br>return a*d [float multiplication]<br>```<br><br>The first round of refactor changed this to:<br><br>```<br>d=b/c [float division]<br>...<br>return a*d [Decimal multiplication]<br>```<br><br>Even though this only moves a change from float land to Decimal land, it still broke things.<br><br>The fix was to move the rest of the calculation into Decimal land:<br><br>```<br>d = b/c [Decimal division]<br>...<br>return a*d [Decimal multiplication]<br>```", "timestamp": "1488479716"}, {"author": "Andrew", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851576446852&reply_comment_id=851578936862", "anchor": "fb-851576446852_851578936862", "service": "fb", "text": "&rarr;&nbsp;The point is you are taking the output of an inexact calculation (float division) and using it as the input for the constructor of an exact representation. That is the wrong direction for data to go.", "timestamp": "1488479902"}, {"author": "Jeff&nbsp;Kaufman", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851576446852&reply_comment_id=851579061612", "anchor": "fb-851576446852_851579061612", "service": "fb", "text": "&rarr;&nbsp;I agree that this is wrong, but this is what the system was already doing.  What was surprising to me is that my attempt to clean up part of the module made things worse, and I instead needed to make a larger change that cleaned up the whole module together.", "timestamp": "1488479983"}, {"author": "Andrew", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851576446852&reply_comment_id=851579171392", "anchor": "fb-851576446852_851579171392", "service": "fb", "text": "&rarr;&nbsp;Your attempt to clean it up involved taking the result of an inexact computation and using it in a supposedly-exact computation. It is entirely unsurprising that it caused problems.", "timestamp": "1488480036"}, {"author": "Jeff&nbsp;Kaufman", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851576446852&reply_comment_id=851579211312", "anchor": "fb-851576446852_851579211312", "service": "fb", "text": "&rarr;&nbsp;What is surprising is that it introduced a problem.", "timestamp": "1488480069"}, {"author": "Andrew", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851576446852&reply_comment_id=851579266202", "anchor": "fb-851576446852_851579266202", "service": "fb", "text": "&rarr;&nbsp;It should not have been surprising if you considered which direction the data was going, and the mistake can be avoided in future by considering such. That's my point.", "timestamp": "1488480115"}, {"author": "Michael", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851576446852&reply_comment_id=851579366002", "anchor": "fb-851576446852_851579366002", "service": "fb", "text": "&rarr;&nbsp;No, Jeff, you have not necessarily cleaned up the whole module.  Now it could be a different example which would go wrong, but some example could still go wrong.  The point is that you have taken the \"floor\" of a number which was computed in float land or in decimal land, which are both approximations.  And where the exact result would be an exact integer, either float land or decimal land could introduce a very slight error which would cause the \"floor\" function to go down to the next lower integer.", "timestamp": "1488480176"}, {"author": "Alex", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851576446852&reply_comment_id=851584914882", "anchor": "fb-851576446852_851584914882", "service": "fb", "text": "&rarr;&nbsp;Jeff: you were never in exact-land because neither decimals nor bicimals can represent 100/101 exactly (because 101 doesn't divide into a power of 2 or 10). It was just a fluke that it worked with 101 (i.e., floor(100*(101/100))==101). As people have said, it's entirely unsurprising that you don't get back to where you started when you multiply back by the denominator. As an example of non-exactness, floor(47*(48/47))==47 (Python 3, my computer, probably yours too).<br><br>If you want to represent rationals exactly then you might try the fractions module (depending on your requirements).", "timestamp": "1488483405"}, {"author": "Jeff&nbsp;Kaufman", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851576446852&reply_comment_id=851587689322", "anchor": "fb-851576446852_851587689322", "service": "fb", "text": "&rarr;&nbsp;@Alex: Yes, that's a good example:<br><br>```<br>&gt;&gt;&gt; from decimal import Decimal as D<br>&gt;&gt;&gt; D(47)*(D(48)/D(47))<br>Decimal('47.99999999999999999999999999')<br>&gt;&gt;&gt; floor(D(47)*(D(48)/D(47)))<br>47<br>```", "timestamp": "1488484685"}, {"author": "Michael", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851576446852&reply_comment_id=851594166342", "anchor": "fb-851576446852_851594166342", "service": "fb", "text": "&rarr;&nbsp;Jeff, I do not know the details of your application, but I cannot imagine that you need an exact representation for any intermediate results.  In almost every possible application, you will do fine with an inexact representation, like floating point, as long as you understand the context you are working in, and design your calculations appropriately.", "timestamp": "1488488081"}, {"author": "Lauren", "source_link": "https://www.facebook.com/jefftk/posts/851537469962?comment_id=851771575812", "anchor": "fb-851771575812", "service": "fb", "text": "if you use decimal, use it before *any* operations. pretty sure it's ieee float compliant as long as you don't switch between it and your cpu floats.", "timestamp": "1488560355"}]}