This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author steven.daprano
Recipients agthorr, belopolsky, christian.heimes, ethan.furman, gregory.p.smith, mark.dickinson, oscarbenjamin, pitrou, ronaldoussoren, sjt, steven.daprano, stutzbach, terry.reedy, tshepang, vajrasky
Date 2013-08-19.16:35:53
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <52124961.20503@pearwood.info>
In-reply-to <CAHVvXxSoDxb2MWeQfzRdBhFHGj-f3CAfPs0BHdGSVLwbrsZH9A@mail.gmail.com>
Content
On 19/08/13 23:15, Oscar Benjamin wrote:

> So with the current implementation I can do:
>
>>>> from decimal import Decimal as D, localcontext, Context, ROUND_DOWN
>>>> data = [D("0.1375"), D("0.2108"), D("0.3061"), D("0.0419")]
>>>> print(statistics.variance(data))
> 0.01252909583333333333333333333
>>>> with localcontext() as ctx:
> ...     ctx.prec = 2
> ...     ctx.rounding = ROUND_DOWN
> ...     print(statistics.variance(data))
> ...
> 0.010
>
> The final result is not accurate to 2 d.p. rounded down. This is
> because the decimal context has affected all intermediate computations
> not just the final result.

Yes. But that's the whole point of setting the context to always round down. If summation didn't always round down, it would be a bug.

If you set the precision to a higher value, you can avoid the need for compensated summation. I'm not prepared to pick and choose which contexts I'll honour. If I honour those with a high precision, I'll honour those with a low precision too. I'm not going to check the context, and if it is "too low" (according to whom?) set it higher.

>Why would anyone prefer this behaviour over
> an implementation that could compensate for rounding errors and return
> a more accurate result?

Because that's what the Decimal standard requires (as I understand it), and besides you might be trying to match calculations on some machine with a lower precision, or different rounding modes. Say, a pocket calculator, or a Cray, or something. Or demonstrating why rounding matters.

Perhaps it will cause less confusion if I add an example to show a use for higher precision as well.

> If statistics.sum and statistics.add_partial are modified in such a
> way that they use the same compensated algorithm for Decimals as they
> would for floats then you can have the following:
>
>>>> statistics.sum([D('-1e50'), D('1'), D('1e50')])
> Decimal('1')

statistics.sum can already do that:

py> with localcontext() as ctx:
...     ctx.prec = 50
...     x = statistics.sum([D('-1e50'), D('1'), D('1e50')])
...
py> x
Decimal('1')

I think the current behaviour is the right thing to do, but I appreciate the points you raise. I'd love to hear from someone who understands the Decimal module better than I do and can confirm that the current behaviour is in the spirit of the Decimal module.
History
Date User Action Args
2013-08-19 16:35:54steven.dapranosetrecipients: + steven.daprano, terry.reedy, gregory.p.smith, ronaldoussoren, mark.dickinson, belopolsky, pitrou, agthorr, christian.heimes, stutzbach, sjt, ethan.furman, tshepang, oscarbenjamin, vajrasky
2013-08-19 16:35:54steven.dapranolinkissue18606 messages
2013-08-19 16:35:53steven.dapranocreate