1

I've been debating on whether I should use < or <= in a for loop.

So I decided to conduct a small test and verify that their gas costs are the same.

Here is my contract:

pragma solidity 0.4.24;

contract MyContract {
    uint public value;
    function func1(uint x) external {
        for (uint i = 0; i < x; i++)
            value += i;
    }
    function func2(uint x) external {
        for (uint i = 0; i <= x; i++)
            value += i;
    }
}

And here is my Truffle test:

contract("MyContract", function(accounts) {
    it("func1", async function() {
        const myContract = await artifacts.require("MyContract").new();
        const response = await myContract.func1(11);
        console.log(response.receipt.gasUsed);
    });
    it("func2", async function() {
        const myContract = await artifacts.require("MyContract").new();
        const response = await myContract.func2(10);
        console.log(response.receipt.gasUsed);
    });
    it("func1", async function() {
        const myContract = await artifacts.require("MyContract").new();
        const response = await myContract.func1(101);
        console.log(response.receipt.gasUsed);
    });
    it("func2", async function() {
        const myContract = await artifacts.require("MyContract").new();
        const response = await myContract.func2(100);
        console.log(response.receipt.gasUsed);
    });
    it("func1", async function() {
        const myContract = await artifacts.require("MyContract").new();
        const response = await myContract.func1(1001);
        console.log(response.receipt.gasUsed);
    });
    it("func2", async function() {
        const myContract = await artifacts.require("MyContract").new();
        const response = await myContract.func2(1000);
        console.log(response.receipt.gasUsed);
    });
});

The results show in a conclusive manner that <= is cheaper than <:

Contract: MyContract func1: 94494
Contract: MyContract func2: 94436
Contract: MyContract func1: 567714
Contract: MyContract func2: 567386
Contract: MyContract func1: 5299978
Contract: MyContract func2: 5296950

Does that make any since at all? AFAIK, both operations (LT and LTE) cost 3 gas units!

I've disassembled the contract, here are the relevant parts:

For the < operation:

    /* "MyContract.sol":142:143  x */
  dup2
    /* "MyContract.sol":138:139  i */
  dup2
    /* "MyContract.sol":138:143  i < x */
  lt

For the <= operation:

    /* "MyContract.sol":247:253  i <= x */
  dup2
  dup2
  gt

They indeed look different (though mostly in the comments for some reason).

And to be honest, I'm not quite sure why gt is used in the <= case.

But other than that, it still doesn't strike me as to why the gas cost is different here.

For all it matters, I've used the default optimization settings (optimize-runs=200).

Thank you.

1

the answer lie in this article: https://link.medium.com/7oxDTDmKpZ

tl;dr: they are the same but the order of method_id make func1 more expensive than func2


Update: So i have try to my theory it seem like somehow it is the solidity function name problem. The reverse code:

pragma solidity ^0.5.0;

contract Test {
    uint public value;
    function func2(uint x) external {
        for (uint i = 0; i < x; i++)
            value += i;
    }

    function func1(uint x) external {
        for (uint i = 0; i <= x; i++)
            value += i;
    }
}

You can take a look at this screenshot: func1 and func2 change order

In the first test (the one above) you can see that if i use your the contract that you give, it give the result that func2 gas is less than func1 gas. But in the second test (the one below) you can see that if i use the reverse func contract, the func2 gas is still less than func1 gas. So that mean '<=' is not lower than the gas cost of '<'.

But the gas is inconsistant btw, if you compile the contract in remix, the func1 gas is less than func2 gas. So i think the problem is the way it compile the for loop not the < function

  • You mea their order in the tests? I doubt that, first of all, because I create a new contract instance at the beginning of each test. Second, because I've changed the order of the tests, and the results were identical. – goodvibration Aug 24 at 15:03
  • 1
    No @goodvibration, you get the wrong idea. The problem it is in your solidity code. The func1(uint) method_id is: 9c797079 and func2(uint) method_id is: 76ffc5c6. So because func2 method_id is less than func1 method_id so func2 will cost less gas than func1 you can read more in the link – haxerl Aug 24 at 15:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.