<div dir="ltr">That patch sounds nice, I don't have to edit my Python distribution! We'll have to do with this.</div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Jun 1, 2015 at 7:03 PM,  <span dir="ltr"><<a href="mailto:python-ideas-request@python.org" target="_blank">python-ideas-request@python.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Send Python-ideas mailing list submissions to<br>
        <a href="mailto:python-ideas@python.org">python-ideas@python.org</a><br>
<br>
To subscribe or unsubscribe via the World Wide Web, visit<br>
        <a href="https://mail.python.org/mailman/listinfo/python-ideas" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
or, via email, send a message with subject or body 'help' to<br>
        <a href="mailto:python-ideas-request@python.org">python-ideas-request@python.org</a><br>
<br>
You can reach the person managing the list at<br>
        <a href="mailto:python-ideas-owner@python.org">python-ideas-owner@python.org</a><br>
<br>
When replying, please edit your Subject line so it is more specific<br>
than "Re: Contents of Python-ideas digest..."<br>
<br>
<br>
Today's Topics:<br>
<br>
   1. Re: Python Float Update (Nick Coghlan)<br>
   2. Re: Python Float Update (Andrew Barnert)<br>
   3. Re: Python Float Update (Andrew Barnert)<br>
   4. Re: Python Float Update (Steven D'Aprano)<br>
<br>
<br>
----------------------------------------------------------------------<br>
<br>
Message: 1<br>
Date: Tue, 2 Jun 2015 10:08:37 +1000<br>
From: Nick Coghlan <<a href="mailto:ncoghlan@gmail.com">ncoghlan@gmail.com</a>><br>
To: Andrew Barnert <<a href="mailto:abarnert@yahoo.com">abarnert@yahoo.com</a>><br>
Cc: python-ideas <<a href="mailto:python-ideas@python.org">python-ideas@python.org</a>><br>
Subject: Re: [Python-ideas] Python Float Update<br>
Message-ID:<br>
        <<a href="mailto:CADiSq7fjhS_XrKe3QfF58hXdhLSSbX6NvsFZZKjRq-%2BOLOQ-eQ@mail.gmail.com">CADiSq7fjhS_XrKe3QfF58hXdhLSSbX6NvsFZZKjRq-+OLOQ-eQ@mail.gmail.com</a>><br>
Content-Type: text/plain; charset=UTF-8<br>
<br>
On 2 Jun 2015 08:44, "Andrew Barnert via Python-ideas"<br>
<<a href="mailto:python-ideas@python.org">python-ideas@python.org</a>> wrote:<br>
>But the basic idea can be extracted out and Pythonified:<br>
><br>
> The literal 1.23 no longer gives you a float, but a FloatLiteral, which is either a subclass of float, or an unrelated class that has a __float__ method. Doing any calculation on it gives you a float. But as long as you leave it alone as a FloatLiteral, it has its literal characters available for any function that wants to distinguish FloatLiteral from float, like the Decimal constructor.<br>
><br>
> The problem that Python faces that Swift doesn't is that Python doesn't use static typing and implicit compile-time conversions. So in Python, you'd be passing around these larger values and doing the slow conversions at runtime. That may or may not be unacceptable; without actually building it and testing some realistic programs it's pretty hard to guess.<br>
<br>
Joonas's suggestion of storing the original text representation passed<br>
to the float constructor is at least a novel one - it's only the idea<br>
of actual decimal literals that was ruled out in the past.<br>
<br>
Aside from the practical implementation question, the main concern I<br>
have with it is that we'd be trading the status quo for a situation<br>
where "Decimal(1.3)" and "Decimal(13/10)" gave different answers.<br>
<br>
It seems to me that a potentially better option might be to adjust the<br>
implicit float->Decimal conversion in the Decimal constructor to use<br>
the same algorithm as we now use for float.__repr__ [1], where we look<br>
for the shortest decimal representation that gives the same answer<br>
when rendered as a float. At the moment you have to indirect through<br>
str() or repr() to get that behaviour:<br>
<br>
 >>> from decimal import Decimal as D<br>
 >>> 1.3<br>
 1.3<br>
 >>> D('1.3')<br>
 Decimal('1.3')<br>
 >>> D(1.3)<br>
 Decimal('1.3000000000000000444089209850062616169452667236328125')<br>
 >>> D(str(1.3))<br>
 Decimal('1.3')<br>
<br>
Cheers,<br>
Nick.<br>
<br>
[1] <a href="http://bugs.python.org/issue1580" target="_blank">http://bugs.python.org/issue1580</a><br>
<br>
<br>
------------------------------<br>
<br>
Message: 2<br>
Date: Mon, 1 Jun 2015 18:27:32 -0700<br>
From: Andrew Barnert <<a href="mailto:abarnert@yahoo.com">abarnert@yahoo.com</a>><br>
To: Nick Coghlan <<a href="mailto:ncoghlan@gmail.com">ncoghlan@gmail.com</a>><br>
Cc: python-ideas <<a href="mailto:python-ideas@python.org">python-ideas@python.org</a>><br>
Subject: Re: [Python-ideas] Python Float Update<br>
Message-ID: <<a href="mailto:EBB58361-19F4-4275-B6A6-E5AF2F77EF9C@yahoo.com">EBB58361-19F4-4275-B6A6-E5AF2F77EF9C@yahoo.com</a>><br>
Content-Type: text/plain;       charset=us-ascii<br>
<br>
On Jun 1, 2015, at 17:08, Nick Coghlan <<a href="mailto:ncoghlan@gmail.com">ncoghlan@gmail.com</a>> wrote:<br>
><br>
> On 2 Jun 2015 08:44, "Andrew Barnert via Python-ideas"<br>
> <<a href="mailto:python-ideas@python.org">python-ideas@python.org</a>> wrote:<br>
>> But the basic idea can be extracted out and Pythonified:<br>
>><br>
>> The literal 1.23 no longer gives you a float, but a FloatLiteral, which is either a subclass of float, or an unrelated class that has a __float__ method. Doing any calculation on it gives you a float. But as long as you leave it alone as a FloatLiteral, it has its literal characters available for any function that wants to distinguish FloatLiteral from float, like the Decimal constructor.<br>
>><br>
>> The problem that Python faces that Swift doesn't is that Python doesn't use static typing and implicit compile-time conversions. So in Python, you'd be passing around these larger values and doing the slow conversions at runtime. That may or may not be unacceptable; without actually building it and testing some realistic programs it's pretty hard to guess.<br>
><br>
> Joonas's suggestion of storing the original text representation passed<br>
> to the float constructor is at least a novel one - it's only the idea<br>
> of actual decimal literals that was ruled out in the past.<br>
<br>
I actually built about half an implementation of something like Swift's LiteralConvertible protocol back when I was teaching myself Swift. But I think I have a simpler version that I could implement much more easily.<br>
<br>
Basically, FloatLiteral is just a subclass of float whose __new__ stores its constructor argument. Then decimal.Decimal checks for that stored string and uses it instead of the float value if present. Then there's an import hook that replaces every Num with a call to FloatLiteral.<br>
<br>
This design doesn't actually fix everything; in effect, 1.3 actually compiles to FloatLiteral(str(float('1.3')) (because by the time you get to the AST it's too late to avoid that first conversion). Which does actually solve the problem with 1.3, but doesn't solve everything in general (e.g., just feed in a number that has more precision than a double can hold but less than your current decimal context can...).<br>
<br>
But it just lets you test whether the implementation makes sense and what the performance effects are, and it's only an hour of work, and doesn't require anyone to patch their interpreter to play with it. If it seems promising, then hacking the compiler so 2.3 compiles to FloatLiteral('2.3') may be worth doing for a test of the actual functionality.<br>
<br>
I'll be glad to hack it up when I get a chance tonight. But personally, I think decimal literals are a better way to go here. Decimal(1.20) magically doing what you want still has all the same downsides as 1.20d (or implicit decimal literals), plus it's more complex, adds performance costs, and doesn't provide nearly as much benefit. (Yes, Decimal(1.20) is a little nicer than Decimal('1.20'), but only a little--and nowhere near as nice as 1.20d).<br>
<br>
> Aside from the practical implementation question, the main concern I<br>
> have with it is that we'd be trading the status quo for a situation<br>
> where "Decimal(1.3)" and "Decimal(13/10)" gave different answers.<br>
<br>
Yes, to solve that you really need Decimal(13)/Decimal(10)... Which implies that maybe the simplification in Decimal(1.3) is more misleading than helpful. (Notice that this problem also doesn't arise for decimal literals--13/10d is int vs. Decimal division, which is correct out of the box. Or, if you want prefixes, d13/10 is Decimal vs. int division.)<br>
<br>
> It seems to me that a potentially better option might be to adjust the<br>
> implicit float->Decimal conversion in the Decimal constructor to use<br>
> the same algorithm as we now use for float.__repr__ [1], where we look<br>
> for the shortest decimal representation that gives the same answer<br>
> when rendered as a float. At the moment you have to indirect through<br>
> str() or repr() to get that behaviour:<br>
><br>
>>>> from decimal import Decimal as D<br>
>>>> 1.3<br>
> 1.3<br>
>>>> D('1.3')<br>
> Decimal('1.3')<br>
>>>> D(1.3)<br>
> Decimal('1.3000000000000000444089209850062616169452667236328125')<br>
>>>> D(str(1.3))<br>
> Decimal('1.3')<br>
><br>
> Cheers,<br>
> Nick.<br>
><br>
> [1] <a href="http://bugs.python.org/issue1580" target="_blank">http://bugs.python.org/issue1580</a><br>
<br>
<br>
------------------------------<br>
<br>
Message: 3<br>
Date: Mon, 1 Jun 2015 19:00:48 -0700<br>
From: Andrew Barnert <<a href="mailto:abarnert@yahoo.com">abarnert@yahoo.com</a>><br>
To: Andrew Barnert <<a href="mailto:abarnert@yahoo.com">abarnert@yahoo.com</a>><br>
Cc: Nick Coghlan <<a href="mailto:ncoghlan@gmail.com">ncoghlan@gmail.com</a>>, python-ideas<br>
        <<a href="mailto:python-ideas@python.org">python-ideas@python.org</a>><br>
Subject: Re: [Python-ideas] Python Float Update<br>
Message-ID: <<a href="mailto:90691306-98E3-421B-ABEB-BA2DE05962C6@yahoo.com">90691306-98E3-421B-ABEB-BA2DE05962C6@yahoo.com</a>><br>
Content-Type: text/plain;       charset=us-ascii<br>
<br>
On Jun 1, 2015, at 18:27, Andrew Barnert via Python-ideas <<a href="mailto:python-ideas@python.org">python-ideas@python.org</a>> wrote:<br>
><br>
>> On Jun 1, 2015, at 17:08, Nick Coghlan <<a href="mailto:ncoghlan@gmail.com">ncoghlan@gmail.com</a>> wrote:<br>
>><br>
>> On 2 Jun 2015 08:44, "Andrew Barnert via Python-ideas"<br>
>> <<a href="mailto:python-ideas@python.org">python-ideas@python.org</a>> wrote:<br>
>>> But the basic idea can be extracted out and Pythonified:<br>
>>><br>
>>> The literal 1.23 no longer gives you a float, but a FloatLiteral, which is either a subclass of float, or an unrelated class that has a __float__ method. Doing any calculation on it gives you a float. But as long as you leave it alone as a FloatLiteral, it has its literal characters available for any function that wants to distinguish FloatLiteral from float, like the Decimal constructor.<br>
>>><br>
>>> The problem that Python faces that Swift doesn't is that Python doesn't use static typing and implicit compile-time conversions. So in Python, you'd be passing around these larger values and doing the slow conversions at runtime. That may or may not be unacceptable; without actually building it and testing some realistic programs it's pretty hard to guess.<br>
>><br>
>> Joonas's suggestion of storing the original text representation passed<br>
>> to the float constructor is at least a novel one - it's only the idea<br>
>> of actual decimal literals that was ruled out in the past.<br>
><br>
> I actually built about half an implementation of something like Swift's LiteralConvertible protocol back when I was teaching myself Swift. But I think I have a simpler version that I could implement much more easily.<br>
><br>
> Basically, FloatLiteral is just a subclass of float whose __new__ stores its constructor argument. Then decimal.Decimal checks for that stored string and uses it instead of the float value if present. Then there's an import hook that replaces every Num with a call to FloatLiteral.<br>
><br>
> This design doesn't actually fix everything; in effect, 1.3 actually compiles to FloatLiteral(str(float('1.3')) (because by the time you get to the AST it's too late to avoid that first conversion). Which does actually solve the problem with 1.3, but doesn't solve everything in general (e.g., just feed in a number that has more precision than a double can hold but less than your current decimal context can...).<br>
><br>
> But it just lets you test whether the implementation makes sense and what the performance effects are, and it's only an hour of work,<br>
<br>
Make that 15 minutes.<br>
<br>
<a href="https://github.com/abarnert/floatliteralhack" target="_blank">https://github.com/abarnert/floatliteralhack</a><br>
<br>
> and doesn't require anyone to patch their interpreter to play with it. If it seems promising, then hacking the compiler so 2.3 compiles to FloatLiteral('2.3') may be worth doing for a test of the actual functionality.<br>
><br>
> I'll be glad to hack it up when I get a chance tonight. But personally, I think decimal literals are a better way to go here. Decimal(1.20) magically doing what you want still has all the same downsides as 1.20d (or implicit decimal literals), plus it's more complex, adds performance costs, and doesn't provide nearly as much benefit. (Yes, Decimal(1.20) is a little nicer than Decimal('1.20'), but only a little--and nowhere near as nice as 1.20d).<br>
><br>
>> Aside from the practical implementation question, the main concern I<br>
>> have with it is that we'd be trading the status quo for a situation<br>
>> where "Decimal(1.3)" and "Decimal(13/10)" gave different answers.<br>
><br>
> Yes, to solve that you really need Decimal(13)/Decimal(10)... Which implies that maybe the simplification in Decimal(1.3) is more misleading than helpful. (Notice that this problem also doesn't arise for decimal literals--13/10d is int vs. Decimal division, which is correct out of the box. Or, if you want prefixes, d13/10 is Decimal vs. int division.)<br>
><br>
>> It seems to me that a potentially better option might be to adjust the<br>
>> implicit float->Decimal conversion in the Decimal constructor to use<br>
>> the same algorithm as we now use for float.__repr__ [1], where we look<br>
>> for the shortest decimal representation that gives the same answer<br>
>> when rendered as a float. At the moment you have to indirect through<br>
>> str() or repr() to get that behaviour:<br>
>><br>
>>>>> from decimal import Decimal as D<br>
>>>>> 1.3<br>
>> 1.3<br>
>>>>> D('1.3')<br>
>> Decimal('1.3')<br>
>>>>> D(1.3)<br>
>> Decimal('1.3000000000000000444089209850062616169452667236328125')<br>
>>>>> D(str(1.3))<br>
>> Decimal('1.3')<br>
>><br>
>> Cheers,<br>
>> Nick.<br>
>><br>
>> [1] <a href="http://bugs.python.org/issue1580" target="_blank">http://bugs.python.org/issue1580</a><br>
> _______________________________________________<br>
> Python-ideas mailing list<br>
> <a href="mailto:Python-ideas@python.org">Python-ideas@python.org</a><br>
> <a href="https://mail.python.org/mailman/listinfo/python-ideas" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
> Code of Conduct: <a href="http://python.org/psf/codeofconduct/" target="_blank">http://python.org/psf/codeofconduct/</a><br>
<br>
<br>
------------------------------<br>
<br>
Message: 4<br>
Date: Tue, 2 Jun 2015 11:58:09 +1000<br>
From: Steven D'Aprano <<a href="mailto:steve@pearwood.info">steve@pearwood.info</a>><br>
To: <a href="mailto:python-ideas@python.org">python-ideas@python.org</a><br>
Subject: Re: [Python-ideas] Python Float Update<br>
Message-ID: <<a href="mailto:20150602015809.GE932@ando.pearwood.info">20150602015809.GE932@ando.pearwood.info</a>><br>
Content-Type: text/plain; charset=us-ascii<br>
<br>
On Tue, Jun 02, 2015 at 10:08:37AM +1000, Nick Coghlan wrote:<br>
<br>
> It seems to me that a potentially better option might be to adjust the<br>
> implicit float->Decimal conversion in the Decimal constructor to use<br>
> the same algorithm as we now use for float.__repr__ [1], where we look<br>
> for the shortest decimal representation that gives the same answer<br>
> when rendered as a float. At the moment you have to indirect through<br>
> str() or repr() to get that behaviour:<br>
<br>
Apart from the questions of whether such a change would be allowed by<br>
the Decimal specification, and the breaking of backwards compatibility,<br>
I would really hate that change for another reason.<br>
<br>
At the moment, a good, cheap way to find out what a binary float "really<br>
is" (in some sense) is to convert it to Decimal and see what you get:<br>
<br>
Decimal(1.3)<br>
-> Decimal('1.3000000000000000444089209850062616169452667236328125')<br>
<br>
If you want conversion from repr, then you can be explicit about it:<br>
<br>
Decimal(repr(1.3))<br>
-> Decimal('1.3')<br>
<br>
("Explicit is better than implicit", as they say...)<br>
<br>
Although in fairness I suppose that if this change happens, we could<br>
keep the old behaviour in the from_float method:<br>
<br>
# hypothetical future behaviour<br>
Decimal(1.3)<br>
-> Decimal('1.3')<br>
Decimal.from_float(1.3)<br>
-> Decimal('1.3000000000000000444089209850062616169452667236328125')<br>
<br>
But all things considered, I don't think we're doing people any favours<br>
by changing the behaviour of float->Decimal conversions to implicitly<br>
use the repr() instead of being exact. I expect this strategy is like<br>
trying to flatten a bubble under wallpaper: all you can do is push the<br>
gotchas and surprises to somewhere else.<br>
<br>
Oh, another thought... Decimals could gain yet another conversion<br>
method, one which implicitly uses the float repr, but signals if it was<br>
an inexact conversion or not. Explicitly calling repr can never signal,<br>
since the conversion occurs outside of the Decimal constructor and<br>
Decimal sees only the string:<br>
<br>
Decimal(repr(1.3)) cannot signal Inexact.<br>
<br>
But:<br>
<br>
Decimal.from_nearest_float(1.5)  # exact<br>
Decimal.from_nearest_float(1.3)  # signals Inexact<br>
<br>
That might be useful, but probably not to beginners.<br>
<br>
<br>
--<br>
Steve<br>
<br>
<br>
------------------------------<br>
<br>
Subject: Digest Footer<br>
<br>
_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
<br>
<br>
------------------------------<br>
<br>
End of Python-ideas Digest, Vol 103, Issue 14<br>
*********************************************<br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature"><div dir="ltr"><font face="garamond, serif" size="6">-Surya Subbarao</font></div></div>
</div>