3

What is a way of getting the order of magnitude of an integer (or float) in a solidity contract?

e.g. such that

MyContract.getOrderMag(2564)   returns 3
MyContract.getOrderMag(987)   returns 2
MyContract.getOrderMag(2.3e76)   returns 76

Ideally in the least gas using way possible...

Here's what I have:

pragma solidity ^0.4.6;
contract Magger {  
    function getOrderMag(int256 input) constant returns (int256){
        int counter=0;
        int temp = input;
        while((temp/10)>1){
            temp = temp/10;
            counter++;
        }
        return counter;
    }
}

This doesn't work with negative numbers or, as pointed out by @RichardHorrocks, when input is 10.

q9f
  • 32,913
  • 47
  • 156
  • 395
Lee
  • 8,548
  • 6
  • 46
  • 80

3 Answers3

2

Just thinking about this a bit more...

Your code takes a (signed) int256 as input. The maximum (absolute) value of this is around 1e+76, which would equate to 76 cycles of the while loop, each composed of multiple instructions.

In such cases it would probably be cheaper to use a logarithmic method - i.e. take the log10 of the input and ignore any fractional parts. (I say "probably" - I haven't checked.)

It will depend on the what values you expect input to usually take, and how quickly the logarithm algorithm converges on an answer.

Richard Horrocks
  • 37,835
  • 13
  • 87
  • 144
1

Here's how I did it. There is probably significant scope for improvement. I would accept any answer that uses less gas:

pragma solidity ^0.4.6;
contract Magger {  

    function getOrderMag(int256 input) constant returns (int256){
        int counter=0;
        if (input<0){
            input=input*-1;
        }
            while((input/10)>=1){
                input = input/10;
                counter++;
            }

        return counter;
}
}
Lee
  • 8,548
  • 6
  • 46
  • 80
1
function magnitude (uint x) public pure returns (uint) {
  require (x > 0);

  uint a = 0;
  uint b = 77;

  while (b > a) {
    uint m = a + b + 1 >> 1;
    if (x >= pow10 (m)) a = m;
    else b = m - 1;
  }

  return a;
}

function pow10 (uint x) private pure returns (uint) {
    uint result = 1;
    uint y = 10;
    while (x > 0) {
      if (x % 2 == 1) {
        result *= y;
        x -= 1;
      } else {
        y *= y;
        x >>= 1;
      }
    }
    return result;
}

This implementation uses bisection and exponentiation by squaring algorithms, has O(ln^2 n) complexity and consumes about 6.5K gas. Though, it seems that O(n) approach as suggested by @atomh33ls is cheaper.

Mikhail Vladimirov
  • 7,313
  • 1
  • 23
  • 38