无符号整数

简介: 无符号整数

整型表示中使用一个 比特 来存储符号位。因此, 64 位整型数最大可以表示 263-1 而不是 264-1 。通常,这点区别并无关紧要,因为 263-1 已经很大了。不过,由于我们可能需要处理使用无符号整型表示的外部数据或实现一些需要 64 位整型数的算法,因而有时也不能浪费这个符号位。此外,在精简 Lua 中,这种区别可能会很重要。例如,如果用一个 32 位有符号整型数表示文件中的位置,那么能够操作的最大文件大小就是 2GB ;而一个无符号整型能操作的最大文件大小则是有符号整型数的 2 倍,即 4GB


Lua 语言不显式支持无符号整型数。不过尽管如此,只要稍加注意,在 Lua 语言中处理无符号整型数并不难。


虽然看上去不太友好,但可以直接写出比 263-1 大的常量:

> x = 13835058055282163712      -- 3 << 62
> x                             --> -4611686018427387904


这里的问题并不在于常量本身,而在于 Lua 语言输出常量的方式;默认情况下,打印数值时是将其作为有符号整型数进行处理的。我们可以使用选项 %u%x 在函数 string.format 中指定以无符号整型数进行输出:

> string.format("%u", x)        --> 13835058055282163712
> string.format("0x%X", x)      --> 0xC0000000000000000


根据有符号整型数的表示方式( 2补码),加法减法乘法操作对于有符号整型数和无符号整型数是一样的:

> string.format("%u", x)        --> 13835058055282163712
> string.format("%u", x + 1)    --> 13835058055282163713
> string.format("%u", x - 1)    --> 13835058055282163711


提示

对于这么大的数,即便 x 乘以 2 也会溢出,所以示例中没有演示乘法。


关系运算对于有符号整型数和无符号整型数是不一样的,当比较具有不同符号位的整型数时就会出现问题。对于有符号整型数而言,符号位被置位的整数更小,因为它代表的是负数:

> 0x7fffffffffffffff < 0x8000000000000000       --> false


如果把这两个整数都当做无符号的,那么结果显然是不正确的。因此,我们需要一种不同的操作来比较无符号整型数。 Lua5.3 提供了函数 math.ultunsigned less than)来完成这个需求:

> math.ult(0x7fffffffffffffff < 0x8000000000000000)       --> true


另一种方法是在进行有符号比较前先用掩码掩去两个操作数的符号位:

> mask = 0x8000000000000000
> (0x7fffffffffffffff ~ mask) < (0x8000000000000000 ~ mask)     --> true点击复制复制失败已复制


无符号除法和有符号除法也不一样,如下所示给出了一种无符号除法的算法:

function udiv(n, d)
  if d < 0 then
    if math.ult(n, d) then 
      return 0 
    else 
      return 1
    end
  end
  local q = ((n >> 1) // d) << 1
  local r = n - q * d
  if not math.ult(r, d) then q = q + 1 end
  return q
end


第一个比较( d < 0 )等价于比较 d 是否大于 263 。如果大于,那么商只能是 1 (如果 n 等于或大于 d )或 0 。否则,我们是被除数除以 2 ,然后除以整数,再把结果乘以 2 。右移一位等价于除以 2 的无符号除法,其结果是一个非负有符号整型数。后续的左移则纠正了商,还原了之前的除法。


总体上说, floor(floor(n/2)/d)*2 (算法进行的计算)与 floor(((n/2)/d)*2) (正确的结果)并不等价。不过,要证明他们之间最多相差 1 并不困难。因此,算法计算了余数(变量 r ),然后判断余数是否比除数大,如果余数比除数大则纠正商(加一)即可。


无符号整型数和浮点数之间的转换需要进行一些调整。要把一个无符号整型数转换为浮点型数,可以先将其转换成有符号整型数,然后通过取模运算纠正结果:

> u = 11529215046068469760      -- 一个示例
> f = (u + 0.0) % 2^64
> string.format("%.0f", f)      --> 11529215046068469760


由于标准转换把 u 当做有符号整型数,因此表达式 u+0.0 的值是 -6917529027641081856 ,而之后的取模操作会把这个值限制在有符号整型数的表示范围内(在实际的代码中,由于涉及浮点型数的取模运算肯定会进行类型转换,所以并不需要进行这次加法运算)。


要把一个浮点型数转换为无符号整型数,可以使用如下的代码:

> f = 0xA000000000000000.0                          -- 一个示例
> u = math.tointeger(((f + 2^63) % 2^64) - 2^63)
> string.format("%x", u)                            --> a000000000000000点击复制复制失败已复制


加法把一个大于 263 的数转换为一个大于 264 的数,取模运算把这个数限制到 [0, 263) 范围内,然后通过减法把结果变成一个“”值(即最高位置位的值)。对于小于 263 的值,加法结果小于 264 ,所以取模运算没有任何效果,之后的减法则把它恢复到了之前的值。

目录
相关文章
|
2月前
|
存储 Python
整数和浮点数。
整数和浮点数。
25 7
|
6月前
|
编译器 C++
【C/C++】C/C++编程——整型(二)
【C/C++】C/C++编程——整型(二)
73 2
|
6月前
|
存储 编译器 C++
【C/C++】C/C++编程——整型(一)
【C/C++】C/C++编程——整型(一)
61 1
|
6月前
|
存储
进制转换和整型提升
进制转换和整型提升
|
C语言
整型提升
整型提升
88 0
|
C语言
整数和浮点数的任意进制转!!(包括16进制)确定不进来看看?!
整数和浮点数的任意进制转!!(包括16进制)确定不进来看看?!
150 0
|
C语言
整形提升详解
整形提升详解
152 0
【整型提升问题】
整型提升: 在计算机中,一个数据的类型如果是char 类型,以整型的形式打印该char类型的值时,会自动转换成整型,叫做整型提升。 整型提升的规则: 整型提升是按照变量的数据类型的符号位来提升 举例说明整型提升的存在:
|
算法 C语言
5.1.3_无符号整数的表示和运算
计算机组成原理之无符号整数的表示和运算
704 0
5.1.3_无符号整数的表示和运算