大家好,我认为这可能是一个错误,但它正在杀死我。我在 Ubuntu Linux 服务器上使用 MySQL 5.1.41。我正在尝试编写一个函数来创建一个随机签名的 BIGINT 值。因为 RAND() 的精度太小,无法生成所有可能的 BIGINT 值,所以我决定尝试使用位运算符组合四个 32 位字。
我启动了 MySQL Workbench,并尝试了以下操作以查看移位运算符是否可以正确处理负数:
SELECT HEX((0x1ACE - 0x8000) << 0x10);
0x1ACE - 0x8000 是 -25906,所以如果我向左移动 16 位,我应该乘以 65536,对吗?我得到的答案是 0xFFFFFFFF9ACE0000,它是 -1697775616 或 -25906 * 65536 的有符号表示。Wunderbar,它有效!
所以我的计划是使用它来生成随机符号 BIGINT 的第一个 32 位字,并使用一个简单的循环将另外三个 32 位字添加到该值中,一次将这些位移动四个字节。令人兴奋的是,我首先将以下代码放入我的函数中,使用硬编码值来测试我的计划:
DECLARE x BIGINT;
SET x = (0x1ACE - 0x8000) << 0x10;
如果我设置该值以使被移动的值为正,则一切正常。但是,在使用移位的负值(在本例中为 -25906)执行此计算后,我一直得到 x 为 0x7FFFFFFFFFFFFFFF,这是有符号 64 位整数的最大正值。我完全感到困惑。完全相同的操作会产生完全不同的结果,具体取决于它是在函数中的 SET 操作中还是在 SELECT 语句中。
所以我开始搞乱 x 是签名还是未签名,事情变得非常奇怪。我尝试使 x 无符号并尝试以下操作:
DECLARE x BIGINT UNSIGNED;
SET x = (0x1ACE - 0x8000);
当我这样做时,我得到的 x 等于零。这并不奇怪,因为 x 是无符号的并且结果是负数。但是,在云雀上,我尝试了这个:
DECLARE x BIGINT UNSIGNED;
SET x = (0x1ACE - 0x8000) << 0;
令我惊讶的是,x 被设置为 0xFFFFFFFFFFFF9ACE!
有人可以帮忙吗?我已经在一个函数上工作了好几个小时,它只不过是有效地生成一个随机签名的 BIGINT,我很累,我越看这些东西,我就越沮丧,我对它的理解就越少. 任何帮助,无论是解释这里发生了什么,还是建议编写这个函数,以便它现在可以始终如一地工作,如果这是一个错误,如果它得到修复,在以后的版本中,将不胜感激!