ya que es la diferencia entre un ciclo con una división (operacion matematica simple posible de hacer por el procesador con un solo paso)
Perdón por la intromisión, pero la división es la operación más costosa con diferencia de las interpretadas como básicas: suma, resta, producto, división. Y cuando digo costosa me refiero en una proporción que puede llegar a ser de 8 a 1.
Dicho esto me ha surgido la duda de saber cual era el algoritmo más óptimo... manos a la obra salió algo tal que:
#include <iostream>
#include <chrono>
#include <math.h>
int DigitosV1( int numero )
{
int digitos;
for ( digitos = 0; numero > 0; digitos++, numero /= 10 ) ;
return digitos;
}
int DigitosV2( int numero )
{
return log( numero ) + 1;
}
const int NUMERO = 1234567890;
const int MAXBUCLE = 1000000000;
int main( )
{
int temp;
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now( );
for ( int i=0; i < MAXBUCLE; i++ )
{
temp = DigitosV1( NUMERO );
}
end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
std::cout << "Tiempo division: " << elapsed_seconds.count() << "s\n";
start = std::chrono::system_clock::now( );
for ( int i=0; i < MAXBUCLE; i++ )
{
temp = DigitosV2( NUMERO );
}
end = std::chrono::system_clock::now();
elapsed_seconds = end-start;
std::cout << "Tiempo logaritmo: " << elapsed_seconds.count() << "s\n";
}
¿Qué sucede con los resultados? Son contundentes
(aviso, abstenerse personas sensibles):
Editado: Estos resultados son con el programa compilado en modo debug... lo siento.Tiempo division: 43.1613s
Tiempo logaritmo: 29.538s
Luego por 5 cabezas de ventaja, la opción del logaritmo es más óptima que la opción de la división.
Edito: Para probar opciones menos extremistas, he reducido el número de prueba a uno con 5 dígitos y he ejecutado el programa... los resultados son los siguientes:
Editado: Estos resultados son con el programa compilado en modo debug... lo siento.Tiempo division: 19.1429s
Tiempo logaritmo: 29.564s
Se ve por tanto que la opción del logaritmo es estable en el tiempo, mientras que la división, obviamente, ha reducido su tiempo a la mitad ( tiene la mitad de dígitos ).
Dicho esto me surgió una nueva duda... log trabaja con "double"... y si la idea es trabajar con números más grandeS??
Un poco de refactorización y listo:
#include <iostream>
#include <chrono>
#include <limits>
#include <math.h>
const int INT5 = 12345;
const int INT7 = 1234567;
const int INT10 = 1234567890;
const double DOUBLE5 = 12345.0;
const double DOUBLE7 = 1234567.0;
const double DOUBLE10 = 1234567890.0;
template< class T >
int DigitosDIV( T numero )
{
int digitos;
T divisor = 10;
T min = 1; // para que el bucle funcione con decimales
for ( digitos = 0; numero >= min; digitos++, numero /= divisor ) ;
return digitos;
}
template< class T >
int DigitosLOG( T numero )
{
return log( numero ) + 1;
}
template< class T >
std::chrono::duration< double > Bucle( T numero, int(*func)(T) )
{
int temp;
auto start = std::chrono::system_clock::now( );
const int max = std::numeric_limits< int >::max( );
for ( int i=0; i < max; i++ )
{
temp = func( numero );
}
auto end = std::chrono::system_clock::now( );
return end - start;
}
int main( )
{
auto DivInt5 = Bucle( INT5, DigitosDIV< int > );
auto DivInt7 = Bucle( INT7, DigitosDIV< int > );
auto DivInt10 = Bucle( INT10, DigitosDIV< int > );
auto LogInt5 = Bucle( INT5, DigitosLOG< int > );
auto LogInt7 = Bucle( INT7, DigitosLOG< int > );
auto LogInt10 = Bucle( INT10, DigitosLOG< int > );
auto DivDouble5 = Bucle( DOUBLE5, DigitosDIV< double > );
auto DivDouble7 = Bucle( DOUBLE7, DigitosDIV< double > );
auto DivDouble10 = Bucle( DOUBLE10, DigitosDIV< double > );
auto LogDouble5 = Bucle( DOUBLE5, DigitosLOG< double > );
auto LogDouble7 = Bucle( DOUBLE7, DigitosLOG< double > );
auto LogDouble10 = Bucle( DOUBLE10, DigitosLOG< double > );
std::cout << "Tiempo division (int 5): " << DivInt5.count( ) << " s\n";
std::cout << "Tiempo division (int 7): " << DivInt7.count( ) << " s\n";
std::cout << "Tiempo division (int 10): " << DivInt10.count( ) << " s\n\n";
std::cout << "Tiempo log (int 5): " << LogInt5.count( ) << " s\n";
std::cout << "Tiempo log (int 7): " << LogInt7.count( ) << " s\n";
std::cout << "Tiempo log (int 10): " << LogInt10.count( ) << " s\n\n";
std::cout << "Tiempo division (double 5): " << DivDouble5.count( ) << " s\n";
std::cout << "Tiempo division (double 7): " << DivDouble7.count( ) << " s\n";
std::cout << "Tiempo division (double 10): " << DivDouble10.count( ) << " s\n\n";
std::cout << "Tiempo log (double 5): " << LogDouble5.count( ) << " s\n";
std::cout << "Tiempo log (double 7): " << LogDouble7.count( ) << " s\n";
std::cout << "Tiempo log (double 10): " << LogDouble10.count( ) << " s\n\n";
}
Y su correspondiente resultado (ahora sí en modo release):
Tiempo division (int 5): 23.6144 s
Tiempo division (int 7): 33.9994 s
Tiempo division (int 10): 49.798 s
Tiempo log (int 5): 60.28 s
Tiempo log (int 7): 60.415 s
Tiempo log (int 10): 60.8651 s
Tiempo division (double 5): 81.3541 s
Tiempo division (double 7): 113.471 s
Tiempo division (double 10): 162.253 s
Tiempo log (double 5): 60.7651 s
Tiempo log (double 7): 60.8521 s
Tiempo log (double 10): 60.7481 s
La conclusión final... cada uno que saque las suyas... pero simplificando yo obtengo las siguientes:
* El logaritmo es más estable... ideal para tareas de tiempo real.
* La división es, de media, más rápida si se trabaja con enteros... el logaritmo es más eficiente con decimales.
* Es curioso como se nota la bajada de tiempos de la división en modo release frente a modo debug