哪種寫法更省 gas

0x01 有趣的問題

有人提出這么個問題,下面哪種寫法更省 gas

 function mul(uint256 x) public pure returns (uint256) {
      return x * x * x;
 }

 function exp(uint256 x) public pure returns (uint256) {
      return x ** 3;
 }

0x02 如何分析

兩個寫法最終的差別體現(xiàn)在是用運(yùn)算符 " * " 還是 " ** " 上。
運(yùn)算符 " * " 最終會用到 EVM 指令 MUL
運(yùn)算符 " ** " 最終會用到 EVM 指令 EXP
對于 MUL 和 EXP 兩個指令的消耗,我們可以查表:https://ethereum.org/en/developers/docs/evm/opcodes/
通過查表得知,MUL 指令一次消耗的 gas 是 5,兩次 MUL 消耗的 gas 就是 10
EXP 指令的消耗有個動態(tài)計(jì)算公式

gas_cost = 10 + 50 * byte_len_exponent

" x ** 3 " 所用到 EXP 指令的消耗就是 10 + 50 * 1 = 60

但是不是這就意味著 "mul" 這個函數(shù)比 "exp" 這個函數(shù)更省 gas 呢?

0x03 實(shí)證

把代碼在 remix 運(yùn)行,當(dāng)輸入為 100 時,“exp” 的消耗是 1052


image.png

“mul” 的消耗是 1084


image.png

“exp” 函數(shù)比 "mul" 更省 gas,為啥呢?
這是因?yàn)?“ x * x * x" 這種寫法需要更多的中間指令,如果對比 "x * x" 和 "x ** 2" 就會發(fā)現(xiàn) "x * x" 要更省 gas 了。

但是,當(dāng)我們把輸入改為 1000 時,“exp“ 的消耗變?yōu)?1293


image.png

而 “mul” 的消耗仍然為 1084


image.png

這是為啥呢?

Solidity 的官方 blog https://blog.soliditylang.org/2020/12/16/solidity-v0.8.0-release-announcement/ 有這么一段話:

For bases up to 306, if the exponent is smaller than a hard-coded safe upper bound, it will use the exp opcode directly. If the base or the exponent is too large, it might fall back to the loop-based implementation.

明白了么?如果基數(shù)大小超過 306,solidity 會使用 MUL 而不是 EXP 指令,消耗了比直接用 MUL 更多的 gas。

如果我們不希望 solidity 為我們做這樣的處理,可以使用 assembly:

 function exp(uint256 x) public pure returns (uint256) {
      assembly {
        mstore(0x0, exp(x, 0x3))
        return (0x0, 32)
      }
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容