473,386 Members | 1,708 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

Re: Comparing float and decimal

Gerhard Häring wrote:
D'Arcy J.M. Cain wrote:
>I'm not sure I follow this logic. Can someone explain why float and
integer can be compared with each other and decimal can be compared to
integer but decimal can't be compared to float?
>>>>from decimal import Decimal
i = 10
f = 10.0
d = Decimal("10.00")
i == f
True
>>>>i == d
True
>>>>f == d
False

I can give you the technical answer after reading the sources of the
decimal module: you can only compare to Decimal what can be converted to
Decimal. And that is int, long and another Decimal.
The new fractions module acts differently, which is to say, as most
would want.
>>from fractions import Fraction as F
F(1) == 1.0
True
>>F(1.0)
Traceback (most recent call last):
File "<pyshell#20>", line 1, in <module>
F(1.0)
File "C:\Program Files\Python30\lib\fractions.py", line 97, in __new__
numerator = operator.index(numerator)
TypeError: 'float' object cannot be interpreted as an integer
>>F(1,2) == .5
True
>>.5 == F(1,2)
True

so Fraction obviously does comparisons differently.

Decimal is something of an anomaly in Python because it was written to
exactly follow an external standard, with no concessions to what would
be sensible for Python. It is possible that that standard mandates that
Decimals not compare to floats.

tjr

Sep 23 '08 #1
6 3657
Terry Reedy <tj*****@udel.eduwrote:
The new fractions module acts differently, which is to say, as most
would want.
>>from fractions import Fraction as F
>>F(1) == 1.0
True
>>F(1.0)
Traceback (most recent call last):
File "<pyshell#20>", line 1, in <module>
F(1.0)
File "C:\Program Files\Python30\lib\fractions.py", line 97, in __new__
numerator = operator.index(numerator)
TypeError: 'float' object cannot be interpreted as an integer
Both the Fraction module and the Decimal module could represent floats
exactly and reversibly since floats are of the form

mantissa * 2**exponent

which is exactly representable as a fraction (rational) and also as

mantissa2 * 10**exponent2

as to why we don't do this...

I guess it is to preserve the sanity of the user when they write
fraction(0.1) or decimal(0.1) did they really mean fraction(1,10),
decimal("0.1") or the exact representations which are
decimal("0.100000000000000005551115123125782702118 1583404541015625")
and fraction(3602879701896397,2**55)

Given that we let the exact representations leak out anyway (which
causes a lot of FAQs in this list), eg
>>0.1
0.10000000000000001

IMHO We should put the exact conversions in for floats to Decimal and
Fraction by default and add a new section to the FAQ!

In that way people will see floats for what they really are - a crude
approximation to a rational number ;-)

--
Nick Craig-Wood <ni**@craig-wood.com-- http://www.craig-wood.com/nick
Sep 24 '08 #2
On Sep 23, 7:31*pm, Terry Reedy <tjre...@udel.eduwrote:
Decimal is something of an anomaly in Python because it was written to
exactly follow an external standard, with no concessions to what would
be sensible for Python. *It is possible that that standard mandates that
Decimals not compare to floats.
I don't think the standard says anything about interactions between
Decimals and floats. But there's certainly been a feeling amongst at
least some of the developers that the job of Python's decimal module
is
to implement the standard and no more, and that extensions to its
functionality belong elsewhere.

Regarding equality, there's at least one technical issue: the
requirement
that objects that compare equal hash equal. How do you come up with
efficient hash operations for integers, floats, Decimals and Fractions
that satisfy this requirement?

For other arithmetic operations: should the sum of a float and a
Decimal
produce a Decimal or a float? Why? It's not at all clear to me that
either of these types is 'higher up' the numerical tower than the
other.

Mark
Sep 24 '08 #3
Mark Dickinson wrote:
On Sep 23, 7:31 pm, Terry Reedy <tjre...@udel.eduwrote:
>Decimal is something of an anomaly in Python because it was written to
exactly follow an external standard, with no concessions to what would
be sensible for Python. It is possible that that standard mandates that
Decimals not compare to floats.

I don't think the standard says anything about interactions between
Decimals and floats.
If there is not now, there could be in the future, and the decimal
authors are committed to follow the standard wherever it goes.
Therefore, the safe course, to avoid possible future deprecations due to
doing too much, is to only do what is mandated.
But there's certainly been a feeling amongst at
least some of the developers that the job of Python's decimal module
is to implement the standard and no more, and that extensions to its
functionality belong elsewhere.
For the reason just stated. A slightly different take is this. The
reason for following the standard is so that decimal code in Python is
exact interconversion both from and to decimal code in other languages.
(And one reason for *that* is that one purpose of the standard is to
reliably implement legal and contractual standards for financial
calculations.) Using extensions in Python could break/deprecate code
translated away from Python.
Regarding equality, there's at least one technical issue: the
requirement
that objects that compare equal hash equal. How do you come up with
efficient hash operations for integers, floats, Decimals and Fractions
that satisfy this requirement?
For integral values, this is no problem.
>>hash(1) == hash(1.0) == hash(decimal.Decimal(1)) ==
hash(fractions.Fraction(1)) == 1
True
For other arithmetic operations: should the sum of a float and a
Decimal produce a Decimal or a float? Why? It's not at all clear to me that
either of these types is 'higher up' the numerical tower than the
other.
Floats and fractions have the same issue. Fractions are converted to
floats. I can think of two reasons: float operations are faster; floats
are my typically thought of as inexact and since the result is likely to
be inexact (rounded), float is the more appropriate type to express
that. Anyone who disagrees with the choice for their application can
explicitly convert the float to a fraction.

Decimals can also be converted to floats (they also have a __float__
method). But unlike fractions, the conversion must be explicit, using
float(decimal), instead of implicit, as with ints and fractions.

Someone *could* write a PyDecimal wrapper that would do implicit
conversion and thereby more completely integrate decimals with other
Python numbers, but I doubt that saving transitivity of equality will be
sufficient motivation ;-).

Terry Jan Reedy

Sep 24 '08 #4
On Wed, 24 Sep 2008 04:30:03 -0500, Nick Craig-Wood wrote:

Both the Fraction module and the Decimal module could represent floats
exactly and reversibly since floats are of the form

mantissa * 2**exponent

which is exactly representable as a fraction (rational) and also as

mantissa2 * 10**exponent2

as to why we don't do this...

I guess it is to preserve the sanity of the user when they write
fraction(0.1) or decimal(0.1) did they really mean fraction(1,10),
decimal("0.1") or the exact representations which are
decimal("0.100000000000000005551115123125782702118 1583404541015625") and
fraction(3602879701896397,2**55)

I would say that in practice the chances that somebody *actually* wanted
0.100000000000000005551115123125782702118158340454 1015625 when they wrote
0.1 is about the same as the chances that the BDFL will support braces in
Python 3.0.

(Hint: "from __future__ import braces")

Given that we let the exact representations leak out anyway (which
causes a lot of FAQs in this list), eg
>>>0.1
0.10000000000000001

IMHO We should put the exact conversions in for floats to Decimal and
Fraction by default and add a new section to the FAQ!

But of the reasons for having the Decimal module is to avoid such leaky
abstractions. Without Decimal (or fraction) there's no obvious way to get
0.1 exactly. It seems perverse to suggest that by default Decimal should
deliberately expose the same leaky abstraction that causes so much
trouble when people use floats.
In that way people will see floats for what they really are - a crude
approximation to a rational number ;-)
You can already see that just by printing a float:
>>0.3
0.29999999999999999
>>0.1
0.10000000000000001
--
Steven
Sep 25 '08 #5
On Sep 24, 6:18*pm, Terry Reedy <tjre...@udel.eduwrote:
If there is not now, there could be in the future, and the decimal
authors are committed to follow the standard wherever it goes.
Therefore, the safe course, to avoid possible future deprecations due to
doing too much, is to only do what is mandated.
Makes sense. It looks as though the standard's pretty stable now
though; I'd be quite surprised to see it evolve to include discussion
of floats. But then again, people thought it was stable just before
all the extra transcendental operations appeared. :-)
For integral values, this is no problem.
*>>hash(1) == hash(1.0) == hash(decimal.Decimal(1)) ==
hash(fractions.Fraction(1)) == 1
True
Getting integers and Decimals to hash equal was actually
something of a pain, and required changing the way that
the hash of a long was computed. The problem in a nutshell:
what's the hash of Decimal('1e100000000')? The number is
clearly an integer, so its hash should be the same as that
of 10**100000000. But computing 10**100000000, and then
finding its hash, is terribly slow... (Try
hash(Decimal('1e100000000')) in Python 2.5 and see
what happens! It's fixed in Python 2.6.)

As more numeric types get added to Python, this
'equal implies equal hash' requirement becomes more
and more untenable, and difficult to maintain. I also find
it a rather unnatural requirement: numeric equality
is, to me, a weaker equivalence relation than the one
that should be used for identifying keys in dictionaries,
elements of sets, etc. Fraction(1, 2) and 0.5 should, to my
eyes, be considered
different elements of a set. But the only way to 'fix' this
would be to have Python recognise two different types of
equality, and then it wouldn't be Python any more.

The SAGE folks also discovered that they couldn't
maintain the hash requirement.
Decimals can also be converted to floats (they also have a *__float__
method). *But unlike fractions, the conversion must be explicit, using
float(decimal), instead of implicit, as with ints and fractions.
Maybe: if I *had* to pick a direction, I'd make float + Decimal
produce a Decimal, on the basis that Decimal is arbitrary precision
and that the float->Decimal conversion can be made losslessly.
But then there are a whole host of decisions one has to make
about rounding, significant zeros, ... (And then, as you point
out, Cowlishaw might come out with a new version of the standard
that does include interactions with floats, and makes an entirely
different set of decisions...)

Mark
Sep 25 '08 #6
Mark Dickinson wrote:
On Sep 24, 6:18 pm, Terry Reedy <tjre...@udel.eduwrote:
>If there is not now, there could be in the future, and the decimal
authors are committed to follow the standard wherever it goes.
Therefore, the safe course, to avoid possible future deprecations due to
doing too much, is to only do what is mandated.

Makes sense. It looks as though the standard's pretty stable now
though; I'd be quite surprised to see it evolve to include discussion
of floats. But then again, people thought it was stable just before
all the extra transcendental operations appeared. :-)
What got me were the bizarre new 'logical' operations whose addition
were rather nonsensical from a Python viewpoint (though probably
sensible from an IBM profit business viewpoint). With those added, and
with this thread, I have decided that Decimals best be thought of as a
separate universe, not to be mixed with other numbers unless one has
good reason to and understands the possible anomalies of doing so. For
pure finance apps, I would think that there should be little reason to mix.

tjr

Sep 26 '08 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Robert Oschler | last post by:
Is there a way to use CAST() to convert a string MySQL field to a 'float' value? I know I can convert a string to a SIGNED or UNSIGNED integer value, but not float. I tried FLOAT, DECIMAL, and a...
687
by: cody | last post by:
no this is no trollposting and please don't get it wrong but iam very curious why people still use C instead of other languages especially C++. i heard people say C++ is slower than C but i can't...
15
by: Kay Schluehr | last post by:
I wonder why this expression works: >>> decimal.Decimal("5.5")**1024 Decimal("1.353299876254915295189966576E+758") but this one causes an error 5.5**1024 Traceback (most recent call...
2
by: O.B. | last post by:
In the following piece of code, the == operator is saying that the two different float values are the same. What's going on here? float testValueA = float.MaxValue; float testValueB =...
18
by: Carramba | last post by:
Hi! is there a better/faster way to compare mantissas of to real number then in following code? #include <stdio.h> #include <stdlib.h> int main(void) { float a,b; int test;
1
Shashi Sadasivan
by: Shashi Sadasivan | last post by:
hi, im comparing two decimal variables d1,d2. at some points, d1 == d2 (where d1 and d2 = 8 shown in debug mode) turns out as false!!! is this a c/c++ version of comparing floats? any ideas on...
7
by: Guido van Brakel | last post by:
Hello I have this now: It now gives a int, but i would like to see floats. How can integrate that into the function? Regards,
17
by: D'Arcy J.M. Cain | last post by:
I'm not sure I follow this logic. Can someone explain why float and integer can be compared with each other and decimal can be compared to integer but decimal can't be compared to float? True...
0
by: =?ISO-8859-1?Q?Gerhard_H=E4ring?= | last post by:
D'Arcy J.M. Cain wrote: I can give you the technical answer after reading the sources of the decimal module: you can only compare to Decimal what can be converted to Decimal. And that is int,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.