我正在尝试将十六进制转换为数字。如果我使用
SELECT To_Number('F8EF7F2C', 'xxxxxxxx') FROM dual;
结果是4176445228.这是qword结果。
我想得到的是dword结果-118522068
我如何实现这一目标?
谢谢,
更新
SELECT to_number('F8EF7F2C', 'xxxxxxxxxx')-Power(2,32) FROM dual
似乎适用于此值'F8EF7F2C'。但是将十六进制值更改为
SELECT to_number('0208A5FA', 'xxxxxxxxxx')-Power(2,32) FROM dual
产生错误的结果-4260846086。正确的结果是34121210,由
生成SELECT to_number('0208A5FA', 'xxxxxxxxxx') FROM dual
我可以在Dword程序员模式下验证PC计算器的正确结果。
答案 0 :(得分:2)
据我所知,你的qword是无符号的32位整数,而dword是带符号的32位整数。
这是一个带有一些十六进制值的小测试:
with hex as (
select '00000000' hex from dual union all
select '0208A5FA' hex from dual union all
select '7FFFFFFF' hex from dual union all
select '80000000' hex from dual union all
select 'F8EF7F2C' hex from dual union all
select 'FFFFFFFF' hex from dual
)
select hex.hex
, to_number(hex.hex,'XXXXXXXX') unsigned
, case
when to_number(hex.hex,'XXXXXXXX') >= power(2,31)
then to_number(hex.hex,'XXXXXXXX') - power(2,32)
else to_number(hex.hex,'XXXXXXXX')
end signed
, mod(
to_number(hex.hex,'XXXXXXXX') + power(2,31)
, power(2,32)
) - power(2,31) signed_alternative
from hex
order by hex.hex
/
查询的输出是:
HEX UNSIGNED SIGNED SIGNED_ALTERNATIVE
-------- ---------- ------------- ------------------
00000000 0 0 0
0208A5FA 34121210 34121210 34121210
7FFFFFFF 2147483647 2147483647 2147483647
80000000 2147483648 -2147483648 -2147483648
F8EF7F2C 4176445228 -118522068 -118522068
FFFFFFFF 4294967295 -1 -1
列SIGNED
的计算方式与@zerkms在评论中的建议相似,CASE
表达式仅用于在2^32
溢出时减去它。
列SIGNED_ALTERNATIVE
给出相同的结果,但首先添加2^31
,然后取模2^32
,然后再次减去2^31
。
CASE
表达式可能会更有效率,因为它对这些NUMBER
值执行的数值运算较少(如果它是浮点运算,模数版本可能会更快,因为它本来可以优化到位操作; - )