Unexpected behaviour of math.floor, round and int functions (rounding)

Avi Gross avigross at verizon.net
Sat Nov 20 19:38:20 EST 2021


Can I suggest a way to look at it, Grant?

In base 10, we represent all numbers as the (possibly infinite) sum of ten
raised to some integral power.

123 is 3 times 1 (ten to the zero power) plus
2 times 10 (ten to the one power) plus
1 times 100 (ten to the two power)

123.456 just extends this with
4 times 1/10 (ten to the minus one power) plus
5 times 1/100 (10**-2) plus
6 time 1/1000 (10**-3)

In binary, all the powers are not powers of 10 but powers of two.

So IF you wrote something like 111 it means 1 times 1 plus 1 times 2 plus 1
times 4 or 7. A zero anywhere just skips a 2 to that power. If you added a
decimal point to make 111.111 the latter part would be 1/2 plus 1/4 plus 1/8
or 7/8 which combined might be 7 and 7/8. So any fractions of the form
something over 2**N can be made easily and almost everything else cannot be
made in finite stretches. How would you make 2/3 or 3 /10?

But the opposite is something true. In decimal, to make the above it becomes
7.875 and to make other fractions of the kind, you need more and more As it
happens, all such base-2 compatible streams can be made because each is in
some sense a divide by two.

7/16 = 1/2 * .875 = .4375
7/32 = 1/2 * .4375 = .21875

and so on. But this ability is a special case artifact caused by a terminal
digit 5 always being able to be divided in tow to make a 25 a unit longer
and then again and again. Note 2 and 5 are factors of 10.  In the more
general case, this fails. In base 7, 3/7 is written easily as 0.3 but the
same fraction in decimal is a repeating copy of .428571... which never
terminates. A number like 3/7 + 4/49 + 5/343 generally cannot be written in
base 7 but the opposite is also true that only a approximation of numbers in
base 2 or base 10 can ever be written. I am, of course, talking about the
part to the right of the decimal. Integers to the left can be written in any
base. It is fractional parts that can end up being nonrepeating.

What about pi and e and the square root of 2? I suspect all of them have an
infinite sequence with no real repetition (over long enough stretches) in
any base! I mean an integer base, of course. The constant e in base e is
just 1.

As has been hammered home, computers have generally always dealt in one or
more combined on/off or Boolean idea so deep down they tend to have binary
circuits. At one point, programmers sometimes used base 8, octal, to group
three binary digits together as in setting flags for a file's permissions,
may use 01, 02 and 04 to be OR'ed with the current value to turn on
read/write/execute bits, or a combination like 7 (1+2+4) to set all of them
at once. And, again, for some purposes, base 16 (hexadecimal) is often used
with numerals extended to include a-f to represent a nibble or half byte, as
in some programs that let you set colors or whatever. But they are just a
convenience as ultimately they are used as binary for most purposes. In high
school, for a while, and just for fun, I annoyed one teacher by doing much
of my math in base 32 leaving them very perplexed as to how I got the
answers right. As far as I know, nobody seriously uses any bases not already
a power of two even for intermediate steps, outside of some interesting
stuff in number theory.

I think there have been attempts to use a decimal representation in some
accounting packages or database applications that allow any decimal numbers
to be faithfully represented and used in calculations. Generally this is not
a very efficient process but it can handle 0.3 albeit still have no way to
deal with transcendental numbers.

As such, since this is a Python Forum let me add you can get limited support
for some of this using the decimal module:

https://www.askpython.com/python-modules/python-decimal-module

But I doubt Python can be said to do things worse than just about any other
computer language when storing and using floating point. As hammered in
repeatedly, it is doing whatever is allowed in binary and many things just
cannot easily or at all be done in binary.

Let me leave you with Egyptian mathematics. Their use of fractions, WAY BACK
WHEN, only had the concept of a reciprocal of an integer. As in for any
integer N, there was a fraction of 1/N. They had a concept of 1/3 but not of
2/3 or 4/9.

So they added reciprocals to make any more complex fractions. To make 2/3
they added 1/2 plus 1/6 for example.

Since they were not stuck with any one base, all kinds of such combined
fractions could be done but of course the square root of 2 or pi were a bit
beyond them and for similar reasons.

https://en.wikipedia.org/wiki/Egyptian_fraction

My point is there are many ways humans can choose to play with numbers and
not all of them can easily do the same thing. Roman Numerals were (and
remain) a horror to do much mathematics with and especially when they play
games based on whether a symbol like X is to the left or right of another
like C as XC is 90 and CX is 110.

To do programming learn the rules that only what can be represented in
binary has a chance to ...





-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net at python.org> On
Behalf Of Grant Edwards
Sent: Saturday, November 20, 2021 5:24 PM
To: python-list at python.org
Subject: Re: Unexpected behaviour of math.floor, round and int functions
(rounding)

On 2021-11-20, Ben Bacarisse <ben.usenet at bsb.me.uk> wrote:

> You seem to be agreeing with me.  It's the floating point part that is 
> the issue, not the base itself.

No, it's the base. Floating point can't represent 3/10 _because_ it's base 2
floating point. Floating point in base 10 doesn't have any problem
representing 3/10.

--
Grant
--
https://mail.python.org/mailman/listinfo/python-list



More information about the Python-list mailing list