Obtener orden de magnitud de un número entero en solidez

¿Cuál es una forma de obtener el orden de magnitud de un número entero (o flotante) en un contrato de solidez?

por ejemplo tal que

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

Idealmente en la menor cantidad de gas usando la forma posible...

Esto es lo que tengo:

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;
    }
}

Esto no funciona con números negativos o, como señaló @RichardHorrocks, cuando la entrada es 10.

Respuestas (3)

Pensando un poco más en esto...

Su código toma un (firmado) int256como entrada. El valor máximo (absoluto) de esto es alrededor de 1e+76, lo que equivaldría a 76 ciclos del whileciclo, cada uno compuesto por múltiples instrucciones.

En tales casos, probablemente sería más barato usar un método logarítmico , es decir, tomar el log 10 de la entrada e ignorar cualquier parte fraccionaria. (Digo "probablemente", no lo he comprobado).

Dependerá de los valores que espera inputtomar normalmente y de la rapidez con la que el algoritmo logarítmico converge en una respuesta.

Editar: dije "sin firmar" en lugar de "firmado" ...

Así es como lo hice. Probablemente hay margen significativo para la mejora. Aceptaría cualquier respuesta que use menos 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;
}
}
Tal como está actualmente, si inputes 10, entonces counteres 0 en lugar de 1 (debido a la whilecondición).
Simplemente puede eliminar la tempvariable y usarla inputen el cálculo.
@RichardHorrocks Gracias. Sí, está un poco roto; Tampoco funciona con números negativos. Voy a eliminar la respuesta a una publicación en la pregunta editada.
@RichardHorrocks intentó arreglar
Se ve bien :) He agregado otra respuesta que considera el tamaño de la entrada: puede ser relevante o no, dependiendo de qué tan grande crea que la entrada será normalmente.
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;
}

Esta implementación utiliza algoritmos de bisección y exponenciación mediante el cuadrado, tiene una complejidad O(ln^2 n) y consume alrededor de 6,5K de gas. Sin embargo, parece que el enfoque O (n) sugerido por @ atomh33ls es más barato.