[Python-Dev] Decimal <-> float comparisons in py3k.

Glenn Linderman v+python at g.nevcal.com
Thu Mar 18 19:27:06 CET 2010


On 3/18/2010 5:23 AM, Steven D'Aprano wrote:
> On Thu, 18 Mar 2010 08:58:25 am Raymond Hettinger wrote:
>    
>> On Mar 17, 2010, at 1:59 PM, Steven D'Aprano wrote:
>>      
>>> On Thu, 18 Mar 2010 07:44:21 am Raymond Hettinger wrote:
>>>        
>>>> The spectrum of options from worst to best is
>>>> 1) compare but give the wrong answer
>>>> 2) compare but give the right answer
>>>> 3) refuse to compare.
>>>>          
>>> Why is 3 the best? If there is a right answer to give, surely
>>> giving the right answer it is better than not?
>>>        
>>  From the early days of the decimal module,
>> we've thought that mixed float-decimal operations
>> are 1) a bit perilous and 2) have few, if any good
>> use cases.
>>      
> When it comes to *arithmetic* operations, I agree. Is there anyone on
> python-dev willing to argue the case for allowing implicit mixed
> float/Decimal arithmetic operations? The arguments in the PEP seem
> pretty convincing to me, and I'm not suggesting we change that.
>
> But comparison operations are different. For starters, you don't need to
> worry about whether to return a float or a Decimal, because you always
> get a bool. In theory, both Decimals and floats are representations of
> the same underlying thing, namely real numbers, and it seems strange to
> me that I can't ask whether two such real numbers are equal just
> because their storage implementation is different.
>
> I can see three reasonable reasons for avoiding mixed comparisons:
>
> (1) To avoid confusing float-naive users (but they're confused by pure
> float comparisons too).
>
> (2) To avoid mixed arithmetic operations (but comparisons aren't
> arithmetic).
>
> (3) If Decimals and floats compare equal, they must hash equal, and
> currently they don't (but Mark Dickinson thinks he has a solution for
> that).
>
>
>
>    
>> Accordingly, any mixed operations should be explicit
>> rather than implicit:
>>
>>       Decimal('1.1') + Decimal.from_float(2.2)
>>
>> is better than:
>>
>>       Decimal('1.1') + 2.2
>>      
> Agreed. The user should explicitly choose whether they want a float
> answer or a Decimal answer.
>
>
>    
>> To help the user avoid confusion, we flag the latter with a
>> TypeError: unsupported operand type(s) for +: 'Decimal' and 'float'.
>>
>> Unfortunately, in Py2.x, implicit mixed comparisons do not
>> raise an exception, and instead will silently fail by giving
>>
>> an incorrect answer:
>>      >>>  Decimal('1.1')<  2.2
>>      False
>>      
> That is clearly the wrong thing to do.
>
> Do you envisage any problems from allowing this instead?
>
>    
>>>> Decimal('1.1')<  2.2
>>>>          
> True
>    

Yes.

As any non-naïve float user is aware, the proper form of float 
comparisons is not to use < or > or == or !=, but rather, instead of 
using < (to follow along with your example), one should use:

Decimal('1.1') - 2.2 < epsilon

However, while even this is only useful in certain circumstances as a 
gross simplification [1], it immediately shows the need to do mixed 
arithmetic to produce (sometimes) correct results.  More correct 
comparisons require much more code (even the 20-line C code in [1], 
which understands the float format to some extent, admits to being 
deficient in some circumstances).

For all the reasons that mixed decimal and float arithmetic is bad, 
mixed decimal and float comparisons are also bad.  To do proper 
comparisons, you need to know the number of significant digits of both 
numbers, and the precision and numeric ranges being dealt with by the 
application.

For the single purpose of sorting, one could make an argument that not 
knowing the significant digits, precision, and numeric ranges, that the 
sort would probably produce results where floats and decimals that 
should compare equal would be clustered similarly as they would if the 
significant digits, precision, and numeric ranges were known, and that 
would probably be close to truth, but only if the decimal vs float key 
were the last in the composite sort key.  I don't think Python informs 
its comparison operations that it is being used as part of a sort, nor 
would there be a way for user-written sorts to inform the comparison 
operations of that fact.

Seems like it would be better to raise an exception, and in the 
documentation for the exception point out that turning off the exception 
(if it should be decided that that should be possible, which could be 
good for compatibility), would regress to the current behavior, which 
doesn't sort numerically, but by type.

[1]
http://www.cprogramming.com/tutorial/floating_point/understanding_floating_point_representation.html


Glenn


More information about the Python-Dev mailing list