[英]Truncate 64Bit Integer to 32Bit and simulate value
我正在尝试编写一种算法,以通过截断将64Bit整数转换为32Bit,并返回准确表示32Bit值的值。 明显的问题是PHP中的整数只有64Bit(禁止32Bit系统)。
我首先尝试了以下方法:
$x = $v & 0xFFFFFFFF
因此,如果$v = PHP_INT_MAX
,则$x
是4294967295
,当我真正想要-1
。 我知道这样做的原因是,当用64Bit整数表示时,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导出此值,然后将其屏蔽到64Bit整数的MSB上。 这就是我现在想要弄清楚的,尽管我试图避免创建怪物方程。
使用按位运算可能是一种更优雅/有效的方法,但是您也可以使用pack()
和unpack()
强制转换。 例如:打包为未签名,解压缩为已签名。
function overflow32($in) {
return unpack('l', pack('i', $in & 0xFFFFFFFF))[1];
}
var_dump( overflow32(pow(2,33)-1) ); // int(-1)
我很好奇您将此应用到什么应用程序,因为几年前当我将应用程序从32位计算机迁移到64位计算机时,我不得不用同样的方法破坏哈希函数,但是我不记得是什么它是。
编辑:哇,由于某种原因,我记得Two's Complement很辛苦。 从字面上看,只需反转并添加一个即可。
function overflow32($in) {
if( $in & 0x80000000 ) {
return ( ( ~$in & 0xFFFFFFFF) + 1 ) * -1;
} else {
return $in & 0xFFFFFFFF;
}
}
var_dump( kludge32(pow(2,33)-1) );
编辑2:我看到您想将此扩展为任意位长度,在这种情况下,您只需要计算掩码即可,而不是显式设置掩码:
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)
);
我留在debug var_dump()
以获取输出风格:
string(32) "10000000000000000000000000000000"
string(32) "10000000000000000000000000000000"
string(32) "11111111111111111111111111111111"
string(16) "1000000000000000"
string(16) "1000000000000000"
string(16) "1111111111111111"
string(8) "10000000"
string(8) "10000000"
string(8) "11111111"
int(-2147483648)
int(-32768)
int(-128)
我想我已经破解了:
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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.