在MySQL中进行BIGINT转换

时间:2011-05-30 03:37:20

标签: mysql bigint

嘿所有,我认为这可能是一个错误,但它杀了我。我在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 unsigned并尝试以下内容:

DECLARE x BIGINT UNSIGNED;
SET x = (0x1ACE - 0x8000);

当我这样做时,我的x等于零。这并不奇怪,因为x是无符号的,结果是负的。然而,在百灵鸟上,我试过这个:

DECLARE x BIGINT UNSIGNED;
SET x = (0x1ACE - 0x8000) << 0;

令我惊讶的是,x被设置为0xFFFFFFFFFFFF9ACE!

有人可以帮忙吗?我已经在一个函数上工作了几个小时,除了有效地生成一个随机签名的BIGINT之外什么也没做,我很累,而且我越看这些东西,我越沮丧,我越不能理解它。任何帮助,无论是在解释这里发生了什么或建议写这个功能,以便它现在一贯工作,如果这是一个错误,在以后的版本,如果它得到修复,将不胜感激!

1 个答案:

答案 0 :(得分:2)

好吧,我想我只想出来了。根据{{​​3}},位移运算符导致无符号 64位整数。所以当你尝试:

DECLARE guid BIGINT;   -- signed BIGINT
SET guid = -25924;     -- = 0xFFFFFFFFFFFF9ABC
SET guid = guid << 0;  -- Result: 0x7FFFFFFFFFFFFFFF

正在发生的事情是为了guid&lt;&lt; 0返回一个无符号整数,它试图将guid从负有符号整数转换为无符号整数,产生0x7FFFFFFFFFFFFFFF,然后将其转移到零位,这是一个导致相同的标识操作0x7FFFFFFFFFFFFFFF。

然而,乘法(*)似乎可以在有符号和无符号数上正确工作。我可以通过以下方式实现我想要的结果:

DECLARE guid BIGINT;        -- signed BIGINT
SET guid = -25924;          -- = 0xFFFFFFFFFFFF9ABC
SET guid = guid * 0x10000;  -- = Result: 0xFFFFFFFF9ABC0000 Woot! \o/