On Mon, 24 May 2010 03:06:28 am Wayne Werner wrote: > On Sat, May 22, 2010 at 9:58 AM, Steven D'Aprano <st...@pearwood.info>wrote: > > On Sun, 23 May 2010 12:19:07 am Wayne Werner wrote: > > > On Sat, May 22, 2010 at 7:32 AM, Steven D'Aprano > > > > <st...@pearwood.info>wrote: > > > > Why do people keep recommending Decimal? Decimals suffer from > > > > the exact same issues as floats, > > > > > > This is exactly incorrect! The Decimal operator offers /exact/ > > > decimal point operations. > > > > Decimal is only exact for fractions which can be represented by a > > finite sum of powers-of-ten, like 0.1, just like floats can only > > represent fractions exactly if they can be represented by a finite > > sum of powers-of-two, like 0.5. > > > > Not only did I demonstrate an example of rounding error using > > Decimal in my post, but you then repeated that rounding error and > > then had the audacity to claim that it was "exact": > > Decimal doesn't round - exact precision, not exact accuracy.
Of course decimal rounds! Did you even bother to read the page on Decimal that you told me to read? It has a section called: "Mitigating round-off error with increased precision" http://docs.python.org/library/decimal.html#mitigating-round-off-error-with-increased-precision Why would it have round-off error if it doesn't round? Not only do Decimal calculations round, but it gives the user a choice of rounding modes (e.g. round down, round up, banker's rounding), and whether to trap rounding and treat it as an error. I demonstrated an example of this rounding, a calculation of Decimal(1)/Decimal(3) which did NOT produce the correct result exactly, but ROUNDED the result to 28 decimal places. Still don't believe me? Then explain this: >>> x = Decimal('0.9999999999999999999999999999') >>> x + Decimal(7)/Decimal(10**29) Decimal('1.000000000000000000000000000') The answer without rounding is: 0.99999999999999999999999999997 not one. And then there is this: >>> decimal.getcontext().rounding = decimal.ROUND_DOWN >>> x + Decimal(7)/Decimal(10**29) == x True IEEE-compliant floats also have a choice of rounding modes, but few high-level programming languages expose that functionality. > Floating > point has neither reliable precision or accuracy, at least to certain > extents. On IEEE-compliant systems (which include nearly any computer you're likely to work on) floating point has reliable precision. C singles are reliably 32 bits with 24 binary digits of precision C doubles (which Python uses) are reliably 64 bits with 53 binary digits of precision. As for accuracy, any lack of accuracy (correctness) is a bug in the implementation, not a fundamental flaw in float. E.g. the infamous Pentium FDIV bug. > Decimal, OTOH will perform exactly the same under the exact > same circumstances every time. And so will floats. Decimals and floats are both constructed exactly the same way: number = significant digits * base ** exponent The only difference is that Decimal uses digits 0...9 for the digits and ten for the base, while floats use 0,1 for the digits and two for the base. This makes Decimal very useful because we humans like to work with base-ten numbers like 0.1 and get upset that they can't be expressed exactly in base-two. But Decimal is subject to the exact same issues as float, because at a fundamental level they are constructed the same way with the same limitations. The difference in base merely affects *which* numbers can't be expressed exactly without rounding, not the existence of such numbers. Because we tend to *think* in base 10, we naturally get annoyed that while binary floats can express 0.099999999999999992 exactly, and 0.10000000000000001 exactly, they miss out on 0.1 (as well as an infinite number of other rationals). But decimal floats suffer from the same issue. Between Decimal('0.0999...9') and Decimal('0.1') there are an infinite number of rationals that can't be expressed exactly, and if a calculation *should* produce one of those rationals, it will be rounded to an appropriate > No matter how many points of precision > you go out to, .3333 * 3 can -never- be equal to 1 (except for very > large values of 3). Really? Would you care to put money on that? >>> decimal.getcontext().prec = 3 >>> Decimal('0.3333') Decimal('0.3333') >>> Decimal('0.3333') * 3 Decimal('1.00') > 1/3 is a different number than .33333 repeating. Nonsense. 0.333 repeating is *exactly* one third. Ask a mathematician. Here is a short proof: x = 0.33333... # goes on forever 10x = 3.33333... # still goes on forever subtract the first from the second: 9x = 3.00000... = 3 exactly so x = 3/9 = 1/3 exactly. > It's close, getting closer the further out you go, and once it > reaches infinity then sure, it's equivalent. You can't "reach" infinity. That's why it is *repeating* -- it never stops. This demonstrates that you can't write 1/3 in decimal exactly, you *must* round the number to a finite number of places. You can't write 1/3 exactly in binary either, but you can in base-three: "0.1". > But unfortunately > computers are finite state machines and therefore are not capable of > expressing the rational number 1/3 in its decimal equivalent. Right. Which means any calculation that *should* produce 1/3, like Decimal(1)/Decimal(3), *must* be rounded. > This has nothing to do with the Decimal module which will always > perform reliably - you can count on Decimals to behave, precisely, > but floats not so much You are confused. float(1)/float(3) will always produce the same result, rounded the same way, just as Decimal(1)/Decimal(3) will. [...] > If you want accurate representation of rational numbers, then of > course like you suggested the Fraction module is available. Which is what I said, and you told me to stop spreading myths about Decimal. -- Steven D'Aprano _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: http://mail.python.org/mailman/listinfo/tutor