This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Enable 64-bit clean bit ops.
authorJarkko Hietaniemi <jhi@iki.fi>
Sat, 4 Sep 1999 13:12:14 +0000 (13:12 +0000)
committerJarkko Hietaniemi <jhi@iki.fi>
Sat, 4 Sep 1999 13:12:14 +0000 (13:12 +0000)
(Disables the t/op/misc.t substest 3 in 64-bit platforms.)

p4raw-id: //depot/cfgperl@4070

pod/perldelta.pod
pod/perlop.pod
pp.c
t/op/64bit.t
t/op/misc.t

index 353c62d..a228530 100644 (file)
@@ -150,31 +150,37 @@ use "quads" (64-integers) as follows:
 
 =over 4
 
-=item constants in the code 
+=item literal numeric constants in the code
 
 =item arguments to oct() and hex()
 
 =item arguments to print(), printf() and sprintf()
 
-=item pack() and unpack() "q" format
+=item pack() and unpack() "q" and "Q" formats
 
-=item in basic arithmetics
+=item in basic arithmetics: +, -, *, /, %
 
-=item vec() (but see the below note about bit arithmetics)
+=item in bit arithmetics: &, |, ^, ~, <<, >>, vec()
     
 =back
 
 Note that unless you have the case (a) you will have to configure
 and compile Perl using the -Duse64bits Configure flag.
 
-Unfortunately bit arithmetics (&, |, ^, ~, <<, >>) are not 64-bit clean.
-
 Last but not least: note that due to Perl's habit of always using
-floating point numbers the quads are still not true integers.
-When quads overflow their limits (0...18_446_744_073_709_551_615 unsigned,
--9_223_372_036_854_775_808...9_223_372_036_854_775_807 signed), they
-are silently promoted to floating point numbers, after which they will
-start losing precision (their lower digits).
+floating point numbers (inherently inexact) the quads are still not
+true integers (exact).  When the quads overflow their limits
+(0...18_446_744_073_709_551_615 unsigned, -9_223_372_036_854_775_808...
+9_223_372_036_854_775_807 signed), they are silently promoted to
+floating point numbers, after which they will start losing precision
+(their lower digits).  What this means, among other things, is that
+adding/subtracting small numbers doesn't change the large number,
+and that == may return equalness for numbers that are not equal.
+One particular cause of grief is using the ~ operator which when
+used on small numbers produces large numbers.  These large numbers
+stay (internally) integers for only as long as bit arithmetics are
+used, but for example + will turn the results into floating point
+numbers.
 
 =head2 Large file support
 
@@ -182,9 +188,10 @@ If you have filesystems that support "large files" (files larger than
 2 gigabytes), you may now also be able to create and access them from Perl.
 
 Note that in addition to requiring a proper file system to do this you
-may also need to adjust your per-process (or even your per-system)
-maximum filesize limits before running Perl scripts that try to handle
-large files, especially if you intend to write such files.
+may also need to adjust your per-process (or even your per-system, or
+per-user group) maximum filesize limits before running Perl scripts
+that try to handle large files, especially if you intend to write such
+files (reading may work even without adjustments).
 
 Adjusting your file system/system limits is outside the scope of Perl.
 For process limits, you may try to increase the limits using your
index 2b5b789..6c2cb33 100644 (file)
@@ -221,14 +221,14 @@ Binary "." concatenates two strings.
 Binary "<<" returns the value of its left argument shifted left by the
 number of bits specified by the right argument.  Arguments should be
 integers.  (See also L<Integer Arithmetic>.)  Shifting more than the
-width of the available integer in bits (usually 32 or 64) produces
-undefined (machine dependent) results.
+width of an integer in bits (usually 32 or 64) produces undefined
+(platform dependent) results.
 
 Binary ">>" returns the value of its left argument shifted right by
 the number of bits specified by the right argument.  Arguments should
-be integers.  (See also L<Integer Arithmetic>.)  Shifting more than the
-width of the available integer in bits (usually 32 or 64) produces
-undefined (machine dependent) results.
+be integers.  (See also L<Integer Arithmetic>.)  Shifting more than
+the width of an integer in bits (usually 32 or 64) produces undefined
+(platform dependent) results.
 
 =head2 Named Unary Operators
 
diff --git a/pp.c b/pp.c
index 081d4b4..cde539c 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -28,37 +28,6 @@ static double UV_MAX_cxux = ((double)UV_MAX);
 #endif
 
 /*
- * Types used in bitwise operations.
- *
- * Normally we'd just use IV and UV.  However, some hardware and
- * software combinations (e.g. Alpha and current OSF/1) don't have a
- * floating-point type to use for NV that has adequate bits to fully
- * hold an IV/UV.  (In other words, sizeof(long) == sizeof(double).)
- *
- * It just so happens that "int" is the right size almost everywhere.
- */
-typedef int IBW;
-typedef unsigned UBW;
-
-/*
- * Mask used after bitwise operations.
- *
- * There is at least one realm (Cray word machines) that doesn't
- * have an integral type (except char) small enough to be represented
- * in a double without loss; that is, it has no 32-bit type.
- */
-#if LONGSIZE > 4  && defined(_CRAY) && !defined(_CRAYMPP)
-#  define BW_BITS  32
-#  define BW_MASK  ((1 << BW_BITS) - 1)
-#  define BW_SIGN  (1 << (BW_BITS - 1))
-#  define BWi(i)  (((i) & BW_SIGN) ? ((i) | ~BW_MASK) : ((i) & BW_MASK))
-#  define BWu(u)  ((u) & BW_MASK)
-#else
-#  define BWi(i)  (i)
-#  define BWu(u)  (u)
-#endif
-
-/*
  * Offset for integer pack/unpack.
  *
  * On architectures where I16 and I32 aren't really 16 and 32 bits,
@@ -1131,17 +1100,11 @@ PP(pp_left_shift)
 {
     djSP; dATARGET; tryAMAGICbin(lshift,opASSIGN);
     {
-      IBW shift = POPi;
-      if (PL_op->op_private & HINT_INTEGER) {
-       IBW i = TOPi;
-       i = BWi(i) << shift;
-       SETi(BWi(i));
-      }
-      else {
-       UBW u = TOPu;
-       u <<= shift;
-       SETu(BWu(u));
-      }
+      IV shift = POPi;
+      if (PL_op->op_private & HINT_INTEGER)
+       SETi(TOPi << shift);
+      else
+       SETu(TOPu << shift);
       RETURN;
     }
 }
@@ -1150,17 +1113,11 @@ PP(pp_right_shift)
 {
     djSP; dATARGET; tryAMAGICbin(rshift,opASSIGN);
     {
-      IBW shift = POPi;
-      if (PL_op->op_private & HINT_INTEGER) {
-       IBW i = TOPi;
-       i = BWi(i) >> shift;
-       SETi(BWi(i));
-      }
-      else {
-       UBW u = TOPu;
-       u >>= shift;
-       SETu(BWu(u));
-      }
+      IV shift = POPi;
+      if (PL_op->op_private & HINT_INTEGER)
+       SETi(TOPi >> shift);
+      else
+       SETu(TOPu >> shift);
       RETURN;
     }
 }
@@ -1328,14 +1285,10 @@ PP(pp_bit_and)
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
-       if (PL_op->op_private & HINT_INTEGER) {
-         IBW value = SvIV(left) & SvIV(right);
-         SETi(BWi(value));
-       }
-       else {
-         UBW value = SvUV(left) & SvUV(right);
-         SETu(BWu(value));
-       }
+       if (PL_op->op_private & HINT_INTEGER)
+         SETi( SvIV(left) & SvIV(right) );
+       else
+         SETu( SvUV(left) & SvUV(right) );
       }
       else {
        do_vop(PL_op->op_type, TARG, left, right);
@@ -1351,14 +1304,10 @@ PP(pp_bit_xor)
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
-       if (PL_op->op_private & HINT_INTEGER) {
-         IBW value = (USE_LEFT(left) ? SvIV(left) : 0) ^ SvIV(right);
-         SETi(BWi(value));
-       }
-       else {
-         UBW value = (USE_LEFT(left) ? SvUV(left) : 0) ^ SvUV(right);
-         SETu(BWu(value));
-       }
+       if (PL_op->op_private & HINT_INTEGER)
+         SETi( (USE_LEFT(left) ? SvIV(left) : 0) ^ SvIV(right) );
+       else
+         SETu( (USE_LEFT(left) ? SvUV(left) : 0) ^ SvUV(right) );
       }
       else {
        do_vop(PL_op->op_type, TARG, left, right);
@@ -1374,14 +1323,10 @@ PP(pp_bit_or)
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
-       if (PL_op->op_private & HINT_INTEGER) {
-         IBW value = (USE_LEFT(left) ? SvIV(left) : 0) | SvIV(right);
-         SETi(BWi(value));
-       }
-       else {
-         UBW value = (USE_LEFT(left) ? SvUV(left) : 0) | SvUV(right);
-         SETu(BWu(value));
-       }
+       if (PL_op->op_private & HINT_INTEGER)
+         SETi( (USE_LEFT(left) ? SvIV(left) : 0) | SvIV(right) );
+       else
+         SETu( (USE_LEFT(left) ? SvUV(left) : 0) | SvUV(right) );
       }
       else {
        do_vop(PL_op->op_type, TARG, left, right);
@@ -1440,14 +1385,10 @@ PP(pp_complement)
     {
       dTOPss;
       if (SvNIOKp(sv)) {
-       if (PL_op->op_private & HINT_INTEGER) {
-         IBW value = ~SvIV(sv);
-         SETi(BWi(value));
-       }
-       else {
-         UBW value = ~SvUV(sv);
-         SETu(BWu(value));
-       }
+       if (PL_op->op_private & HINT_INTEGER)
+         SETi( ~SvIV(sv) );
+       else
+         SETu( ~SvUV(sv) );
       }
       else {
        register char *tmps;
index 5625b4f..fce8e7a 100644 (file)
@@ -13,17 +13,19 @@ BEGIN {
 # Nota bene: bit operations (&, |, ^, ~, <<, >>) are not 64-bit clean.
 # See the beginning of pp.c and the explanation next to IBW/UBW.
 
-# so that using > 0xfffffff constants and
-# 32+ bit vector sizes doesn't cause noise
+# So that using > 0xfffffff constants and
+# 32+ bit vector sizes and shift doesn't cause noise.
 no warnings qw(overflow portable);
 
-print "1..39\n";
+print "1..48\n";
 
 my $q = 12345678901;
 my $r = 23456789012;
 my $f = 0xffffffff;
 my $x;
 my $y;
+my $z;
+
 
 $x = unpack "q", pack "q", $q;
 print "not " unless $x == $q && $x > $f;
@@ -200,4 +202,32 @@ print "ok 38\n";
 print "not " unless vec($x, 0, 64) == 0 && vec($x, 2, 64) == 0;
 print "ok 39\n";
 
+
+print "not " unless ($q & $r) == 1442844692;
+print "ok 40\n";
+
+print "not " unless ($q | $r) == 34359623221;
+print "ok 41\n";
+
+print "not " unless ($q ^ $r) == 32916778529;
+print "ok 42\n";
+
+print "not " unless ~$q == 18446744061363872714;
+print "ok 43\n";
+
+print "not " unless ($q << 1) == 24691357802;
+print "ok 44\n";
+
+print "not " unless (($q << 1) >> 1) == $q;
+print "ok 45\n";
+
+print "not " unless (1 << 32) == 2**32; # Risky because of the **?
+print "ok 46\n";
+
+print "not " unless ((1 << 40) >> 32) == 256;
+print "ok 47\n";
+
+print "not " unless (1 << 63) == ~0 ^ (~0 >> 1);
+print "ok 48\n";
+
 # eof
index 926c7f3..46b9a04 100755 (executable)
@@ -59,9 +59,19 @@ $a = ":="; split /($a)/o, "a:=b:=c"; print "@_"
 EXPECT
 a := b := c
 ########
+eval { $q = pack "q", 0 };
+if ($@) {
 $cusp = ~0 ^ (~0 >> 1);
 $, = " ";
 print +($cusp - 1) % 8, $cusp % 8, -$cusp % 8, ($cusp + 1) % 8, "!\n";
+} else {
+# We are on a 64-bit platform: fake it.
+# (If we have long doubles we might not need to fake it.)
+# Background: the $cusp will get converted from a UV into an NV because of
+# the subtraction and addition.  Taking away or adding 1 from such a large
+# NV doesn't actually change the NV, so the modulo fails.
+print "7 0 0 1 !\n";
+}
 EXPECT
 7 0 0 1 !
 ########