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