Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to simulate C style integer division?

164 views
Skip to first unread message

Shiyao Ma

unread,
Jan 21, 2016, 3:39:46 AM1/21/16
to
Hi,

I wanna simulate C style integer division in Python3.

So far what I've got is:
# a, b = 3, 4

import math
result = float(a) / b
if result > 0:
result = math.floor(result)
else:
result = math.ceil(result)


I found it's too laborious. Any quick way?

--

吾輩は猫である。ホームーページはhttps://introo.me <http://introo.me>。

Yann Kaiser

unread,
Jan 21, 2016, 3:42:27 AM1/21/16
to
You can use the // operator, which should do what you want.
> --
> https://mail.python.org/mailman/listinfo/python-list
>

Peter Heitzer

unread,
Jan 21, 2016, 3:44:51 AM1/21/16
to
Shiyao Ma <i...@introo.me> wrote:
>Hi,

>I wanna simulate C style integer division in Python3.

>So far what I've got is:
># a, b = 3, 4

>import math
>result = float(a) / b
>if result > 0:
> result = math.floor(result)
>else:
> result = math.ceil(result)


>I found it's too laborious. Any quick way?
In Python3 you have to use the floor division operator '//'
For example:
result=a//b



Jussi Piitulainen

unread,
Jan 21, 2016, 3:59:38 AM1/21/16
to
Shiyao Ma writes:

> I wanna simulate C style integer division in Python3.
>
> So far what I've got is:
> # a, b = 3, 4
>
> import math
> result = float(a) / b
> if result > 0:
> result = math.floor(result)
> else:
> result = math.ceil(result)
>
> I found it's too laborious. Any quick way?

The general principle is to define a function when something is too
laborious to do inline. def truncdiv(a, b): ...

But math.trunc rounds towards 0. Maybe you want to use that here.

Ben Finney

unread,
Jan 21, 2016, 4:12:05 AM1/21/16
to
Shiyao Ma <i...@introo.me> writes:

> I wanna simulate C style integer division in Python3.

I'm not sure I know exactly what behaviour you want (“C style” may mean
different things to each of us).

I'll point out that Python's ‘//’ operator specifies floor division
<URL:https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations>.

--
\ “Timid men prefer the calm of despotism to the boisterous sea |
`\ of liberty.” —Thomas Jefferson |
_o__) |
Ben Finney

Paul Rubin

unread,
Jan 21, 2016, 4:44:15 AM1/21/16
to
Ben Finney <ben+p...@benfinney.id.au> writes:
> I'm not sure I know exactly what behaviour you want (“C style” may mean
> different things to each of us).

I thought he meant trunc-division, so -5 / 2 = -2 and -5 % 2 = -1.
Python specifies floor division but C leaves it unspecified, I thought.

Jussi Piitulainen

unread,
Jan 21, 2016, 4:58:23 AM1/21/16
to
Paul Rubin writes:

> Ben Finney writes:
>> I'm not sure I know exactly what behaviour you want (“C style” may mean
>> different things to each of us).
>
> I thought he meant trunc-division, so -5 / 2 = -2 and -5 % 2 = -1.
> Python specifies floor division but C leaves it unspecified, I thought.

I found a statement that it's specified to be truncating since C99.
Before that it was flooring or truncating.

Reading OP's code, the intention seemed clear to me.

Jussi Piitulainen

unread,
Jan 21, 2016, 5:13:52 AM1/21/16
to
It's actually best to avoid floating point altogether. The following
answer by Abhijit was linked from the StackOverflow page[1] where I
found out about C99 integer division:

def trunc_div(a,b):
q, r = divmod(a,b)
if q < 0 and r:
q += 1
return q

It adjusts a negative floored quotient towards zero if there was a
remainder.

[1] http://stackoverflow.com/questions/15633787/truncated-versus-floored-division-in-python?rq=1

Oscar Benjamin

unread,
Jan 21, 2016, 5:23:36 AM1/21/16
to
On 21 January 2016 at 08:39, Shiyao Ma <i...@introo.me> wrote:
>
> I wanna simulate C style integer division in Python3.
>
> So far what I've got is:
> # a, b = 3, 4
>
> import math
> result = float(a) / b
> if result > 0:
> result = math.floor(result)
> else:
> result = math.ceil(result)
>
>
> I found it's too laborious. Any quick way?

How precise do you want to be? I think that having a negative divisor
doesn't come up much in practise but this matches in all cases anyway:

atruncb = abs(a) // abs(b) if a * b > 0 else - (abs(a) // abs(b))

If you don't care about the negative divisor case then it becomes:

atruncb = abs(a) // b if a > 0 else - (abs(a) // b)

Note that for integers in Python these are exact and will work for
integers of any size. Using floating point is unnecessary here and
would have overflow problems.

--
Oscar

Steven D'Aprano

unread,
Jan 21, 2016, 7:43:11 AM1/21/16
to
On Thu, 21 Jan 2016 08:11 pm, Ben Finney wrote:

> Shiyao Ma <i...@introo.me> writes:
>
>> I wanna simulate C style integer division in Python3.
>
> I'm not sure I know exactly what behaviour you want (“C style” may mean
> different things to each of us).

Surely is means "whatever the C standard defines integer division to mean".

Are their any C programmers here who can tell us what the C standard says?

According to this:

http://stackoverflow.com/questions/3602827/what-is-the-behavior-of-integer-division-in-c

the behaviour of integer division was implementation dependent in C89, but
has now been specified in detail since C99. The answer is that a/b for
integers a and b *truncate towards zero*. That is, it returns the integer
part with no fractional part:

Both arguments are positive, or both negative:

11/2 = 5.5 so throw away the 0.5 and return 5

-11/-2 = 5.5 so throw away the 0.5 and return 5

One argument is positive and the other negative:

-11/2 = -5.5 so throw away the 0.5 and return -5

11/-2 = -5.5 so throw away the 0.5 and return -5


Python's integer division // performs flooring, not truncating, so it
disagrees in the case that exactly one of the arguments are negative:

py> 11//2
5
py> -11//-2
5

py> 11//-2
-6
py> -11//2
-6


So my guess is that the fastest, and certainly the most obvious, way to get
the same integer division behaviour as C99 would be:

def intdiv(a, b):
# C99 style integer division with truncation towards zero.
n = a//b
if (a < 0) != (b < 0):
n += 1
return n



--
Steven

Jussi Piitulainen

unread,
Jan 21, 2016, 9:00:49 AM1/21/16
to
Steven D'Aprano writes:

> So my guess is that the fastest, and certainly the most obvious, way
> to get the same integer division behaviour as C99 would be:
>
> def intdiv(a, b):
> # C99 style integer division with truncation towards zero.
> n = a//b
> if (a < 0) != (b < 0):
> n += 1
> return n

You should only increment if there is a (non-zero) remainder.

Marko Rauhamaa

unread,
Jan 21, 2016, 9:32:00 AM1/21/16
to
Jussi Piitulainen <jussi.pi...@helsinki.fi>:
Maybe:

def intdiv(a, b):
return a // b if (a < 0) == (b < 0) else -(-a // b)


Marko

Wolfgang Maier

unread,
Jan 21, 2016, 9:36:13 AM1/21/16
to
Right. Merging Steven's suggestion and fractions.Fraction.__trunc__
implementation I think the right answer may be:

def intdiv2(a,b):
# C99 style integer division with truncation towards zero.
if (a < 0) != (b < 0):
return -(-a // b)
else:
return a // b

Cheers,
Wolfgang


---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus


Jussi Piitulainen

unread,
Jan 21, 2016, 9:48:56 AM1/21/16
to
Marko Rauhamaa writes:
Nice.

Random832

unread,
Jan 21, 2016, 2:52:39 PM1/21/16
to
On Thu, Jan 21, 2016, at 09:31, Marko Rauhamaa wrote:
> Maybe:
>
> def intdiv(a, b):
> return a // b if (a < 0) == (b < 0) else -(-a // b)

Personally, I like a // b + (a % b and a ^ b < 0) - I've done the
opposite in C to get python-style division.

Marko Rauhamaa

unread,
Jan 21, 2016, 4:17:34 PM1/21/16
to
Random832 <rand...@fastmail.com>:
Well, then there's:

def intdiv(a, b):
return int(a / b)


Marko

Matt Wheeler

unread,
Jan 21, 2016, 7:57:24 PM1/21/16
to
On 21 January 2016 at 21:17, Marko Rauhamaa <ma...@pacujo.net> wrote:
> Well, then there's:
>
> def intdiv(a, b):
> return int(a / b)

That depends on how accurate you need it to be

>>> def intdiv(a, b):
... return a//b if (a < 0) == (b < 0) else -(-a//b)
...
>>> num = 3**171
>>> num
3870210234510307998744588107535211184800325224934979257430349324033792477926791547
>>> num2 = 4**80
>>> num2
1461501637330902918203684832716283019655932542976
>>> intdiv(num, num2)
2648105301871818722187687529062555
>>> int(num/num2)
2648105301871818477801931416797184



--
Matt Wheeler
http://funkyh.at

Grobu

unread,
Jan 21, 2016, 8:59:42 PM1/21/16
to
On 21/01/16 09:39, Shiyao Ma wrote:
> Hi,
>
> I wanna simulate C style integer division in Python3.
>
> So far what I've got is:
> # a, b = 3, 4
>
> import math
> result = float(a) / b
> if result > 0:
> result = math.floor(result)
> else:
> result = math.ceil(result)
>
>
> I found it's too laborious. Any quick way?
>

math.trunc( float(a) / b )

Terry Reedy

unread,
Jan 21, 2016, 9:56:41 PM1/21/16
to
On 1/21/2016 3:39 AM, Shiyao Ma wrote:

> I wanna simulate C style integer division in Python3.

There are two problems with this spec: it assumes that 'C style integer
division' is well defined and that we know the definition. Better:

"How do I write a function 'div' in Python 3 so that the following (with
values added after each '==') is True:

all((div(1,2) == , div(-1,-2) == , dif(-1,2) == , dif(1,-2) == ))"

For '//', the values would be 0, 0, -1, -1. If you want 0, 0, 0, 0
(truncation toward 0), then

def div(i, j):
return (i // j) + ((i < 0) ^ (j < 0))

print(all((div(1,2) == 0, div(-1,-2) == 0,
div(-1,2) == 0, div(1,-2) == 0)))

prints 'True'.

--
Terry Jan Reedy

Terry Reedy

unread,
Jan 21, 2016, 10:28:36 PM1/21/16
to
But fails with remainder 0, as others noted. Lesson: include corner
cases in validation test. Anyway, my main point about writing a clear
spec remains true.

--
Terry Jan Reedy

Steven D'Aprano

unread,
Jan 21, 2016, 10:48:56 PM1/21/16
to
That fails for sufficiently big numbers:


py> a = 3**1000 * 2
py> b = 3**1000
py> float(a)/b # Exact answer should be 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: long int too large to convert to float


Note that Python gets the integer division correct:

py> a//b
2L


And even gets true division correct:

py> from __future__ import division
py> a/b
2.0


so it's just the intermediate conversion to float that fails.



--
Steven

Random832

unread,
Jan 22, 2016, 12:58:55 AM1/22/16
to
Terry Reedy <tjr...@udel.edu> writes:
> But fails with remainder 0, as others noted. Lesson: include corner
> cases in validation test. Anyway, my main point about writing a clear
> spec remains true.

My validation test for this was to loop both numerator and denominator
from -5 to 5 (skipping denominator 0) to cover all cases (comparing
against the original post's unoptimized code) without having to think
about a minimal set to cover them.

Grobu

unread,
Jan 23, 2016, 7:04:11 AM1/23/16
to
On 22/01/16 04:48, Steven D'Aprano wrote:
[ ... ]

>> math.trunc( float(a) / b )
>
>
> That fails for sufficiently big numbers:
>
>
> py> a = 3**1000 * 2
> py> b = 3**1000
> py> float(a)/b # Exact answer should be 2
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> OverflowError: long int too large to convert to float
>
>
> Note that Python gets the integer division correct:
>
> py> a//b
> 2L
>
>
> And even gets true division correct:
>
> py> from __future__ import division
> py> a/b
> 2.0
>
>
> so it's just the intermediate conversion to float that fails.
>

Thanks! I did see recommandations to avoid floats throughout the thread,
but didn't understand why.

Following code should be exempt from such shortcomings :

def intdiv(a, b):
return (a - (a % (-b if a < 0 else b))) / b


Grobu

unread,
Jan 23, 2016, 7:52:50 AM1/23/16
to
> def intdiv(a, b):
> return (a - (a % (-b if a < 0 else b))) / b
>
>

Duh ... Got confused with modulos (again).

def intdiv(a, b):
return (a - (a % (-abs(b) if a < 0 else abs(b)))) / b

Jussi Piitulainen

unread,
Jan 23, 2016, 10:07:36 AM1/23/16
to
You should use // here to get an exact integer result.

Grobu

unread,
Jan 23, 2016, 11:44:06 AM1/23/16
to
You're totally right, thanks! It isn't an issue for Python 2.x's
"classic division", but it becomes one with Python 3's "True division",
and '//' allows to play it safe all along.
0 new messages