位元操作子

lua-users home
wiki

Lua 5.3+ 具備對著名位元操作子的原生支援。(見 [§3.4.2])

從 5.2 版開始,Lua 附帶 [bit32] 函式庫,其中新增對位元操作的支援。之前版本的 Lua 沒有包含位元操作子,但 bit32 已回傳到 5.1 版。此外,也有相對應的 Lua 函式庫和一些 Lua 修補版本。

Lua 中的位元操作子實作

Lua BitOp (第 1.0.1 版) 說明

bit.tobit(x)          -- normalize number to the numeric range of
                      -- bit operations (all bit ops use this implicitly)
bit.tohex(x[,n])      -- convert x to hex with n digits (default 8)
bit.bnot(x)           -- bitwise not of x
bit.band(x1[,x2...])  -- bitwise and of x1, x2, ...
bit.bor(x1[,x2...])   -- bitwise or of x1, x2, ...
bit.bxor(x1[,x2...])  -- bitwise xor of x1, x2, ...
bit.lshift(x, n)      -- left-shift of x by n bits
bit.rshift(x, n)      -- logical right-shift of x by n bits
bit.arshift(x, n)     -- arithmetic right-shift of x by n bits
bit.rol(x, n)         -- left-rotate of x by n bits
bit.ror(x, n)         -- right-rotate of x by n bits
bit.bswap(x)          -- byte-swap of x (little-endian <-> big-endian)

bitlib (第 25 版) 說明

bit.bits           -- number of bits usable in bitwise operations
bit.bnot(a)        -- returns the one's complement of a
bit.band(w1, ...)  -- returns the bitwise and of the w's
bit.bor(w1, ...)   -- returns the bitwise or of the w's
bit.bxor(w1, ...)  -- returns the bitwise exclusive or of the w's
bit.lshift(a, b)   -- returns a shifted left b places
bit.rshift(a, b)   -- returns a shifted logically right b places
bit.arshift(a, b)  -- returns a shifted arithmetically right b places
bit.cast(a)        -- cast a to the internally-used integer type

bitlib 是用 C 撰寫的。內部而言,每組位元陣列都是以整數類型實作。授權採用 MIT 授權條款。

adt.bits (2009-04)

bits.create(value, number)     -- return bitmap of given size set to value
bits:set(value)                -- set all bits to value, return bitmap
bits:set(value, n1[,n2[n3,...]]) -- set these bits to value, return bitmap
bits:get(n)                    -- get value of this bit
bits:get(n1[,n2[n3,...]])      -- get value of these bits
bits:iterator()                -- return iterator for all bits => i,v
bits:iterator(n)               -- return iterator starting at bit n => i,v
bits:iterator(n1, n2)          -- return iterator over range [n1..n2] => i,v
bits:index(value)              -- return iterator => next index with the value
bits:index(value, start)       -- return index of next bit with the value
bits:isequal(b)  bits == b     -- return true or false for equality
bits:notbits()   - bits        -- return NOT of the bitmap
bits:orbits(b)   bits + b      -- return OR of the bitmaps
bits:andbits(b)  bits * b      -- return AND of the bitmaps
bits:xorbits(b)  bits % b      -- return XOR of the bitmaps
bits:orbits(n1, n2[, n3,...])  -- return OR of these bits
bits:andbits(n1, n2[, n3,...]) -- return AND of these bits
bits:xorbits(n1, n2[, n3,...]) -- return XOR of these bits
bits:copy()                    -- return a copy of the bitmap
bits:printlimit()              -- return current limit
bits:printlimit(n|"all"|"*")   -- set n or all bits printed, return new limit
bits:size(), #bits             -- return the bit capacity
bits:ones()                    -- return the number of 1 bits
bits.version()                 -- return the version of module

在 Lua 中反覆執行位元說明

function bit(p)
  return 2 ^ (p - 1)  -- 1-based indexing
end

-- Typical call:  if hasbit(x, bit(3)) then ...
function hasbit(x, p)
  return x % (p + p) >= p       
end

function setbit(x, p)
  return hasbit(x, p) and x or x + p
end

function clearbit(x, p)
  return hasbit(x, p) and x - p or x
end

這比較像實際函式庫的設計樣式。它是在 Lua 中實作的。內部而言,每組位元陣列都是以 Lua 數字實作。上述的原始運算提供簡單的程式碼,可對數字中的位元進行測試/設定/清除。位元運算可以定義為這些函式的條款。

LuaBit (第 0.4 版) 說明

bit.bnot(n) -- bitwise not (~n)
bit.band(m, n) -- bitwise and (m & n)
bit.bor(m, n) -- bitwise or (m | n)
bit.bxor(m, n) -- bitwise xor (m ^ n)
bit.brshift(n, bits) -- right shift (n >> bits)
bit.blshift(n, bits) -- left shift (n << bits)
bit.blogic_rshift(n, bits) -- logic right shift(zero fill >>>)

LuaBit 是完全用 Lua 撰寫的。內部而言,每組位元陣列都是以 Lua 數字或 Lua 數位陣列實作。此套件也包括用於將數字轉換為 16 進位字串或將 16 進位字串轉換為數字的函式,以及用於將 UTF8 轉換為 UCS2 字串的「utf8」模組,和與 Nokia 電腦有關的「noki」模組。授權採用 MIT 授權條款。

BinDecHex (2007-10) 說明

Hex2Bin(s)
Bin2Hex(s)
Hex2Dec(s)
Dec2Hex(s)
Bin2Dec(s)
Dec2Bin(s [, num])
BMAnd(v, m)
BMNAnd(v, m)
BMOr(v, m)
BMXOr(v, m)
BMNot(v, m) 

BinDecHex 是完全用 Lua 編寫的。內部而言,每組位元陣列都是以大端序形式的 Lua 字串實作。授權採用 BSD 授權條款。

BitUtils 說明

BitUtils 提供一些完全用 Lua 實作的程式碼片段。通常來說,內部而言,每組位元陣列都是以 Lua 數字實作。

位元運算元運算式 Power Patch 說明

Infix bitwise operators for AND (&, __and), OR (|, __or), XOR (^^, __xor).
Infix bitwise operators for SHIFT LEFT (<<, __shl) and SHIFT RIGHT (>>, __shr).
Unary bitwise negation operator (~, __not).
Infix arithmetic operator for INTEGER DIVISION (\, __intdiv).
    accepts both ~= and != for comparison. 

這是以 Lua 的補丁實作的。內部而言,每組位元陣列都是以 Lua 數字實作。運算元是視為語法延伸和 VM 操作碼提供 (包括元方法)。

RiscLua 說明

RiscLua 的 6 版以前版本,會使用 16 進位字面量並具有位元運算元,每個運算元都有相應的事件

x&y                __bit_and
x|y                __bit_or
x^^y               __bit_xor
~x                 __bit_not
-- also has arithmetic shifts:
x<<y              __bit_lshift
x>>y              __bit_rshift

這是以 Lua 的補丁實作的。內部而言,每組位元陣列都是以 Lua 數字實作。運算元是視為語法延伸和 VM 操作碼提供 (包括元方法)。此補丁並非獨立的,而是整合在 RiscLua 中。

hextype.patch 說明

| & ^^ << >> ~ \\ !=

這是以 Lua 的補丁實作的。內部而言,每組位元陣列都是以新的原值類型實作 (type(x) == 'hex'LUA_THEX),與「數字」不同。此類型在內部是無符號整數。運算元是視為語法延伸和 VM 操作碼提供 (包括元方法)。

枚舉/位元操作在 LuaPowerPatches 說明

-- example
local a1= enum.new( 0x10, "I'm A" )
assert( tonumber(a1)==16 )
assert( tostring(a1)=="0x10" )
assert( tonumber(a1"not")==4294967279 )
assert( tostring(a1"not")=="0xffffffef" )
local c1= enum.new( 10 )   -- I'm None!
assert( c1[3] == 1 )  -- 10 == 0x1010: bit 3 _is_ set

這是以 Lua 的補丁實作的。內部而言,每組位元陣列都是以新的原值類型實作 (type() 會傳回兩個值:「enum」和 enum 類別名稱)。enum 值具有過載的 []() 運算,可對 Lua 端的位元執行位元運算。

祈求

以上實作在兩個問題上有不同的處理方式(部分情況下甚至完全沒處理)

有一個實作假設為 32 位元整數,並提供有符號和無符號右位移。

另一個實作使用 long longunsigned long long,並依賴於 C 編譯器在每個情況下正確執行右位移(剛好對我來說在使用 gcc 的 x86 上執行得很好,但 C89 和 C99 沒有明確規定有符號右位移如何執行;這是「實作定義的行為」)。

另一個實作似乎完全忽略這個問題,交給 C 編譯器決定如何處理 lua_Integer

請注意,Java 在加入運算子時,定義 >> 運算子使用有符號擴充功能,而 >>> 運算子使用零擴充功能。

似乎沒有任一種實作提供便於攜帶的方式,可將任意大小的位元場轉換為有符號數字。

[這個] 修補程式會很棒,如果 bitfield 另外提供一個布林選項參數,表示結果應該有符號擴充功能至一個 lua_Integer 的完整大小。

順帶一提,這是一個為位元場進行有符號擴充功能的無分歧方式(Henry S. Warren Jr.,CACM v20 n6,1977 年 6 月)

sext = 1 << (len - 1); i = (i ^ sext) - sext;
假設 i 是右對齊的,且所有場左側的位元皆為零;前述要補強的修補程式中的情況就是這種情況(其中 sextp 是表示希望進行符號擴充功能的選用參數)
if (len < LI_BITS)
{ i &= LI_MASK(len);
  if (sextp) 
  { lua_Integer sext = 1 << (len - 1);
    i = (i ^ sext) - sext;
  }
}

目的

採用位元運算至少有兩個非常不同的原因:(1) 對一個小集合的成員進行組合運算,(2) 編輯定義在 Lua 程式外部的資料之明確表示形式中的欄位。位元運算子所參照的實作主要設計用於後者。對於前者的實作,請參閱 Asko 在 LuaPowerPatches 中的 Enum/bit 操作修補程式。

範例

以下是利用位元運算子(用例)的 Lua 程式碼範例

常見用途包括

意見

對於打算與 C/C++ 相介接的語言來說,奇妙的是位元運算子並非語法的一部分。當然,它們可以做為函式實作,但這很笨拙。請參閱 FeatureProposals

「如何執行位元運算?」是一個 LuaFaq 問題。

註:hex 文字在 Lua 5.1 中新增:0xfe。

Java 對稱為 EnumSet 的位元向量有一種抽象法 [1]。可以在 Lua 上執行類似的事情。


RecentChanges · preferences
edit · history
最後編輯時間:2020 年 6 月 2 日 下午 3:24 GMT (diff)