将64位整数截断为32位并模拟值

时间:2019-08-01 00:51:32

标签: php type-conversion integer bit-manipulation bitwise-operators

我正在尝试编写一种算法,以通过截断将64Bit整数转换为32Bit,并返回一个准确表示32Bit值的值。明显的问题是PHP中的整数只有64Bit(不包括32Bit系统)。

我首先尝试了以下方法:

$x = $v & 0xFFFFFFFF

因此,如果$v = PHP_INT_MAX$x4294967295,那么我真的很想-1。我知道这样做的原因是,当用64位整数表示时,PHP将零添加到最后32位,这就是为什么我得到正数的原因。

到目前为止,我的解决方案是:

function convert64BitTo32Bit(int $v): int
{
    $v &= 0xFFFFFFFF;

    if ($v & 0x80000000) {
        return $v | 0xFFFFFFFF00000000;
    }

    return $v;
}

我非常确定它是正确的。我的问题是,它需要if语句来检查截断的数字是否为负。我真的希望有一个按位解决方案。可能不可能,但是我想问一下。

编辑:

可以将问题简化为解决方案的一部分。即,如果第一位为1,则将所有位设为1,如果第一位为0,则将所有位设为0

# example assumes input is the LSBs of an 8Bit integer.
# scale for 64Bit and the same solution should work.

op(1010) = 1111
op(0101) = 0000

op(0000) = 0000
op(1000) = 1111
op(0001) = 0000

我将能够使用LSB导出此值,然后将其屏蔽到64位整数的MSB上。这就是我现在想要找出的,尽管我试图避免创建怪物方程。

2 个答案:

答案 0 :(得分:2)

使用按位运算可能是一种更优雅/有效的方法,但是您也可以使用CREATE VIEW customer_master as ( select * from survey_info full join survey_responses on survey_info.submissionid =survey_responses.submissionid ); +-------+ ----+ | | +---- | | | | ----+ | | +---- +-------+ 强制进行转换。例如:打包为未签名,打包为已签名。

pack()

我很好奇您将其应用于什么,因为几年前当我将应用程序从32位计算机迁移到64位计算机时,我不得不用同样的方法破坏哈希函数,但是我可以不记得那是什么。

编辑:出于某种原因,我记得Two's Complement很辛苦。从字面上看,只需反转并添加一个即可。

unpack()

编辑2:我看到您想将其扩展为任意位长度,在这种情况下,您只需要计算掩码而不是显式设置它们即可:

function overflow32($in) {
    return unpack('l', pack('i', $in & 0xFFFFFFFF))[1];
}

var_dump( overflow32(pow(2,33)-1) ); // int(-1)

我留在调试function overflow32($in) { if( $in & 0x80000000 ) { return ( ( ~$in & 0xFFFFFFFF) + 1 ) * -1; } else { return $in & 0xFFFFFFFF; } } var_dump( kludge32(pow(2,33)-1) ); 中以获取输出味道:

function overflow_bits($in, $bits=32) {
    $sign_mask = 1 << $bits-1;
    $clamp_mask = ($sign_mask << 1) - 1;

    var_dump(
        decbin($in),
        decbin($sign_mask),
        decbin($clamp_mask)
    );

    if( $in & $sign_mask ) {
        return ( ( ~$in & $clamp_mask) + 1 ) * -1;
    } else {
        return $in & $clamp_mask;
    }
}

var_dump(
    overflow_bits(pow(2, 31), 32),
    overflow_bits(pow(2, 15), 16),
    overflow_bits(pow(2, 7), 8)
);

答案 1 :(得分:0)

我想我已经破解了:

function overflow32Bit(int $x): int
{
    return ($x & 0xFFFFFFFF) | ((($x & 0xFFFFFFFF) >> 31) * ((2 ** 32) - 1) << 32);
}

var_dump(overflow32Bit(PHP_INT_MAX));     // -1          correct
var_dump(overflow32Bit(PHP_INT_MAX - 1)); // -2          correct
var_dump(overflow32Bit(PHP_INT_MIN));     //  0          correct
var_dump(overflow32Bit((2 ** 31) - 1));   //  2147483647 correct
var_dump(overflow32Bit((2 ** 31)));       // -2147483647 correct
var_dump(overflow32Bit(0xFFFFFFFF));      // -1          correct
var_dump(overflow32Bit(0x7FFFFFFF));      //  2147483647 correct

解决方案实际上是盯着我。获取第一位的值,然后将其乘以无符号32位整数的最大值。

如果有人可以提出更好或更短的解决方案,我也会接受。

PS。这仅适用于32Bit,我也打算将此证明用于16Bit和8Bit。


展开,输入$x,输出$z

$x = PHP_INT_MAX;
$y = (2 ** 32) - 1;
$z = ($x & $y) | ((($x & $y) >> 31) * ($y << 32));

var_dump($z);
相关问题