天天看點

labview實作異或運算_Solidity位運算:與、或、非、異或、移位

Solidity位操作運算有助于縮減以太坊交易的成本。本文介紹以太坊智能合約開發語言 Solidity中的位操作運算符,以及如何使用這些Solidity位操作符對合約資料執 行位操作運算,例如與、或、非、異或等,同時也介紹如何實作Soldity不支援 的取反、移位等操作。

1、Solidity位操作概述

以太坊是一台世界計算機, 雖然可能是最昂貴的那台。由于存儲是最消耗gas的操作,是以時不時地需要精打細算, 進行一些位操作,就像彙編開發者在晶片固件程式設計時所做的一樣。這可以讓你對資料有 更多的控制并最終縮減交易成本。

以太坊智能合約開發語言Solidity支援基本的位操作運算,雖然目前還不支援左/右 位移。幸運的是有等價的算數運算。

所有的位操作都是逐位執行的,就和你比較兩個不同的數組成員一樣,都會 按順序逐位操作。注意:在位操作中0和1,分别對應false和true。

出于簡化考慮,我将使用bytes1類型(和byte一樣),不過更長的資料類型也是 同樣的原理。在下面的例子中我們都是用相同的兩個變量a和b:

labview實作異或運算_Solidity位運算:與、或、非、異或、移位

在Solidity中,我們使用16進制表示的值來初始化這兩個變量:

12bytes1 a = 0xb5; // [10110101]bytes1 b = 0x56; // [01010110]
           

2、與運算/AND

兩個變量中都是1的位,其與計算/AND結果位才是1,否則都是0:

labview實作異或運算_Solidity位運算:與、或、非、異或、移位

上圖中黃色部分表示計算結果,可以看到隻有當兩個輸入變量a和b的對應位 都是1時,結果的響應位才是1。

在Solidity中,與操作符是&:

1a & b; // 結果: 0x14 [00010100]
           

3、或運算/OR

在計算或操作結果的某一位時,隻要任何一個輸入變量的對應位是1, 那麼結果都是1:

labview實作異或運算_Solidity位運算:與、或、非、異或、移位

在Solidity中,或操作符是|:

1a | b; // 結果: 0xf7 [11110111]
           

4、異或運算/XOR

在計算異或運算結果的某一位時,隻有當兩個輸入變量的對應位不一緻 時,結果才是1:

labview實作異或運算_Solidity位運算:與、或、非、異或、移位

在Solidity中,異或操作符時^:

1a ^ b; // 結果: 0xe3 [11100011]
           

異或運算有趣的一點是,你把結果和任意一個輸入變量再做異或運算, 就可以得到另一個輸入變量:

10xe3 ^ a; // 結果: 0x56 == b [01010110]
           

5、非運算/NEG

非運算是單目運算,隻需要一個輸入變量,它就是取反,原來是1結果 就是0,原來是0結果就是1:

labview實作異或運算_Solidity位運算:與、或、非、異或、移位

Solidity本身并不支援非運算,不過幸運的是你可以将變量與全1值 異或,就得到同樣的結果:

1a ^ 0xff; // Result: 0x4a [01001010]
           

6、移位運算/SHIFT

位移運算指的是向左或向右移動輸入變量的位。

讓我們先用十進制數來舉個例子。例如對于下面的數值:

100001230
           

向左位移3位就得到:

101230000
           

換句話說,向左移動3位其實就是将原來的數乘以10的3次方。

同樣,如果我們繼續向右移動4位,結果就和将輸入變量除以10的4次方一樣:

100000123
           

上面的原理對于二進制移位運算也是适用的,是以當我們向左 移N位時,就等價于乘以2的N次方;向右移M位時,就等價于除以2 的M次方。

由于Solidity目前不支援移位運算,是以我們需要借助于算數運算 來實作同樣的效果。

6.1 左移位

labview實作異或運算_Solidity位運算:與、或、非、異或、移位

示例代碼如下:

1234var n = 3; var aInt = uint8(a); // Converting bytes1 into 8 bit integervar shifted = aInt * 2 ** n;bytes1(shifted); // Back to bytes. Result: 0xa8 [10101000]
           

6.2 右移位

labview實作異或運算_Solidity位運算:與、或、非、異或、移位

示例代碼如下:

1234var n = 2; var aInt = uint8(a); // Converting bytes1 into 8 bit integervar shifted = aInt / 2 ** n;bytes1(shifted); // Back to bytes. Result: 0x2d [00101101]
           

7、提取前N位

我們可以使用與操作來提取變量的前N位,方法就是建立一個掩碼變量, 其前N位都是1:

labview實作異或運算_Solidity位運算:與、或、非、異或、移位

示例代碼如下:

1234var n = 5;var nOnes = bytes1(2 ** n - 1); // Creates 5 1svar mask = shiftLeft(nOnes, 8 - n); // Shift left by 3 positionsa & mask; // Result: 0xb0 [10110000]
           

8、提取後N位

利用對2取模計算就可以提取變量的後N位,例如:

123var n = 5;var lastBits = uint8(a) % 2 ** n;bytes1(lastBits); // Result: 0x15 [00010101]
           

9、資料壓縮

有了上面的基礎,我們就可以使用更少的存儲空間來減少交易成本。 例如,假設有兩個變量其實都是隻利用了4位,那麼我們可以将其 壓縮到一個變量裡:

labview實作異或運算_Solidity位運算:與、或、非、異或、移位

示例代碼如下:

123bytes1 c = 0x0d;bytes1 d = 0x07;var result = shiftLeft(c, 4) | d; // 0xd7 [11010111]
           

完整源代碼

下面是本文内容的完整源代碼:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061contract BitsAndPieces {  function and(bytes1 a, bytes1 b) returns (bytes1) { return a & b; }  function or(bytes1 a, bytes1 b) returns (bytes1) { return a | b; }  function xor(bytes1 a, bytes1 b) returns (bytes1) { return a ^ b; }  function negate(bytes1 a) returns (bytes1) { return a ^ allOnes(); }  function shiftLeft(bytes1 a, uint8 n) returns (bytes1) { var shifted = uint8(a) * 2 ** n; return bytes1(shifted); }  function shiftRight(bytes1 a, uint8 n) returns (bytes1) { var shifted = uint8(a) / 2 ** n; return bytes1(shifted); }  function getFirstN(bytes1 a, uint8 n) returns (bytes1) { var nOnes = bytes1(2 ** n - 1); var mask = shiftLeft(nOnes, 8 - n); // Total 8 bits return a & mask; }   function getLastN(bytes1 a, uint8 n) returns (bytes1) { var lastN = uint8(a) % 2 ** n; return bytes1(lastN); }   // Sets all bits to 1 function allOnes() returns (bytes1) { return bytes1(-1); // 0 - 1, since data type is unsigned, this results in all 1s. }  // Get bit value at position function getBit(bytes1 a, uint8 n) returns (bool) { return a & shiftLeft(0x01, n) != 0; }  // Set bit value at position function setBit(bytes1 a, uint8 n) returns (bytes1) { return a | shiftLeft(0x01, n); }  // Set the bit into state "false" function clearBit(bytes1 a, uint8 n) returns (bytes1) { bytes1 mask = negate(shiftLeft(0x01, n)); return a & mask; } }
           

原文:Solidity位操作 - 彙智網