Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bit overshift undefined: 1<<32 can be 1 #450

Closed
p5pRT opened this issue Aug 28, 1999 · 8 comments
Closed

bit overshift undefined: 1<<32 can be 1 #450

p5pRT opened this issue Aug 28, 1999 · 8 comments

Comments

@p5pRT
Copy link

p5pRT commented Aug 28, 1999

Migrated from rt.perl.org#1291 (status was 'resolved')

Searchable as RT1291$

@p5pRT
Copy link
Author

p5pRT commented Aug 28, 1999

From @jhi

One of Jon's quiz show questions (print (1<<(1<<5))) and the offered
answer of zero reminded me of this little feature I found while doing
64-bit footwork​:

$ perl -le 'print (1<<32)'
1

This is what happens for example in Intel Linux with Perl 5.005_03,
so this funky behavior is kinda pretty common. So Jon was wrong :-)

My guess is that the C standard doesn't actually say what should happen.

Now, the question is​: should we mandate a Known Behaviour for
overly wide bitshifts?

Here's something you can play with to see what your C compiler
and CPU conspire to do.

#include <stdio.h>
#define B(x) (sizeof(x)*8)
#define BM1(x) (B(x)-1)
int main() {
  unsigned long a = 1L;
  unsigned long b = 1L<<BM1(a);
  printf("a = %lx\n", a);
  printf("b = %lx\n", b);
  printf("a << %d = %lx %lx\n", B(a), a << B(a), 0);
  printf("a << %d = %lx %lx\n", BM1(a), a << BM1(a), b);
  printf("b >> %d = %lx %lx\n", B(b), b >> B(b), 0);
  printf("b >> %d = %lx %lx\n", BM1(b), b >> BM1(b), a);
  return 0;
}

Perl Info


Site configuration information for perl 5.00558:

Configured by jhi at Thu Jul 29 00:21:03 EET DST 1999.

Summary of my perl5 (revision 5.0 version 5 subversion 58) configuration:
  Platform:
    osname=dec_osf, osvers=4.0, archname=alpha-dec_osf
    uname='osf1 alpha.hut.fi v4.0 878 alpha '
    config_args='-Dprefix=/u/vieraat/vieraat/jhi/Perl -ders'
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=undef useperlio=undef d_sfio=undef
    use64bits=undef usemultiplicity=undef
  Compiler:
    cc='cc', optimize='-O4', gccversion=
    cppflags='-std -ieee -D_INTRINSICS -DLANGUAGE_C'
    ccflags ='-std -fprm d -ieee -D_INTRINSICS -DLANGUAGE_C'
    stdchar='unsigned char', d_stdstdio=define, usevfork=false
    intsize=4, longsize=8, ptrsize=8, doublesize=8
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=8
    alignbytes=8, usemymalloc=y, prototype=define
  Linker and Libraries:
    ld='ld', ldflags =''
    libpth=/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /var/shlib
    libs=-lgdbm -ldbm -ldb -lm -lrt
    libc=, so=so, useshrplib=true, libperl=libperl.so
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='  -Wl,-rpath,/u/vieraat/vieraat/jhi/Perl/lib/perl5/5.00558/alpha-dec_osf/CORE'
    cccdlflags=' ', lddlflags='-shared -expect_unresolved "*" -msym -s'

Locally applied patches:
    


@INC for perl 5.00558:
    /u/vieraat/vieraat/jhi/Perl/lib
    /u/vieraat/vieraat/jhi/Perl/lib/perl5/5.00558/alpha-dec_osf
    /u/vieraat/vieraat/jhi/Perl/lib/perl5/5.00558
    /u/vieraat/vieraat/jhi/Perl/lib/site_perl/5.00558/alpha-dec_osf
    /u/vieraat/vieraat/jhi/Perl/lib/site_perl
    .


Environment for perl 5.00558:
    HOME=/u/vieraat/vieraat/jhi
    LANG=C
    LANGUAGE (unset)
    LC_ALL=fi_FI.ISO8859-1
    LC_CTYPE=fi_FI.ISO8859-1
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/u/vieraat/vieraat/jhi/Perl/bin:/u/vieraat/vieraat/jhi/.s:/u/vieraat/vieraat/jhi/.b/OSF1:/c/bin:/p/bin:/p/adm/bin:/usr/bin:/usr/sbin:/sbin:/bin:/usr/ccs/bin:/usr/lib:/etc:/lib:/p/X6/bin:/p/X5/bin:/usr/bin/X11:/usr/lbin:/usr/sbin/acct:/usr/tcb/bin:/tcb/bin:/usr/field:/u/vieraat/vieraat/jhi
    PERLLIB=/u/vieraat/vieraat/jhi/Perl/lib
    PERL_BADLANG (unset)
    SHELL=/bin/zsh

@p5pRT
Copy link
Author

p5pRT commented Aug 28, 1999

From @jhi

Jarkko Hietaniemi writes​:

My guess is that the C standard doesn't actually say what should happen.

All this guessing and recollecting (*) is so touching. Somebody on
p5p must be carrying his C standard around at all times.

(*) "the second argument is interpreted modulo the wordsize [in bits]
  for unsigned arguments" was offered to me in private email.

--
$jhi++; # http​://www.iki.fi/jhi/
  # There is this special biologist word we use for 'stable'.
  # It is 'dead'. -- Jack Cohen

@p5pRT
Copy link
Author

p5pRT commented Aug 28, 1999

From [Unknown Contact. See original ticket]

On Sun, 29 Aug 1999 00​:26​:59 +0300 (EET DST), Jarkko Hietaniemi
<jhi@​cc.hut.fi> wrote​:

Here's something you can play with to see what your C compiler
and CPU conspire to do.

#include <stdio.h>
#define B(x) (sizeof(x)*8)
#define BM1(x) (B(x)-1)
int main() {
unsigned long a = 1L;
unsigned long b = 1L<<BM1(a);
printf("a = %lx\n", a);
printf("b = %lx\n", b);
printf("a << %d = %lx %lx\n", B(a), a << B(a), 0);
printf("a << %d = %lx %lx\n", BM1(a), a << BM1(a), b);
printf("b >> %d = %lx %lx\n", B(b), b >> B(b), 0);
printf("b >> %d = %lx %lx\n", BM1(b), b >> BM1(b), a);
return 0;
}

Here's what I get from VC++ on WinNT​:

./shift
a = 1
b = 80000000
a << 32 = 1 0
a << 31 = 80000000 80000000
b >> 32 = 80000000 0
b >> 31 = 1 1

The docs say​:

The result of a shift operation is undefined if the second operand
is negative, or if the right operand is greater than or equal to
the width in bits of the promoted left operand.

-Jan

@p5pRT
Copy link
Author

p5pRT commented Aug 28, 1999

From [Unknown Contact. See original ticket]

One of Jon's quiz show questions (print (1<<(1<<5))) and the offered
answer of zero reminded me of this little feature I found while doing
64-bit footwork​:

$ perl -le 'print (1<<32)'
1

This is what happens for example in Intel Linux with Perl 5.005_03,
so this funky behavior is kinda pretty common. So Jon was wrong :-)

The wrapping is certainly, um, interesting.

In C, we have this​:

  main() {
  int i;
  for (i = 30; i < 35; i++)
  printf("1 << %d == %u\n", i,1 << i);
  }
PRODUCING​:
  1 << 30 == 1073741824
  1 << 31 == 2147483648
  1 << 32 == 1
  1 << 33 == 2
  1 << 34 == 4

Which is what we have in Perl​:

  for ($i = 30; $i < 35; $i++) {
  printf("1 << %d == %u\n", $i,1 << $i);
  }
PRODUCING​:
  1 << 30 == 1073741824
  1 << 31 == 2147483648
  1 << 32 == 1
  1 << 33 == 2
  1 << 34 == 4

Note that changing %u to %d in both cases produces the negative -2147483648.

Python does this​:

  for i in xrange(30,35)​:
  print "1 << %d == %u" % (i, 1 << i)
PRODUCING​:
  1 << 30 == 1073741824
  1 << 31 == 2147483648
  1 << 32 == 0
  1 << 33 == 0
  1 << 34 == 0

But a simple change from 1 to 1L (built-in C-fast bigint) plus the printf
format to a string convert

  for i in xrange(30,35)​:
  print "1 << %d == %s" % (i, 1L << i)
PRODUCING​:
  1 << 30 == 1073741824L
  1 << 31 == 2147483648L
  1 << 32 == 4294967296L
  1 << 33 == 8589934592L
  1 << 34 == 17179869184L

Trying to do the same in Perl gets you in trouble​:

  % perl -MMath​::BigInt=​:constant -le 'print 1 << 40'
  Operation `<<'​: no method found,
  left argument in overloaded package Math​::BigInt,
  right argument in overloaded package Math​::BigInt at -e line 1.

--tom

@p5pRT
Copy link
Author

p5pRT commented Aug 28, 1999

From [Unknown Contact. See original ticket]

Oh, I can get it in C, too​:

  main() {
  int i;
  for (i = 30; i < 35; i++)
  printf("1 << %d == %12Lu\n", i, 1LL << i);
  }

Gives me​:

  1 << 30 == 1073741824
  1 << 31 == 2147483648
  1 << 32 == 4294967296
  1 << 33 == 8589934592
  1 << 34 == 17179869184

Of course, leftshift of 80 bits doesn't work quite so well in C as in Python. :-)

--tom

@p5pRT
Copy link
Author

p5pRT commented Aug 28, 1999

From @jhi

Jarkko Hietaniemi writes​:

This is what happens for example in Intel Linux with Perl 5.005_03,
so this funky behavior is kinda pretty common.

After some testing​: only AIX (both in ppc and power2) gets 0 from
1<<32, all the others I tried (x86 Linux, sparc Solaris, hppa HPUX,
and alpha Digital Unix with 1<<64) get 1.

So what should it be​: 0, 1, (NV)4294967296.0 (yech), or a bigint
(which we don't have yet)?

The same issue goes for right shift​: 0 or modulo if overshifting?
(just don't please suggest NVs or bigrats...)

--
$jhi++; # http​://www.iki.fi/jhi/
  # There is this special biologist word we use for 'stable'.
  # It is 'dead'. -- Jack Cohen

@p5pRT
Copy link
Author

p5pRT commented Aug 28, 1999

From @jhi

Kurt D. Starsinic writes​:

On Sun, Aug 29, 1999 at 01​:18​:02AM +0300, Jarkko Hietaniemi wrote​:

Jarkko Hietaniemi writes​:

This is what happens for example in Intel Linux with Perl 5.005_03,
so this funky behavior is kinda pretty common.

After some testing​: only AIX (both in ppc and power2) gets 0 from
1<<32, all the others I tried (x86 Linux, sparc Solaris, hppa HPUX,
and alpha Digital Unix with 1<<64) get 1.

Irix 6\.5 on the O2 also gets 1\.

So what should it be​: 0, 1, (NV)4294967296.0 (yech), or a bigint
(which we don't have yet)?

My vote is not the NV under any circumstances\, bigint preferred

when implemented, and big red letters in the docs saying that results
are undefined if you exceed the the maximum integer value that Perl

Would that be

  B<undefined>

or

  <EMPHASIS/>undefined</EMPHASIS>

or

  <BLINK><HONK><FONT SIZE="big" COLOR="red">undefined</FONT></BLINK>

(ducking)

--
$jhi++; # http​://www.iki.fi/jhi/
  # There is this special biologist word we use for 'stable'.
  # It is 'dead'. -- Jack Cohen

@p5pRT
Copy link
Author

p5pRT commented Aug 29, 1999

From [Unknown Contact. See original ticket]

On Sun, Aug 29, 1999 at 01​:18​:02AM +0300, Jarkko Hietaniemi wrote​:

Jarkko Hietaniemi writes​:

This is what happens for example in Intel Linux with Perl 5.005_03,
so this funky behavior is kinda pretty common.

After some testing​: only AIX (both in ppc and power2) gets 0 from
1<<32, all the others I tried (x86 Linux, sparc Solaris, hppa HPUX,
and alpha Digital Unix with 1<<64) get 1.

  Irix 6.5 on the O2 also gets 1.

So what should it be​: 0, 1, (NV)4294967296.0 (yech), or a bigint
(which we don't have yet)?

  My vote is not the NV under any circumstances, bigint preferred
when implemented, and big red letters in the docs saying that results
are undefined if you exceed the the maximum integer value that Perl
can handle on your hardware.

The same issue goes for right shift​: 0 or modulo if overshifting?
(just don't please suggest NVs or bigrats...)

  In this case, 0 makes sense to me.

  Peace,
* Kurt Starsinic (Kurt.Starsinic@​isinet.com) --------- Technical Specialist *
| `People keep pretending they can make things deeply |
| hierarchical, categorizable and sequential when they can't. |
| Everything is deeply intertwingled.' -- Ted Nelson |
Institute for Scientific Information http​://www.isinet.com/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant