Integer math question

Bengt Richter bokr at oz.net
Thu Jan 8 13:53:10 EST 2004


On 3 Jan 2004 08:32:07 -0800, mersmann at szut.uni-bremen.de (Frank) wrote:

>Hi,
>
>can anybody help with the following problem?
>
>In C++
>
>i = 5 / 10 	and
>i = -5 / 10 	both have the same result 0.
>
>In python
>
>i = 5 / 10 	gives me 0 as expected, but
>i = -5 / 10 	gives -1 as result.
>
>Is this a feature or a bug? I remember Delphi gave me the same result as
>C++.
It is a feature. Python does the more useful thing IMO.
If you look on / (or now //) as a denominator-defined mapping
of integer intervals to integers, it is clearer.

I.e., the mappings that python implements are

    [denom*k, denom*k+denom) => k for denom >0
and
    [denom*k+denom, denom*k) => k for denom <0


The C version is ugly, because it maps a unique extra-sized interval
around zero to zero, i.e., for denom>0

    [-denom+1, denom) => 0

which contains 2*denom-1 source integers, and all the rest of the
intervals go symmetrically in both directions from there, containing
denom integers. Python's source intervals are all the same size.


====< showintdiv.cpp >=====================================
#include <stdio.h>
#include <stdlib.h>
void main(int argc, char* argv[]){
    if(argc<4){ printf("Usage: %s xlo xhi den\n", argv[0]); return; }
    int xlo = atoi(argv[1]);
    int xhi = atoi(argv[2]);
    int den = atoi(argv[3]);
    int x;
    for(x=xlo; x<xhi; ++x) printf("%3d", x); printf("\n");
    for(x=xlo; x<xhi; ++x) printf("%3d", x/den); printf("\n");
}
===========================================================

We'll do a weird printf JFTHOI and to match program lines better:

====< showintdiv.py >======================================
printf = (lambda wso, fmt, *args: wso(fmt%args)).__get__(
            __import__('sys').stdout.write)

def main(argv):
    if len(argv)<4: printf("Usage: %s xlo xhi den\n" % argv[0]); return
    xlo = int(argv[1])
    xhi = int(argv[2])
    den = int(argv[3])
    for x in xrange(xlo, xhi): printf("%3d", x)
    printf("\n");
    for x in xrange(xlo, xhi): printf("%3d", x/den)
    printf("\n");

if __name__== '__main__':
    import sys
    main(sys.argv)
===========================================================


Python maps successive equal sized intervals to successive integers from -inf to +inf

[10:38] C:\pywk\clp>showintdiv.py   -15 16  5
-15-14-13-12-11-10 -9 -8 -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
 -3 -3 -3 -3 -3 -2 -2 -2 -2 -2 -1 -1 -1 -1 -1  0  0  0  0  0  1  1  1  1  1  2  2  2  2  2  3

But C maps symmetrically across zero, causing 2*denom-1 points to map to zero

[10:38] C:\pywk\clp>showintdiv.exe  -15 16  5
-15-14-13-12-11-10 -9 -8 -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
 -3 -2 -2 -2 -2 -2 -1 -1 -1 -1 -1  0  0  0  0  0  0  0  0  0  1  1  1  1  1  2  2  2  2  2  3

With a negative denominator, python still maps successive intervals, but going the other
direction from (and including) zero.

[10:38] C:\pywk\clp>showintdiv.py   -15 16 -5
-15-14-13-12-11-10 -9 -8 -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
  3  2  2  2  2  2  1  1  1  1  1  0  0  0  0  0 -1 -1 -1 -1 -1 -2 -2 -2 -2 -2 -3 -3 -3 -3 -3

Whereas C is still symmetric with the 2n-1 points going to zero:

[10:38] C:\pywk\clp>showintdiv.exe  -15 16 -5
-15-14-13-12-11-10 -9 -8 -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
  3  2  2  2  2  2  1  1  1  1  1  0  0  0  0  0  0  0  0  0 -1 -1 -1 -1 -1 -2 -2 -2 -2 -2 -3

The extra-sized interval across zero makes for a hiccup in the use of the mapping as a function.
E.g., you can't translate the input by k*denom and get a uniformly translated (by k) output
unless you stay away from the zero interval.

Ok, back to the grind...

Regards,
Bengt Richter



More information about the Python-list mailing list