Re: Strange behavior of int()

2006-01-29 Thread Dan Bishop
Brian wrote:
> Hello,
>
> Can someone tell me what I am doing wrong in this code.
>
> If I create a file change.py with the following contents:
>
> def intTest(M, c):
> r = M
> for k in c:
> print 'int(r/k) = ', int(r/k), 'r =', r, 'k =', k, 'r/k
> =', r/k
> r = r - (k*int(r/k))
>
> intTest(2.30, [0.25, 0.10, 0.05, 0.01])
>
> and execute it, I get the output:
>
> int(r/k) =  9 r = 2.3 k = 0.25 r/k = 9.2
> int(r/k) =  0 r = 0.05 k = 0.1 r/k = 0.5
> int(r/k) =  0 r = 0.05 k = 0.05 r/k = 1.0
> int(r/k) =  4 r = 0.05 k = 0.01 r/k = 5.0

The important thing to remember is that, as far as your computer is
concerned, there are no such numbers as 2.30, 0.10, 0.05, or 0.01.
What's actually stored is the closest binary equivalents.  So your
intTest call is equivalent to

intTest(5179139571476070*2**(-51), [0.25, 7205759403792794*2**(-56),
7205759403792794*2**(-57), 5764607523034235*2**(-59)])

The first time through the loop, r = 5179139571476070*2**(-51) and k =
0.25, so r/k = 5179139571476070*2**(-49), which equals
9.199289457264239899814128875732421875.  This is as close
to the desired 9.2 as you can get.  So far, so good.

Now, it happens that the value k*int(r/k) = 2.25 is computed exactly.
Subtracting this from r gives

r = 5179139571476070*2**(-51) - 2.25
  = 5179139571476070*2**(-51) - 5066549580791808*2**(-51)
  = (5179139571476070 - 5066549580791808) * 2**(-51)
  = 112589990684262*2**(-51)
  = 7205759403792768*2**(-57)

My last computation here is to normalize the result to 53 significant
bits.  But note that the last 6 of those are zero, because the result
was shifted by 6 places.

0011001100110011001100110011001100110011001100110 * 2**(-51)
 /  /
/  /
   /  /
  /  /
 /  /
/  /
1100110011001100110011001100110011001100110011000 * 2**(-57)
   ^^
   padding

The loss of 6 significant bits means that this approximation of 0.05 is
slightly different from the direct approximation of 0.05.  The worst
part is, it's slightly *less*

7205759403792768*2**(-57) # result of the computation
7205759403792794*2**(-57) # 0.05 as stored in the computer

This causes r/k to be slightly *less* than one, which makes int(r/k)
zero and f's up the rest of your computations.

The way to fix this is to use numbers that can be stored exactly in
binary.  The simplest way is to represent monetary amounts as integer
numbers of cents

>>> intTest(230, [25, 10, 5, 1])
int(r/k) =  9 r = 230 k = 25 r/k = 9.2
int(r/k) =  0 r = 5 k = 10 r/k = 0.5
int(r/k) =  1 r = 5 k = 5 r/k = 1.0
int(r/k) =  0 r = 0 k = 1 r/k = 0.0

You might also consider using the decimal.Decimal class.  (Of course,
you'll still have roundoff problems if working with nondecimal amounts
like 1/3 or 1/7.  In that case, use a Rational class.)

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Strange behavior of int()

2006-01-29 Thread Rob E
> Why is int(r/k), where r = 0.5 and k = 0.5 = 0?  Shouldn't it be 1?
> And why is the last one = 4 and not 5?

I dont' know why the differences in your exact case.  However, please
realise that Regardless of the programming language good programming 
practice is to never rely on the int of a floating point division 
-- or even the int of a floating point constant to be exactly 
the integer value you expect it to be.  This is because both 
constant representations and math operations have rounding 
error.  Instead do less precise conversions by rounding.  For 
example:

a=b/c
if (a >= 0.0):
   d = int(a+0.5)
else:
   d = int(a-0.5)

If you don't do this sort of thing your programs generally 
are  senstivie to the details of foating point rounding -- 
which is generally dependent on processor, compilier and
in pythons case probably the runtime system.

Rob
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Strange behavior of int()

2006-01-26 Thread Dan Sommers
On 26 Jan 2006 18:42:34 -0800,
"Brian" <[EMAIL PROTECTED]> wrote:

> If I execute a similar command from the command line, it works just
> fine:
 int(0.05/0.05)
> 1

Try this:

>>> print 2.3 - int(2.3/.25)*.25
0.05
>>> 2.3 - int(2.3/.25)*.25
0.049822

Then check out .

Regards,
Dan

-- 
Dan Sommers

-- 
http://mail.python.org/mailman/listinfo/python-list


Strange behavior of int()

2006-01-26 Thread Brian
Hello,

Can someone tell me what I am doing wrong in this code.

If I create a file change.py with the following contents:

def intTest(M, c):
r = M
for k in c:
print 'int(r/k) = ', int(r/k), 'r =', r, 'k =', k, 'r/k
=', r/k
r = r - (k*int(r/k))

intTest(2.30, [0.25, 0.10, 0.05, 0.01])

and execute it, I get the output:

int(r/k) =  9 r = 2.3 k = 0.25 r/k = 9.2
int(r/k) =  0 r = 0.05 k = 0.1 r/k = 0.5
int(r/k) =  0 r = 0.05 k = 0.05 r/k = 1.0
int(r/k) =  4 r = 0.05 k = 0.01 r/k = 5.0

Why is int(r/k), where r = 0.5 and k = 0.5 = 0?  Shouldn't it be 1?
And why is the last one = 4 and not 5?

If I execute a similar command from the command line, it works just
fine:
>>> int(0.05/0.05)
1

I have tested this on Linux, python 2.3.2 and 2.4.1 and Windows python
2.4.2
all with the same results.

I think I am doing something wrong in this line:
r = r - (k*int(r/k))

Thanks for any help.

Brian

-- 
http://mail.python.org/mailman/listinfo/python-list