*** Python 2.5.1 (r251:54863, May 1 2007, 17:47:05) [MSC v.1310 32
bit (Intel)] on win32. ***
>>> float (.3)
0.29999999999999999
>>> foo = 0.3
>>> foo
0.29999999999999999
>>>
Regards,
Marek
This is true. Fortunately Python does provide a module which allows
you to work with exact floating point quantities.
http://docs.python.org/lib/module-decimal.html
Of course the downside is that these are not quite as fast as the
built in float type, but probably good enough for most purposes.
Preston
> I've never had any call to use floating point numbers and now that
> I want to, I can't!
Ever considered phrasing your actual problem so one can help, let
alone looking at the archive for many, many postings about this
topic?
Regards,
Björn
--
BOFH excuse #66:
bit bucket overflow
A classic (if lengthy) read:
http://docs.sun.com/source/806-3568/ncg_goldberg.html
If you just want to see a pretty representation:
>>> print 0.3
0.3
If you need a pretty string for use in code:
>>> def pretty_fp(fpnum, prec=8):
... return ('%.8f' % fpnum).rstrip('0')
...
>>> pretty_fp(0.3)
'0.3'
That's a misconception. The decimal-module has a different base (10
instead of 2), and higher precision. But that doesn't change the fact
that it will expose the same rounding-errors as floats do - just for
different numbers.
>>> import decimal as d
>>> d = d.Decimal
>>> d("1") / d("3") * d("3")
Decimal("0.9999999999999999999999999999")
>>>
The advantage is that the rounding errors are the ones expected in
monetary caluclations, which means that you can write correct programs
for such purposes.
Diez
Nothing!
> that's what "print" invokes, whereas the interpreter prompt is using
>
> repr(0.3)
Thanks for pointing that out.
No, print invokes the tp_print slot of the float type. Some core types
have a special handler for print. The tp_print slot is not available
from Python code and most people don't know about it. :]
Christian
???
bruno@bruno:~$ python
Python 2.5.1 (r251:54863, May 2 2007, 16:56:35)
[GCC 4.1.2 (Ubuntu 4.1.2-0ubuntu4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class Toto(object):
... def tp_print(self):
... return "AHAHAHA"
...
>>> t = Toto()
>>> t
<__main__.Toto object at 0xb7db8d6c>
>>> print t
<__main__.Toto object at 0xb7db8d6c>
>>> (0.3).tp_print
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'float' object has no attribute 'tp_print'
>>> (0.3).__print__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'float' object has no attribute '__print__'
>>> (0.3).__tp_print__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'float' object has no attribute '__tp_print__'
>>>
I Must have miss something...
Yeah, You have missed the beginning of the third sentence: "The tp_print
slot is not available from Python code". The tp_print slot is only
available in C code and is part of the C definition of a type. Hence tp_
as type.
Search for float_print and tp_print in
http://svn.python.org/view/python/trunk/Objects/floatobject.c?rev=60567&view=auto
Christian
> I Must have miss something...
Perhaps you missed the part where Christian said "The tp_print slot is not
available from Python code"?
oops, my bad ! I missed the "not" !-)
> Bruno Desthuilliers wrote:
>> I Must have miss something...
>
> Yeah, You have missed the beginning of the third sentence: "The
tp_print
> slot is not available from Python code". The tp_print slot is only
> available in C code and is part of the C definition of a type. Hence
tp_
> as type.
It isn't easy to come up with an example which actually demonstrates
that print doesn't just call str, but after a little playing around I
managed it:
>>> class mystr(str):
def __str__(self):
return mystr('oops')
>>> s = mystr('aargh')
>>> s
'aargh'
>>> str(s)
'oops'
>>> print s
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
print s
RuntimeError: maximum recursion depth exceeded
>>>
Alternatively:
>>> class mystr(str):
def __str__(self):
if self=='oops':
return 'you printed me!'
return mystr('oops')
>>> s = mystr('aargh')
>>> str(s)
'oops'
>>> str(str(s))
'you printed me!'
>>> print s
and on that last line idle locks until you restart the shell. I can't
immediately see why; the command line interpreter is fine so it seems
just to be an idle problem:
>>> class mystr(str):
... def __str__(self):
... if self=='oops':
... return 'you printed me!'
... return mystr('oops')
...
>>> s = mystr('aargh')
>>> s
'aargh'
>>> str(s)
'oops'
>>> print s
you printed me!
>>>
Why does print use the tp_print slot, rather than str()? Are the two
effectively redundant? If (non-repr) string representations are
frequently needed for a given type, could str() be implemented as a
reference to tp_slot, via a C-language extension?
>> No, print invokes the tp_print slot of the float type. Some core types
>> have a special handler for print. The tp_print slot is not available
>> from Python code and most people don't know about it. :]
>
> Why does print use the tp_print slot, rather than str()? Are the two
> effectively redundant? If (non-repr) string representations are
> frequently needed for a given type, could str() be implemented as a
> reference to tp_slot, via a C-language extension?
As a side note, the print statement has FIVE related opcodes. Looks like
printing has been considered a very important operation...
--
Gabriel Genellina
The tp_print slot is used only when printing to a C file descriptor. In
most cases where it is used it simply duplicates the str and repr
functionality but avoids building the entire output in memory. It also
takes a flag argument indicating whether it should output the str or repr,
the latter being used when rendering the content inside an object such as a
dict or list.
So for example a dict's repr builds a list containing the repr of each
key/value pair and then joins the list using a comma separator. The
tp_print simply outputs the '{', then uses tp_print to output the repr of
the key and repr of the value with appropriate separators and finally the
closing '}'. It would not suprise me if by replacing the output of a single
large string with a lot of small calls to fputs 'print x' could be slower
than 'print str(x)'.
Surely you jest. Your example is exact to 28 digits. Your attempted
trick is to use a number that never ends (1/3=0.3333...). It would
only convert back to one if you have and infinite number of
significant digits. That has nothing to do with the Python decimal
module (which does what it claims). It is one of the idiosyncrasies
of the base 10 number system. Remember we are working with base 10
decimals and not fractions.
Diez was not claiming that the decimal module did anything less than
what it promised. He just pointed out that the module does not support
infinitely precise floating-point arithmetic, any more than tradition
base-2 representations do. Please review the thread (the parts you
snipped) for clarification.
I think we're using the term "rounding error" to mean different things.
If the value 1/3 is represented as a finite sequence of threes divided
by a power of ten (e.g. 0.3333333333333333333333333333), then it is
actually representing a different value than the original 1/3
(3333333333333333333333333333/10000000000000000000000000000). This is
what most of us mean by "rounding error." There are data types than can
represent rational numbers exactly, such that 1 / 3 * 3 = 1.
> For anything less that 28
> significant digits it rounds to 1.0.
I'm not sure what you mean here. Do you mean that Decimal can represent
any sequence of up to 28 decimal digits without any loss in precision?
No one disputes that.
> With floats 1.0/3 yields
> 0.33333333333333331<-- on my machine.
Right, that is != 1/3. But if the last digit were a 3, the number still
would not be 1/3, only a different approximation of it.
> Also you can compare two
> decimal.Decimal() objects for equality. With floats you have to test
> for a difference less than some small value.
A small margin of error (epsilon) is required for both Decimal and
floats. Both of these data types have "floating points;" they just use
different radixes. Particular sorts of rounding-errors have become
acceptable in base-10 arithmetic within certain (mainly financial)
contexts, so Decimal is preferable for calculations in those contexts.
For the same reason, a major U.S. stock exchange switched from base-2 to
base-10 arithmetic a few years ago. There's nothing inherently more
accurate about base-10.
> BTW, a college professor
> who also wrote code for a living made this offhand remark "In general
> it is best to multiply first and then divide." Good general advice.
It is best to keep track of how many significant digits remain in
whatever base is being used. "M before D" may help preserve sig.
digits, but it is not a substitute for knowing how much error each
calculation introduces.
The point is that all numbering systems with a base + precision will
have (rational) values they can't exactly represent. Q\R is of course
out of the question by definition....
And the poster I replied to said
"""
This is true. Fortunately Python does provide a module which allows
you to work with exact floating point quantities.
"""
Which is not more true for decimal as it is for IEEE754 floating points.
Just for other values.
Diez
This 'Decimal is exact' myth has been appearing often enough that I
wonder whether it's worth devoting a prominent paragraph to in the
docs.
Mark
> I disagree with this statement
> <quote>But that doesn't change the fact that it will expose the same
> rounding-errors as floats do - just for different numbers. </quote> The
> example used has no rounding errors.
Of course it does. Three thirds equals one, not 0.9999, or
0.9999999999999999999999999999, or any other finite decimal
representation. That's a rounding error, regardless of whether you are
rounding in base 2 (like floats) or in base 10 (like Decimal does).
> Also you can compare two
> decimal.Decimal() objects for equality. With floats you have to test
> for a difference less than some small value.
That's a superstition.
As a heuristic, it is often wise to lower your expectations when testing
for equality. Since you often don't know how much rounding error will be
introduced into a calculation, demanding that a calculation has zero
rounding error is often foolish.
But good advice becomes a superstition when it becomes treated as a law:
"never test floats for equality". That's simply not true. For example,
floats are exact for whole numbers, up to the limits of overflow. If you
know your floats are whole numbers, and still writing something like this:
x = 1234.0
y = 1000.0 + 200.0 + 30.0 + 4.0
if abs(x-y) < 1e-12:
print "x and y are equal"
then you are wasting your time and guilty of superstitious behaviour.
Similarly for fractional powers of two.
x = 1/2 + 1/4 + 1/8 + 1/16
y = 1.0 - 1/32 - 1/32
assert x == y
--
Steven
That's not true. Epsilon becomes large (in absolute terms) for large
numbers. For 64-bit IEEE floats, eps > 1 at about 10**16.
> If you
> know your floats are whole numbers, and still writing something like this:
>
> x = 1234.0
> y = 1000.0 + 200.0 + 30.0 + 4.0
> if abs(x-y) < 1e-12:
> print "x and y are equal"
>
> then you are wasting your time and guilty of superstitious behaviour.
In what way? It's true that you hard-coded integers for which the
margin of error happens to be < 1, but there's nothing magical about
whole numbers. If you need to test for exact equality, you still can
only check within the limits of the float's precision.
>>> 1e16 + 1 == 10000000000000000
True
>>> 1e16 == 10000000000000000 - 1
False
>> But good advice becomes a superstition when it becomes treated as a
>> law: "never test floats for equality". That's simply not true. For
>> example, floats are exact for whole numbers, up to the limits of
>> overflow.
>
> That's not true. Epsilon becomes large (in absolute terms) for large
> numbers. For 64-bit IEEE floats, eps > 1 at about 10**16.
Ah yes, good point. Sorry for my brain-fart, I was conflating integer
floats with the comp data type, as used in the Standard Apple Numerics
Environment (SANE). It used a floating point data type to store what was
effectively a 64-bit integer, which was quite significant in the days
when PCs used 16-bit integers!
Nevertheless, I stand by my claim, and support it by quoting from
Professor W Kahan of Berkley, who wrote in the forward to the Apple
Numerics Manual (2nd Edition):
[quote]
... because so many computers in the 1960's and 1970's possessed so many
different arithmetic anomalies, computational lore has become encumbered
with a vast body of superstition purporting to cope with them. One such
superstitious rule is "*Never* ask whether floating-point numbers are
exactly equal."
[end quote]
In practice, you often do want to test floating point values within some
tolerance. But it isn't a universal law: see also "What Every Computer
Scientist Should Know About Floating Point Arithmetic".
[quote]
Incidentally, some people think that the solution to such anomalies is
never to compare floating-point numbers for equality, but instead to
consider them equal if they are within some error bound E. This is hardly
a cure-all because it raises as many questions as it answers.
[end quote]
http://docs.sun.com/source/806-3568/ncg_goldberg.html
Not directly related to this issue, but to get a great overview of some
of the problems with floating point, you could do a lot worse than to
read the following interview with Kahan:
and this wonderful lecture:
http://www.cs.berkeley.edu/~wkahan/ieee754status/ieee754.ps
where he details how optimizing compilers cause arithmetic errors, how
and why the facilities provided by IEEE arithmetic are underused, and
finally gives his idea of some things that could be done to turn the
situation around.
Sadly this lecture was given almost twelve years ago, and things have
barely changed. Compilers still do the wrong thing, especially optimizing
ones; computations that would be easy with NANs and infinities are
needlessly difficult; and benchmarks still over-value speed and under-
value getting the right answer, let alone simplicity of programming.
>> If you know your floats are whole numbers, and still writing
>> something like this:
>>
>> x = 1234.0
>> y = 1000.0 + 200.0 + 30.0 + 4.0
>> if abs(x-y) < 1e-12:
>> print "x and y are equal"
>>
>> then you are wasting your time and guilty of superstitious behaviour.
>
> In what way? It's true that you hard-coded integers for which the
> margin of error happens to be < 1,
No, in this case the error is *precisely* zero. There simply are no
rounding errors in this calculation, and the error is zero. If you wrote
the test as "if abs(x-y) < 1.0" you'd still be wasting your time.
It's true that I gave a hard-coded example, but it is hardly a special
case. There are many problem domains that don't require the full range of
floats and the type of rounding error you give can't occur.
(If your application calculates the amount of concrete needed to build a
house, say, then you pretty much know the amounts aren't going to be
measured in the trillions of megatonnes. If a user insists on specifying
that the house has 1.73e820 stories built on a base measuring 1.82e-87
metres squared, then roundoff is the least of your problems: the
algorithms you are applying will no longer be valid.)
Or possible you have already rounded the numbers yourself, earlier:
>>> x = round(1.5678, 2)
>>> x == 1.57
True
Why would you do this instead?
>>> abs(x - 1.57) < 1e-12
True
The important thing is that your numbers have appropriately similar
scales. If you know that it going to be the case, then you know that
addition won't cause the sort of round-off error. I'm talking about.
Naturally there may be other forms of round-off, but rounding error
doesn't just appear from nowhere, it is predictable and understandable.
--
Steven
I agree, there are some numbers that is rationals can't represent
(like pi, phi, e) but these rounding problems also exist in floating
points, and rational numbers wouldn't be so easily fooled by something
like 1 / 3 * 3, and 1/10 (computer) is exactly 0.1 (human). The first
problem with rational is that to get an infinite precision rational,
the language would have to have an infinite length integers, which
Python have given us. The second problem with rationals is to keep
rationals in its most simple, trivial form. This can be solved with a
good GCD algorithm, which can also be a nice addition to Python's math
library.
Yes, I'm aware of the PEP and actually have been trying for some time
to reopen the PEP.
The reason that PEP is rejected is because Decimal is accepted, which
I think is a completely absurd reason as Decimal doesn't actually
solve the rounding problems and equality comparison problem. Some
people have also pointed out that Decimal IS Inexact, while a rational
number is always exact except if you have an operation with a (binary
or decimal) floating point involved (this can be easilty resolved by
making fraction recessive, i.e. an operation that receive a fraction
and a float should return a float).
It's already in the trunk! Python will have a rational type (called
Fraction) in Python 2.6 and Python 3.0, thanks largely to the work of
Jeffrey Yaskin.
Mark
Forgot to give the link:
http://docs.python.org/dev/library/fractions.html
Mark
Really? I didn't know that (last time I checked they frowned at me for
asking that). It's going to be be great if Python supports fractional
number. Although rationals have its limitations too, it is a much
better choice compared to floats/Decimals for most cases. One thing
though, the time I've spent on creating a rational class myself would
be 'somewhat' wasted, although I don't really mind that since it was
fun in any case.
Have you looked at the gmpy madule? That's what I
use whenever this comes up. Works very nice to
eliminate the issues that prevent a float olution
for the problems I'm working on.
And some irrationals can be represented by infite
sequences of rationals that, coupled with gmpy's
unlimited precision floats, allows any number of
accurate decimal places to be calculated.
If you would like to see an example, check out
Maybe that's true for your use cases, but it's not true for most cases
in general.
Rationals are pretty useless for almost any extended calculations,
since the denominator tends to grow in size till it's practically
unusbale, which means you have to periodically do non-exact reductions
to keep things running, and if you do that you might as well be using
floating point.
Rationals have their occasional special purpose uses, but for most
cases they're at best marginally better then floats and more often
incomparably worse.
Carl Banks
This only happens if you're chaining many divisions by non-constants,
which in the typical business calculation does not happen. Those
calculations divide by 10 a lot, and sometimes by 12 or 365, but they
rarely divide a calculated quantity by another calculated quantity,
especially to more than one level. I.e. they might compute the ratio
of widgets sold to widgets repaired, but they wouldn't then divide
that ratio by some other weird number.
I did in fact implement rational arithmetic in a business app a long
time ago, because management wanted it. I had the same concerns that
you express, but they just weren't a problem in practice.
OK, that might have been an overstatement, but as I see it, it is
safer to handle something in a Fraction compared to floats (which is
why I uses fractions whenever possible in non-computer maths).
> Rationals are pretty useless for almost any extended calculations,
> since the denominator tends to grow in size till it's practically
> unusbale, which means you have to periodically do non-exact reductions
> to keep things running, and if you do that you might as well be using
> floating point.
Rationals aren't that good if the same piece of variable is to be
calculated again and again because of its growth, but there are a lot
of cases where the data would only require five or six or so
operations done on it (and there are thousands or millions of such
datas), rationals is the perfect choice for those situations because
it is easier to use thanks to the comparison safety. Or in the
situations where speed isn't as important and accuracy is required,
Fraction may be faster than decimal and more accurate at the same time
(someone need to test that though).
What do you mean by "practically unusable?" I heard similar arguments
made against big integers at one point ("Primitive types are usually big
enough, why risk performance?") but I fell in love with them when I
first saw them in Smalltalk, and I'm glad Python supports them natively.
He's not joking at all.
> Your example is exact to 28 digits. Your attempted
> trick is to use a number that never ends (1/3=0.3333...).
It does end in base 3, 6, 9, 12, etc.
You have to remember that base-ten wasn't chosen because it has
mathematical advantages over other bases, but merely because people
counted on their fingers. In light of this fact, why is one-fifth
more deserving of an exact representation than one-third is?
So big that a fraction takes 10 minutes to reduce to simplest form and/
or your hard disk starts thrashing.
It can easily happen with seemingly innocuous calculations.
> I heard similar arguments
> made against big integers at one point ("Primitive types are usually big
> enough, why risk performance?") but I fell in love with them when I
> first saw them in Smalltalk, and I'm glad Python supports them natively.
It's not the same argument, though.
Repeated calculations don't make bignums too large to manage unless
they're growing it exponentially.
With rationals, the accumulating calculations usually makes the
denominator grow out of control (unless there's some mitigating
factor, like in Paul Rubin's example where there were only a ever few
denominators.)
Carl Banks
OK, thanks for explaining. It doesn't seem to me intuitively like
something that would be a problem, but I'm willing to take your word for it.
Out of curiosity, just how big is that?
I ask because I routinely use extremely big
ints and rationals and haven't seen that.
And I'm talking about numbers with, say,
50000 decimal digits up to numbers with
over a billion bits.
>
> It can easily happen with seemingly innocuous calculations.
Where I've had problems is not the size
of the numbers in the repeated calculations
but the number of calculations, say, millions.
>
> > I heard similar arguments
> > made against big integers at one point ("Primitive types are usually big
> > enough, why risk performance?") but I fell in love with them when I
> > first saw them in Smalltalk, and I'm glad Python supports them natively.
>
> It's not the same argument, though.
>
> Repeated calculations don't make bignums too large to manage unless
> they're growing it exponentially.
My work grows exponentially.
>
> With rationals, the accumulating calculations usually makes the
> denominator grow out of control (unless there's some mitigating
> factor, like in Paul Rubin's example where there were only a ever few
> denominators.)
I don't see any problem there either.
It's entirely possible _I_ won't be able
to use the new Fraction data type. My work
has already left the built-in Python big
ints in the dust in favor of gmpy, so I
have no expectation that the new Fraction
type will be of any use to me.
>
> Carl Banks
Consider what happens when you add two fractions:
1/2 + 1/5
To do that, you have to take the LCD of the denomintor, in this case
10, so you get
5/10 + 2/10 = 7/10
Now imagine that you're adding a lot of different numbers with a lot
of different bases. That LCD's going to be pretty big. To make
matters worse, imagine taking this number as the divisor in a later
calculation: a new denominator would appear (7). So you get
denominators that you didn't even input, which can make LCDs go
higher.
Any iteration with repeated divisions and additions can thus run the
denominators up. This sort of calculation is pretty common (examples:
compound interest, numerical integration).
The thing I don't like about rationals is that they give a false sense
of security. They are performing reasonably, and then you make a
slight change or some circumstance changes slightly and suddenly they
blow up.
Carl Banks
> Consider what happens when you add two fractions:
>
> 1/2 + 1/5
>
> To do that, you have to take the LCD of the denomintor, in this case 10,
> so you get
>
> 5/10 + 2/10 = 7/10
>
> Now imagine that you're adding a lot of different numbers with a lot of
> different bases. That LCD's going to be pretty big.
It *will* be pretty big, or it *could be* pretty big?
The worst case comes from something like this:
a/2 + b/3 + c/4 + d/5 + e/6 + ...
where the denominator could be as high as n! (for n = the number of
fractions you're adding). Since n! gets large quickly, you don't want
that.
But a less-naive implementation shouldn't be that bad: the lowest common
denominator of a/2 + c/4 is 4, not 8. Still, multiplying all the
relatively-prime denominators will still get large quickly, just not
quite as quickly as n!.
Which is where a good fraction implementation should allow you to specify
the largest denominator you wish to see. After all, the difference
between:
975328755018/6827301285133
and
1/7
is less than 2e-13, or a relative error of approximately 0.0000000001%.
If you care about a difference of that magnitude, you're probably already
using numpy.
An interesting question would be, how large a denominator would you need
to beat the precision of floats? My back-of-the-envelope calculation
suggests that limiting your denominator to 4503599627370496 is enough to
give you a precision as good as floats:
# on my PC, the machine accuracy is 2.2204460492503131e-16
# this is the smallest float which, when added to 1.0,
# doesn't give 1.0
>>> eps = 2.2204460492503131e-16
>>> 1/eps
4503599627370496.0
The advantage is that while 1000.0+eps gives 1000.0 (which it shouldn't),
(1000*4503599627370496 + 1)/4503599627370496 is a perfectly reasonable
fraction to work with. Ugly to the human eye perhaps, but if your PC is
grinding to a halt on such a fraction, maybe you should take this as a
sign that 64K *isn't* enough memory for everybody.
*wink*
[snip]
> The thing I don't like about rationals is that they give a false sense
> of security. They are performing reasonably, and then you make a slight
> change or some circumstance changes slightly and suddenly they blow up.
Or, to put it another way, rationals and floats both are dangerous, but
in different ways. The performance of rationals can fall drastically, and
floating point calculations can suddenly become inaccurate. You make your
choice and take your chances.
--
Steven
Wrong. Addition and subtraction would only grow the denominator up to
a certain limit
> > The thing I don't like about rationals is that they give a false sense
> > of security. They are performing reasonably, and then you make a slight
> > change or some circumstance changes slightly and suddenly they blow up.
>
> Or, to put it another way, rationals and floats both are dangerous, but
> in different ways. The performance of rationals can fall drastically, and
> floating point calculations can suddenly become inaccurate. You make your
> choice and take your chances.
When I mean safety, fraction is safe in calculation integrity safety,
it is always safe to do calculations in fraction (although at one time
the huge calculation might stall the system, the calculation will
always be correct all the time). But actually there is a way to ensure
performance safety in Fraction class, fraction might grow
uncontrollably only if the data is multiplied or divided. If you're
just doing addition and subtraction, the denominator growth is limited
to a certain range given a limited range of data.
Surely this assumes that the denominators are being reduced after each
operation, which would certainly add to the time the operations take.
The simplest and fasted implementation of rational addition and
subtraction uses a common denominator which is the product of both. To
avoid denominator growth at each operation you have to start extracting
common factors, which is bound to slow you down.
So, presuming your "certain limit" is the product of all mutually prime
denominators that have been involved, you are slowing things down to
maintain that limitation.
regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/
I said repeated additions and divisions.
Anyways, addition and subtraction can increase the denominator a lot
if for some reason you are inputing numbers with many different
denominators.
Carl Banks
Repeated Addition and subtraction can't make fractions grow
infinitely, only multiplication and division could.
> Anyways, addition and subtraction can increase the denominator a lot
> if for some reason you are inputing numbers with many different
> denominators.
Up to a certain limit. After you reached the limit, the fraction would
always be simplifyable.
If the input numerator and denominator have a defined limit, repeated
addition and subtraction to another fraction will also have a defined
limit.
(n1/d1) + (n2/d2) = ((n1*d2) + (n2*d1)) / (d1*d2)
If d1 and d2 are mutually prime (have no common factors) then it is
impossible to reduce the resulting fraction further in the general case
(where n1 = n2 = 1, for example).
>> Anyways, addition and subtraction can increase the denominator a lot
>> if for some reason you are inputing numbers with many different
>> denominators.
>
> Up to a certain limit. After you reached the limit, the fraction would
> always be simplifyable.
>
Where does this magical "limit" appear from?
> If the input numerator and denominator have a defined limit, repeated
> addition and subtraction to another fraction will also have a defined
> limit.
Well I suppose is you limit the input denominators to n then you have a
guarantee that the output denominators won't exceed n!, but that seems
like a pretty poor guarantee to me.
Am I wrong here? You seem to be putting out unsupportable assertions.
Please justify them or stop making them.
Well, I do a test on my own fraction class. I found out that if we set
a limit to the numerators and denominators, the resulting output
fraction would have limit too. I can't grow my fraction any more than
this limit no matter how many iteration I do on them. I do the test is
by something like this (I don't have the source code with me right
now, it's quite long if it includes the fraction class, but I think
you could use any fraction class that automatically simplify itself,
might post the real code some time later):
while True:
a = randomly do (a + b) or (a - b)
b = random fraction between [0-100]/[0-100]
print a
And this limit is much lower than n!. I think it's sum(primes(n)), but
I've got no proof for this one yet.
It's the least common multiple of the integers 1 through n, or
equivalently the product over all primes p <= n of the highest power
of p not exceeding n. So for n = 100, it's:
64 * 81 * 25 * 49 * 11 * 13 * 17 * ... rest of primes up to 100.
For general n, this number is of roughly the same order of magnitude
as e**n.
See
http://www.research.att.com/~njas/sequences/A003418
for more.
Mark
Ah, yes, I meant product(primes(n)), please forgive my honest mistake
which is partially caused by me not supposed to still be awake at this
time of the day. And thanks for Mark for noticing the mistake, and
here is the code I used:
import fraction
import random
frac = fraction.frac
ops = (frac.__add__, frac.__sub__)
a = frac(random.randrange(1, 10), random.randrange(1, 10))
b = frac(random.randrange(1, 10), random.randrange(1, 10))
while True:
o = ops[random.randrange(0, 2)]
a = o(a, b)
b = frac(random.randrange(1, 10), random.randrange(1, 10))
print a
I decided to keep the num/den limit low (10) because higher values
might obscure the fact that it do have limits. And through further
observations, I think it is sufficient if the limit is imposed in the
denominator only (numerator can have any values it wanted to,
denominator growth is determined only by the limit of denominator
growth).
I think I'll also post the code for the fraction class I used, if you
have other fraction class that can automatically simplify, you could
use that instead as this class suffers from a naive GCD
implementation:
==== fraction.py ====
from __future__ import division
def GCD(a, b):
if b == 0: return a
return GCD(b, a % b)
class frac:
''' Fraction Class
A fraction class.
Attributes:
num -> the numerator of a fraction
den -> the denominator of a fraction
Methods:
add(a, b) -> add fraction a to fraction b and return a
new fraction
sub(a, b) -> subtract fraction b from fraction a and
return a new fraction
mul(a, b) -> multiply fraction a with fraction b and
return a new fraction
div(a, b) -> divides fraction b from fraction a and
return a new fraction
invert(a) -> invert the fraction (switch the numerator
and denominator)
neg(a) -> negates the fraction (negates numerator)
powr(a, b) -> raise fraction a to the power of b
simplify(a, b) -> simplify fraction to its canonical
representation
__init__(a, b) -> creates a new fraction
__str__(a, b) -> returns a string representation. Mixed
fraction if possible
__repr__(a, b) -> returns a string representation. Always
return vulgar fraction
Operators:
Conversion to fractions will be done automatically whenever
possible, in-place
operation is fully supported. Both regular and reflected
operation is supported.
a + b -> Calls frac.add(a, b)
a - b -> Calls frac.sub(a, b)
a * b -> Calls frac.mul(a, b)
a / b -> Calls frac.div(a, b)
a // b -> Floors the resulting fraction from frac.div(a, b)
-a -> Negates a fraction
+a -> Returns a copy of the fraction
~a -> Return the reciprocal of a
Comparisons:
Implemented through __cmp__(a, b), no rich comparison.
a == b -> a equals b
a != b -> a not equal b
a > b -> a greater than b
a < b -> a less than b
a >= b -> a greater than or equal to b
a <= b -> a less than or equal to b
Casting:
__complex__ -> Converts the fraction to floats and return the
result as complex number
__int__ -> Returns the whole part of the fraction in
Integer
__long__ -> Returns the whole part of the fraction in Long
__float__ -> Returns the value of the fractino in Float
Exceptions:
ZeroDenominatorError
-> A fraction cannot have zero as its denominator
Bugs:
- At the meantime, the fraction class doesn't mix well if used
together with floating type numbers. Inline operators and
initializers implicitly assumed that numbers are either
integers or
fraction. So if there are operations involving floating
point or
you initialized a fraction with a floating point number, the
result
would be something like a "floating point fraction".
'''
def __init__(self, a = 0, b = 1):
dev = GCD(a, b)
if b > 0:
self.num = a // dev
elif b < 0:
self.num = -a // dev
else:
raise frac.ZeroDenominatorError
self.den = abs(b) // dev
def simplify(self):
dev = GCD(self.num, self.den)
self.num //= dev
self.den //= dev
return self
def add(a, b):
return frac(a.num * b.den + b.num * a.den, a.den * b.den)
def sub(a, b):
return frac(a.num * b.den - b.num * a.den, a.den * b.den)
def mul(a, b):
return frac(a.num * b.num, a.den * b.den)
def div(a, b):
return frac(a.num * b.den, a.den * b.num)
def invert(a):
return frac(a.den, a.num)
def neg(a):
return frac(-a.num, a.den)
def powr(x, y):
return frac(x.num ** y, x.den ** y)
def __add__(self, other):
return self.add(other)
def __radd__(self, other):
return other.add(self)
def __sub__(self, other):
return self.sub(other)
def __rsub__(self, other):
return other.sub(self)
def __mul__(self, other):
return self.mul(other)
def __rmul__(self, other):
return other.mul(self)
def __div__(self, other):
return self.div(other)
def __rdiv__(self, other):
return other.div(self)
def __truediv__(self, other):
return self.div(other)
def __rtruediv__(self, other):
return other.div(self)
def __floordiv__(self, other):
ret = self.div(other)
return ret.num // ret.den
def __rfloordiv__(self, other):
ret = other.div(self)
return ret.num // ret.den
def __iadd__(a, b):
a.num, a.den = a.num * b.den + b.num * a.den, a.den * b.den
return a.simplify()
def __isub__(a, b):
a.num, a.den = a.num * b.den - b.num * a.den, a.den * b.den
return a.simplify()
def __imul__(a, b):
a.num, a.den = a.num * b.num, a.den * b.den
return a.simplify()
def __idiv__(a, b):
a.num, a.den = a.num * b.den, a.den * b.num
return a.simplify()
def __itruediv__(a, b):
a.num, a.den = a.num * b.den, a.den * b.num
return a.simplify()
def __ifloordiv__(self, other):
self /= other
return self.num // self.den
def __str__(self):
''' String Function
Convert the function to its human-friendly representation.
Tries
to convert smartly.
'''
ret = ''
if self.num < 0: ret = '-'
w, n, d = abs(self.num // self.den), abs(self.num) % self.den,
self.den
if w != 0:
if n != 0 and d != 1:
ret += '%s %s/%s' % (w, n, d)
else:
ret += str(w)
else:
if n != 0 and d != 1:
ret += '%s/%s' % (n, d)
else:
ret = '0'
return ret
def __repr__(self):
return str(self.num) + '/' + str(self.den)
def __complex__(self):
return complex(float(self))
def __int__(self):
return int(self.num / self.den)
def __long__(self):
return long(self.num / self.den)
def __float__(self):
return self.num / self.den
def __neg__(self):
return frac.neg(self)
def __pos__(self):
return frac(self.num, self.den)
def __abs__(self):
return frac(abs(self.num), self.den)
def __invert__(self):
return frac.invert(self)
def __pow__(x, y):
return powr(x, y)
def __coerce__(self, other):
try:
self.num, self.den
except AttributeError:
self = frac(self)
try:
other.num, other.den
except AttributeError:
other = frac(other)
return self, other
def __cmp__(self, other):
a = self.num * other.den
b = other.num * self.den
return cmp(a, b)
class ZeroDenominatorError(Exception):
''' Exception for having a zero as the denominator in a
Fraction Class
'''
def __init__(self):
pass
def __str__(self):
return "A fraction cannot have zero as denominator
(frac.den != 0)"
Out of curiosity, of what use is denominator limits?
The problems where I've had to use rationals have
never afforded me such luxury, so I don't see what
your point is.
In Donald Knuth's The Art of Computer Programming, he described
floating slash arithmetic where the total number of bits by the
numerator and denominator was bounded. IIRC, a use case was matrix
inversion.
casevh
*jaw drops*
Please stop trying to "help" convince people that rational classes are
safe to use. That's the sort of "help" that we don't need.
For the record, it is a perfectly good strategy to *artificially* limit
the denominator of fractions to some maximum value. (That's more or less
the equivalent of setting your floating point values to a maximum number
of decimal places.) But without that artificial limit, repeated addition
of fractions risks having the denominator increase without limit.
--
Steven
> Out of curiosity, of what use is denominator limits?
>
> The problems where I've had to use rationals have never afforded me such
> luxury, so I don't see what your point is.
It ensures that your fraction's denominator doesn't grow indefinitely, at
the cost of some precision. In principle, fraction denominators can grow
exponentially. In practice, probably less quickly, but still quickly
enough that people on this list have reported that adding two fractions
lead to millions of digits in each denominator and massive paging as
their computer struggled to perform the addition.
The beauty of fractions is that they give you infinite precision. The
danger of fractions is that it takes a lot of memory to store infinitely
precise numbers :)
Frankly, I think that for most real-world data, it's unlikely to be a
problem, but Guido's experiences with ABC were the opposite. But then we
don't know how naive the ABC fraction libraries were. For all I know they
did this:
1/2 + 1/2 = 4/4
4/4 - 1/2 = 4/8
4/8 + 1/2 = 16/16
etc.
--
Steven
> I decided to keep the num/den limit low (10) because higher values might
> obscure the fact that it do have limits.
You do realise that by putting limits on the denominator, you guarantee
that the sum of the fractions also has a limit on the denominator? In
other words, your "test" is useless.
With denominators limited to 1 through 9 inclusive, the sum will have a
denominator of 2*3*5*7 = 210. But that limit is a product (literally and
figuratively) of your artificial limit on the denominator. Add a fraction
with denominator 11, and the sum now has a denominator of 2310; add
another fraction n/13 and the sum goes to m/30030; and so on.
--
Steven
Th limit will be 2*2*2*3*3*5*7. As MD said, "equivalently
the product over all primes p <= n of the highest power
of p not exceeding n".
Ok, but I've never seen that happen with the rationals
of the gmpy module. I'm getting the feeling that this
fear of rationals is overrated.
But maybe it's because I know what I'm doing.
Naw, that can't be it.
>
> The beauty of fractions is that they give you infinite precision. The
> danger of fractions is that it takes a lot of memory to store infinitely
> precise numbers :)
>
> Frankly, I think that for most real-world data, it's unlikely to be a
> problem,
My guess is that you're right.
> but Guido's experiences with ABC were the opposite. But then we
> don't know how naive the ABC fraction libraries were. For all I know they
> did this:
>
> 1/2 + 1/2 = 4/4
> 4/4 - 1/2 = 4/8
> 4/8 + 1/2 = 16/16
> etc.
Perhaps Guido should have an occasional peek
at the monster he's created. The gmpy library
always reduces to lowest denominator, so the
above couldn't happen.
>
> --
> Steven
In calculations dealing only with selected units of measure: dollars
and cents, pounds, ounces and tons, teaspoons, gallons, beer bottles
28 to a case, then the denominators would settle out pretty quickly.
In general mathematics, not.
I think that might be the point.
Mel.
Ok.
>
> In general mathematics, not.
But that doesn't mean they become less manageable than
other unlimited precision usages. Did you see my example
of the polynomial finder using Newton's Forward Differences
Method? The denominator's certainly don't settle out, neither
do they become unmanageable. And that's general mathematics.
>
> I think that might be the point.
If the point was as SDA suggested, where things like 16/16
are possible, I see that point. As gmpy demonstrates thouigh,
such concerns are moot as that doesn't happen. There's no
reason to suppose a Python native rational type would be
implemented stupidly, is there?
>
> Mel.
> But that doesn't mean they become less manageable than
> other unlimited precision usages. Did you see my example
> of the polynomial finder using Newton's Forward Differences
> Method? The denominator's certainly don't settle out, neither
> do they become unmanageable. And that's general mathematics.
>
Since you are expecting to work with unlimited (or at least, very
high) precision, then the behavior of rationals is not a surprise. But
a naive user may be surprised when the running time for a calculation
varies greatly based on the values of the numbers. In contrast, the
running time for standard binary floating point operations are fairly
constant.
>
> If the point was as SDA suggested, where things like 16/16
> are possible, I see that point. As gmpy demonstrates thouigh,
> such concerns are moot as that doesn't happen. There's no
> reason to suppose a Python native rational type would be
> implemented stupidly, is there?
In the current version of GMP, the running time for the calculation of
the greatest common divisor is O(n^2). If you include reduction to
lowest terms, the running time for a rational add is now O(n^2)
instead of O(n) for a high-precision floating point addition or O(1)
for a standard floating point addition. If you need an exact rational
answer, then the change in running time is fine. But you can't just
use rationals and expect a constant running time.
There are trade-offs between IEEE-754 binary, Decimal, and Rational
arithmetic. They all have there appropriate problem domains.
And sometimes you just need unlimited precision, radix-6, fixed-point
arithmetic....
casevh
Well, that applies equally to Python long ints
which can be intractable compared to gmpy's
long ints.
> In contrast, the
> running time for standard binary floating point operations are fairly
> constant.
>
>
>
> > If the point was as SDA suggested, where things like 16/16
> > are possible, I see that point. As gmpy demonstrates thouigh,
> > such concerns are moot as that doesn't happen. There's no
> > reason to suppose a Python native rational type would be
> > implemented stupidly, is there?
>
> In the current version of GMP, the running time for the calculation of
> the greatest common divisor is O(n^2). If you include reduction to
> lowest terms, the running time for a rational add is now O(n^2)
> instead of O(n) for a high-precision floating point addition or O(1)
> for a standard floating point addition. If you need an exact rational
> answer, then the change in running time is fine. But you can't just
> use rationals and expect a constant running time.
Well, _I_ don't expect constant run time, but I usually
need tractable run-time. And since Python's built-ins
can't always cut it compared to gmpy, I suppose a fraction
type probably couldn't hold a candle to gmpy either.
So even if implemented correctly to prevent runaway
denominators, the fraction type would likely
end up being as worthless to me as the current long
ints are.
>
> There are trade-offs between IEEE-754 binary, Decimal, and Rational
> arithmetic. They all have there appropriate problem domains.
Of course. And design decisions shouldn't be based
on bad algorithms, but those that are appropriate
to the problem domain.
What part of "repeated additions and divisions" don't you understand?
Carl Banks
No, that's a specific algorithm. That some random algorithm doesn't
blow up the denominators to the point of disk thrashing doesn't mean
they won't generally.
Try doing numerical integration sometime with rationals, and tell me
how that works out. Try calculating compound interest and storing
results for 1000 customers every month, and compare the size of your
database before and after.
Carl Banks
Usually you would round to the nearest penny before storing in the
database.
I throw it out there as a hypothetical, not as a real world example.
"This is why we don't (usually) use rationals for accounting."
Carl Banks
http://www.egenix.com/products/python/mxExperimental/mxNumber/
It provides fast rational operations based on the GNU MP
library.
It is well possible to limit the denominator before storing it
in a database or other external resource using Farey neighbors:
http://en.wikipedia.org/wiki/Farey_sequence#Farey_neighbours
mxNumber implements an algorithm for this (not the most efficient
one, but it works nicely).
--
Marc-Andre Lemburg
eGenix.com
Professional Python Services directly from the Source (#1, Feb 25 2008)
>>> Python/Zope Consulting and Support ... http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ... http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/
________________________________________________________________________
:::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,MacOSX for free ! ::::
eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48
D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
Registered at Amtsgericht Duesseldorf: HRB 46611
There are cases where the law requires a higher precision or where the
rounding has to be a floor or...
Some things make no sense and when dealing with money things make even less
sense to either protect the customer or to grant the State getting its
share of the transaction.
Here in Brasil, for example, gas stations have to display the price with 3
decimal digits and round the end result down (IIRC). A truck filling 117
liters at 1.239 reais per liter starts making a mess... If the owner wants
to track "losses" due to rounding or if he wants to make his inventory of
fuel accurately, he won't be able to save just what he billed the customer
otherwise things won't match by the end of the month.
Nobody said rationals were the appropriate solution
to _every_ problem, just as floats and integers aren't
the appropriate solution to _every_ problem.
Your argument is that I should be forced to use
an inappropriate type when rationals _are_
the appropriate solution.
I have never used the Decimal type, but I'm not
calling for it's removal because I know there are
cases where it's useful. If a rational type were
added, no one would force you to use it for
numerical integration.
>
> Carl Banks
> On 24 Feb 2008 23:04:14 -0800, Paul Rubin <http://phr...@NOSPAM.invalid>
> declaimed the following in comp.lang.python:
>
>
>> Usually you would round to the nearest penny before storing in the
>> database.
>
> Tell that to the payroll processing at Lockheed...My paycheck
> tends to vary from week to week as the database apparently carries
> amount to at least 0.001 resolution, only rounding when distributing
> among various taxes for the paycheck itself. Tedious data entry in
> Quicken as I have to keep tweaking various tax entries by +/- a penny
> each week.
"Worst practice" in action *wink*
I predict they're using some funky in-house accounting software they've
paid millions to a consultancy firm (SAP?) for over the decades, written
by some guys who knows lots of Cobol but no accounting, and the internal
data type is a float.
[snip]
> Oh... And M$ -- the currency type in VB is four decimal places.
Accounting standards do vary according to context: e.g. I see that
offical Australian government reporting standards for banks is to report
in millions of dollars rounded to one decimal place. Accountants can
calculate things more or less any way they like, so long as they tell
you. I found one really dodgy example:
"The MFS Water Fund ARSN 123 123 642 (‘the Fund’) is a registered managed
investment scheme. ... MFS Aqua may calculate the Issue Price to the
number of decimal places it determines."
Sounds like another place using native floats. But it's all above board,
because they tell you they'll use an arbitrary number of decimal places,
all the better to confuse the auditors my dear.
--
Steven
But since accountants (usually) round to the nearest cent, accounting is
a *good* use-case for rationals. Decimal might be better, but floats are
worst.
I wonder why you were doing numerical integration with rationals in the
first place? Are you one of those ABC users (like Guido) who have learnt
to fear rationals because ABC didn't have floats?
--
Steven
That's not necessarily true in general: finance libraries usually try
to always do calculations at the best possible precision and then only
apply rounding at the very end of a calculation. Most of the time a float
is the best data type for this.
Accounting uses a somewhat different approach and one which various
between the different accounting standards and use cases. The decimal
type is usually better suited for this, since it supports various
ways of doing rounding.
Rationals are not always the best alternative, but they do help
in cases where you need to guarantee that the sum of all parts
is equal to the whole for all values. Combined with interval
arithmetic they go a long way towards more accurate calculations.
I was answering your claim that rationals are appropriate for general
mathematical uses.
> Your argument is that I should be forced to use
> an inappropriate type when rationals _are_
> the appropriate solution.
I don't know where you got that idea.
My argument is that rationals aren't suitable for ordinary uses
because they have poor performance and can easily blow up in your
face, trash your disk, and crash your program (your whole system if
you're on Windows).
In other words, 3/4 in Python rightly yields a float and not a
rational.
Carl Banks
> In other words, 3/4 in Python rightly yields a float
Unless you're in the camp that believes 3/4 should yield the
integer 0. ;)
> and not a rational.
--
Grant Edwards grante Yow! Zippy's brain cells
at are straining to bridge
visi.com synapses ...
I'm in the camp that believes that 3/4 does indeed yield the integer 0,
but should be spelled 3//4 when that is the intention.
Cheers,
Cliff
No, it is a real limit. This is what I'm talking about. If the input
data has a limit, the output data has a real limit, not a user-defined-
limit (FOR ADDITION AND SUBTRACTION). If the input data's denominator
is unbounded, the output fraction's denominator is also unbounded
I very agree with this statement. Fractionals do have its weakness,
and so do Decimal and Hardware Floating Point. And they have their own
usage, their own scenarios where they're appropriate. If you needed
full-speed calculation, it is clear that floating point wins all over
the place, OTOH, if you need to manage your precision carefully
Fractional and Decimal both have their own plus and mins
What part of additions and subtractions don't you understand? I'm
invalidating half of your statement, the division part, but validating
another half, the additions part and adding some statements on my own.
>
> Try doing numerical integration sometime with rationals, and tell me
> how that works out. Try calculating compound interest and storing
> results for 1000 customers every month, and compare the size of your
> database before and after.
>
Since when have I said that fractional is appropriate for calculating
compound interests. Fractionals works best in scenarios where the
calculations are mostly addition and subtraction, not percentage
division and multiplications like in compounds.
And it should, as floats have native CPU support, 3/4 (with __future__
import) should yields 0.75. Fractional is safe for many usage
scenario, but obviously it is not appropriate for all cases, just like
floats and decimals. I think this mailing list already have enough
absolutist, who can go to either side of the camp but doesn't want to
be in the middle.
In real world, money is probably best described by float or Decimals,
as non-computer money calculations are used to do rounding at 1 cents.
But the interest rate is probably better described by rationals.
In trigonometry, _perhaps_ the world would be better if trigonometric
functions returns rational. Perhaps it is better to use rational for
pi (ratio of diameter and circumferrence) and phi (golden ratio). But
I think angles is better described as floats nevertheless.
> J Cliff Dyer:
> I'm in the camp that believes that 3/4 does indeed yield the integer 0,
> but should be spelled 3//4 when that is the intention.
That's creepy for people that are new to programming and doesn't know
how CPUs work and are used to general mathematics. That means most
people. As programming language are now more accessible to regular
people without specialized Computer Science degree, it is a just
natural trend that computer arithmetic must be done in an expectable
manner as seen by those general population not by people who holds a
CS degree.
If you have a lot to say, say it together and take the time to slow
down, re-read it and not just fly it out, line by line, by line, by
line...
To answer only the following:
> That's creepy for people that are new to programming and doesn't know
> how CPUs work and are used to general mathematics. That means most
> people. As programming language are now more accessible to regular
> people without specialized Computer Science degree, it is a just
> natural trend that computer arithmetic must be done in an expectable
> manner as seen by those general population not by people who holds a
> CS degree.
Couldn't disagree with you more, the fact they don't specialise in
Computer Science shouldn't be a reason to follow their "expected
outcomes", they should be informed of the standard CS approach. I'm
all for punishing people for making "well I thought it would always do
the following..." thought process. The quicker they learn certain
methods and expectations are wrong the quicker they get used to the
proper thought patterns.
Of course. That's why I think you ought to spell it 3//4. Nobody gets
confused when a strange operator that they've never seen before does
something unusual. Average Jo off the street looks at python code and
sees 3/4, and immediately thinks "aha! .75!" Show the same person 3//4,
and she'll think, "A double slash? I'd better check the
documentation--or better yet, play with it a little in the interactive
interpreter."
Why do we care what A. Jo thinks? I would hope that A. Programmer Jo
would see "int {OP} int" and assume int result. A. Jo isn't going to be
debugging anything.
If 3/4 ever returned 0.75 in any language I would drop that language.
--
D'Arcy J.M. Cain <da...@druid.net> | Democracy is three wolves
http://www.druid.net/darcy/ | and a sheep voting on
+1 416 425 1212 (DoD#0082) (eNTP) | what's for dinner.
>> J Cliff Dyer:
>> I'm in the camp that believes that 3/4 does indeed yield the integer 0,
>> but should be spelled 3//4 when that is the intention.
>
> That's creepy for people that are new to programming and doesn't know
> how CPUs work and are used to general mathematics. That means most
> people. As programming language are now more accessible to regular
> people without specialized Computer Science degree, it is a just
> natural trend that computer arithmetic must be done in an expectable
> manner as seen by those general population not by people who holds a
> CS degree.
So why is it creepy then!? ``3 // 4`` is for the people knowing about
integer division and ``3 / 4`` gives the expected result for those who
don't. Those who don't know ``//`` can write ``int(3 / 4)`` to get the
same effect.
Ciao,
Marc 'BlackJack' Rintsch
> If 3/4 ever returned 0.75 in any language I would drop that language.
Then prepare to drop Python from version 3 on:
Python 3.0a1 (py3k, Aug 31 2007, 21:20:42)
[GCC 4.1.2 (Ubuntu 4.1.2-0ubuntu4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 3 / 4
0.75
Ciao,
Marc 'BlackJack' Rintsch
There's no reason why int op int would imply an int result. It's only
a convention in some languages, and a bad one.
> A. Jo isn't going to be
> debugging anything.
>
> If 3/4 ever returned 0.75 in any language I would drop that language.
Have fun dropping Python, then, chief. Integer division with / is
already deprecated, can be disabled ever since Python 2.4, and will be
wholly removed in Python 3.0.
Carl Banks
The problem lies on which maths is the real maths? In real world, 3/4
is 0.75 is 0.75 and that's an unchangeable fact, so programming
languages that do other things is either wrong or have their reason to
do that. Python, C, and other programming languages that uses integer
division by default choose to do default integer division because CPUs
execute integer division faster than floating division, but it doesn't
change the fact that 3/4 is equal to 0.75 but is not equal to 0.
I think a CS should understand that the choice of default integer
division was actually a workaround for the expensive operation, not
because 3/4 actually equals 0. As the more educated person, they
should still expect 3/4 to be 0.75 but could understand why if the
language they're using gives 0. Commoners are the less educated,
languages should appeal to as much people as it could, and giving 3/4
== 0 is the best way to confuse some people right away, instead giving
3/4 == 0.75 would just make the more educated CSs search for the
"regular" division operator.
It is better to think this way:
CSs supposed brain thought:
try:
print 3 / 4
except IntegerResult:
print 'integer division workaround'
if wants[floatdivision]: print 'searching for float division
operator'
elif wants[integerdivision]: print 'that was already correct'
Commoner's supposed brain thought:
try:
print 3 / 4
than this way:
CSs supposed brain thought:
try:
print 3 / 4
except FPointResult:
print 'This language is a jerk'
Commoner's supposed brain thought:
try:
print 3 / 4
The first set of brain thought appeal to everyone, everyone is happy
with the result. The second set of brain thought kills a CS guy and
gives unhandled error to a commoner. DO you still think that default
integer division is better?
I have not been following Python development that closely lately so I
was not aware of that. I guess I won't be going to Python 3 then. It's
great that Python wants to attract young, new programmers. Too bad
about us old farts I guess.
How soon before 2.x is completely deprecated and I have to become a
Walmart greeter?
Which real world is that? In my real world 3/4 is 0 with a remainder
of 3. What happens to that 3 depends on the context. When I worked
with a youth soccer group I was pretty sure that I would be disciplined
if I carved up a seven year old player so that I could put 0.75 of a
child on a team.
Anyway, I'm sure that all these arguments have been made and it is
pointless to argue about it now. It sounds like the decision has been
made.
Don't worry, Python would still have integer division (// - double
slash), if you still prefer integer division.
> Lie <Lie.1...@gmail.com> wrote:
> > The problem lies on which maths is the real maths? In real world, 3/4
> > is 0.75 is 0.75 and that's an unchangeable fact, so programming
>
> Which real world is that? In my real world 3/4 is 0 with a remainder
> of 3. What happens to that 3 depends on the context. When I worked
> with a youth soccer group I was pretty sure that I would be disciplined
> if I carved up a seven year old player so that I could put 0.75 of a
> child on a team.
lol, when counting how much players needed you wouldn't do a division,
you count from one to eleven (a.k.a addition by one a.k.a. increment),
excepting at the point where number of available players + current
count = 11 (+ spares) (or better, you subtract the number of players
to the number of players required). Save the float division for the
time, 90 minutes / number of players if you wanted each child to play
an equal amount of time.
Good joke, and a true argument, I don't wish to see anyone chopped off
because I said floating point division is better.
And of course A. Jo will love this:
Python 3.0a1+ (py3k:59330, Dec 4 2007, 18:44:39)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 3/5
0.59999999999999998
On a more general note, though, I believe that integer division is a
more important concept to CS than 'near exact' division. CS deals
mainly with discrete objects (and one might say exclusively, given the
digital nature of modern computers), and integers are the more natural
numerical objects to associate with discrete things. As with the
soccer example given by D'Arcy J.M. Cain, many objects can't be
chopped in halves or quarters (especially in CS) therefore float
division is no meaningless to them.
--
Arnaud
> I have not been following Python development that closely lately so
> I was not aware of that. I guess I won't be going to Python 3 then.
> It's great that Python wants to attract young, new programmers. Too
> bad about us old farts I guess.
Before deciding to drop Python 3 on the grounds of integer division, I
recommend that you at least read PEP 238
(http://www.python.org/dev/peps/pep-0238/) to see arguments *why* the
division was changed. Who knows, maybe they persuade you?
The "Motivation" section of the PEP makes a persuasive argument why
integer division works well in statically typed languages, but results
in many more gotchas in a dynamic language like Python.
yep, that's the point. The new division operator isn't that creepy
anymore by returning float instead of integer, kudos for whoever made
the change.
I have. They don't. I'm not impressed by the fact that the same
generation(s) that can't make change when the cash register is broken
are surprised by integer division. What can I say? I learned
arithmetic with paper and pencil and my head before I was allowed to use
a calculator. Integer division means integer result to me in a very
real sense. Arguing that integer division "should" return a float just
sounds like proof by vigorous assertion to me.
I suppose I will adapt but it really feels wrong.
Or Jo thinks // is a typo, and helpfully "fixes" it.