php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #16366 bit shifting error
Submitted: 2002-03-31 11:48 UTC Modified: 2004-07-26 16:48 UTC
Votes:3
Avg. Score:4.0 ± 0.8
Reproduced:3 of 3 (100.0%)
Same Version:2 (66.7%)
Same OS:2 (66.7%)
From: adam at adeptsoftware dot com Assigned:
Status: Closed Package: Documentation problem
PHP Version: 4.1.2 OS: WinXP
Private report: No CVE-ID: None
 [2002-03-31 11:48 UTC] adam at adeptsoftware dot com
echo (11>>34) produces "2"

Also PHP docs state that the max integer is "usually" 32 bits.  So what is an unsigned bigint from mysql stored as, and can I use the bit shift operator on it?

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2002-03-31 11:54 UTC] sander@php.net
AFAIK, PHP stores any number from MySQL as a string, until you access it as a number. If you try to do some math on that number, that will probably not work as expected. Bitshifting won't work either.
 [2002-03-31 12:21 UTC] daniel@php.net
and besides, you should consider using more accurate operators for sensitive data:

  http://www.php.net/manual/en/ref.bc.php

PHP is not actually meant to do real-time calculations or to write 3D-engines in. Also, there is no precalculated sine table and no int 13h in PHP :)

11/34 or bcdiv(11, 34) should do the trick. 
 [2002-03-31 12:27 UTC] adam at adeptsoftware dot com
Hmm well the bug of (11>>34) still exists.. anything >>32 or more should be zero.

I'm not really doing math, I am just storing boolean values in all the bits of a bigint, and trying to access the high bits has become a problem.  I could always divide by 2 34 times but that kinda sucks.
I think I will switch to blobs or something.
 [2002-03-31 12:43 UTC] daniel@php.net
why store boolean values in a bigint if someone invented "columns" in SQL? it's a useful thing, you know.

but to get your script working, why don't you just binary "&" ? 

if($data & 2)

would check if register two was set.
 [2002-03-31 12:49 UTC] daniel@php.net
> I think I will switch to blobs or something.

the problem is PHP-related. Switching to BLOBs won't solve it.

Why don't you use the ENUM('0','1') data field instead? It is more humand-friendly (better readable) and somewhat more what the inventor of databases wanted to do.

You can forget all database-related optimizations because the database does not understand what you want to do. 
 [2002-03-31 12:50 UTC] msopacua at idg dot nl
Daniel: 32 columns or 1 integer, I'd take the integer anytime.

The problem is, that large integers are converted to floats:
<?php
$number=11;
$bigint=$number * 10000000000000000000000000000000;
$bigint_nocalc=1100000000000000000000000000000000;
echo("Using values: $number - $bigint - $bigint_nocalc\n");
var_dump($number);
var_dump($bigint);
var_dump($bigint_nocalc);
echo ("\nNumber shift 34\n");
echo ($number>>34);
echo ("\nNumber shift 2\n");
echo ($number>>2);
echo("\nBigint shift 29\n");
echo($bigint>>29);
echo("\nBigint shift 30\n");
echo($bigint>>30);
echo("\nBigint shift 31\n");
echo($bigint>>31);
echo("\nBigint shift 32\n");
echo($bigint>>32);
echo("\nBigint shift 33\n");
echo($bigint>>33);
echo("\nBigint shift 1\n");
echo($bigint>>1);
?>

Output:
$ ./test_bit.php
Using values: 11 - 1.1E+32 - 1.1E+33
int(11)
float(1.1E+32)
float(1.1E+33)

Number shift 34
2
Number shift 2
2
Bigint shift 29
0
Bigint shift 30
0
Bigint shift 31
0
Bigint shift 32
0
Bigint shift 33
0
Bigint shift 1
0
 [2002-03-31 12:58 UTC] daniel@php.net
But "32 columns" are the way databases work. You can give names to these columns and everybody will understand what they are good for.

- If you decide to just have a (int)flags in SQL, how could someone possibly understand this without reading your documentation (if you wrote it) or reading through your source code?

- Databases are meant to have columns - commands such as WHERE, ORDER BY etc.. only work on columns, but not on your homebrewn data format. 

- You can add or remove columns, but modifying your flags would end in a big mess.

- Databases can optimize/cache requests on certain columns (at least I think they can).

- Using columns is less error-prone.

Why the hell should you STILL be using your custom-made flags-thingie instead?

But you are right and the bug still exists. PHP has problems with floating point operations - that's why I suggested to use the "BC" package.

I wrote a "BC wrapper" which wraps all BC functions to regular PHP functions. It is meant for people who want to develop their code with BC, but still want to keep compatibility to PHP installations without BC. Tell me if you want it.
 [2002-03-31 13:09 UTC] daniel@php.net
I'm sorry, but this is not flipcode.com - this is web-development.

Not performance, but maintaineability and readability are crucial. Always write your code in a way someone else could easily understand what you are trying to do (even if you'll never release your sourcecode). 
 [2002-03-31 13:10 UTC] derick@php.net
Can you please stop this discussion in the bug system. Fighting about what is best can be done in private mail just fine.

Derick
 [2002-03-31 13:23 UTC] msopacua at idg dot nl
Related to the bug only:
<?php
$int=2;

for($i=25;$i<33;$i++)
{
        $check=pow($int, $i);
        $check2=(int)$check;
        $check2 += 1;
        $check3=(int)$check;
        $check3 -= 1;
        echo("i is $i\n");
        var_dump($check);
        var_dump($check2);
        var_dump($check3);
        echo("\n");
}
?>

Gives some weird results:
$ ./test_float_conversion.php
i is 25
int(33554432)
int(33554433)
int(33554431)

i is 26
int(67108864)
int(67108865)
int(67108863)

i is 27
int(134217728)
int(134217729)
int(134217727)

i is 28
int(268435456)
int(268435457)
int(268435455)

i is 29
int(536870912)
int(536870913)
int(536870911)

i is 30
int(1073741824)
int(1073741825)
int(1073741823)

i is 31
float(2147483648)
int(-2147483647)
float(-2147483649)

i is 32
float(4294967296)
int(1)
int(-1)


I guess the manual should be appended, in the 'typecasting' section, to not cast to integer, when it's larger than 2^30 and that those numbers are automatically converted to floats.

(http://www.php.net/manual/en/language.types.type-juggling.php#language.types.typecasting)
 [2002-03-31 13:27 UTC] sander@php.net
Good point. Reopening as documentation problem.
 [2002-03-31 13:38 UTC] adam at adeptsoftware dot com
Well I have 200 groups of 64 on/off's.. I can name the 200 bigint groups but there is no way in hell I am going to name 12,800 bools, not to mention that they would take up 8x more space in the database.. Each group has the same structure - somebody needs to write a DB that uses structures as custom fields.  This may be the way they work but this is ancient design - I was surprised as hell when I started learning MySQL and realized that they are still doing things this way.  But anyway.  Now I am thinking "char binary" since it can be fixed size, but the documentation on PHP's conversions of MySQL is sparse.  If someone would like to pursue this in private email please write.

The original bug was about bit shifting, which I don't think would involve a conversion to float.. unless PHP is doing something weird.  It looks like someone is just not expecting a shift greater than 32.
 [2002-03-31 13:39 UTC] daniel@php.net
are you sure? there is already a bunch of reports on "floating-point bugs" in PHP. That's why I didn't reopen it.
 [2002-03-31 13:42 UTC] adam at adeptsoftware dot com
Just a reminder of the original issue:

echo (11>>34) produces "2"

This is not a documentation problem, unless you want to write that shifting greater than 32 has incorrect results.
 [2002-03-31 15:32 UTC] msopacua at idg dot nl
Actually - the echo(11>>34) issue, is somewhat expected behavior. What happens, is that it returns 11>>2 (34 - 32) - BUT only on a 32-bit system.

I just checked at an AIX 64-bit system, and there echo(11>>34) gives 0 And anything above 64-bit is than equal to $int>>($shift % 64).
Maybe it should be added to the bitwise operators documentation.

<?php
print("32 bits test\n");
$int=11;
for ($shift=31;$shift<35;$shift++)
{
        print("$shift: ");
        $check=$int>>$shift;
        print($check);
        print("\n\n");
}
print("64 bits test\n");
for($shift=63;$shift<67;$shift++)
{
        print("$shift: ");
        $check=$int>>$shift;
        print($check);
        print("\n");
}
?>

On a 64-bit system produces:
$ php -f test.php
32 bits test
31: 0

32: 0

33: 0

34: 0

64 bits test
63: 0
64: 11
65: 5
66: 2

On a 32-bit system produces:
32 bits test
31: 0

32: 11

33: 5

34: 2

64 bits test
63: 0
64: 11
65: 5
66: 2
 [2002-03-31 17:53 UTC] adam at adeptsoftware dot com
Ahh.. It still should produce zero though.
 [2002-04-01 22:43 UTC] jason@php.net
This is not really a bug, this is the behavior of a 32 bit system in any language. Run "perl -e 'print 11>>34'" or write a C program which does the same. 

Since this behavior is common and exists in other languages, the best we could do is document it.

-Jason
 [2004-07-26 16:48 UTC] vrana@php.net
This bug has been fixed in the documentation's XML sources. Since the
online and downloadable versions of the documentation need some time
to get updated, we would like to ask you to be a bit patient.

Thank you for the report, and for helping us make our documentation better.


 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Wed Nov 19 09:00:01 2025 UTC