Get order of magnitude of an integer in solidity

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.

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.

• Edit: I'd said "unsigned" instead of "signed"... – Richard Horrocks Jan 11 '17 at 16:35

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;
}
}
• As it currently stands, if input is 10, then counter is 0 instead of 1 (because of the while condition). – Richard Horrocks Jan 11 '17 at 10:57
• You could just remove the temp variable and use input in the calculation. – Richard Horrocks Jan 11 '17 at 10:58
• @RichardHorrocks Thanks. Yes it's a bit broken; also doesn't work with negative numbers. Going to delete answer an post in edited question. – atomh33ls Jan 11 '17 at 11:04
• @RichardHorrocks attempted to fix – atomh33ls Jan 11 '17 at 11:21
• Looks good :) I've added another answer that considers the size of the input - it may or may not be relevant, depending on how big you think the input will normally be. – Richard Horrocks Jan 11 '17 at 14:03
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.