Una vez hice una pregunta relacionada: ¿Cómo puedes obtener el primer dígito en un int? Muchas de las mismas metodologías que a continuación se utilizaron en las respuestas de las personas. Aquí está el enlace en caso de que sea relevante para su tarea [ stackoverflow.com/questions/701322/]
Dinah
¿El montaje en línea califica?
György Andrasek
1
Si bien todas estas respuestas están en términos de base 10, es bastante fácil de cambiar para calcular el resultado para cualquier base deseada.
Ira Baxter
Respuestas:
106
Bueno, la forma más eficiente, suponiendo que conozca el tamaño del número entero, sería una búsqueda. Debería ser más rápido que el enfoque basado en el logaritmo mucho más corto. Si no le importa contar el '-', elimine el + 1.
// generic solutiontemplate<class T>int numDigits(T number){int digits =0;if(number <0) digits =1;// remove this line if '-' counts as a digitwhile(number){
number /=10;
digits++;}return digits;}// partial specialization optimization for 32-bit numberstemplate<>int numDigits(int32_t x){if(x == MIN_INT)return10+1;if(x <0)return numDigits(-x)+1;if(x >=10000){if(x >=10000000){if(x >=100000000){if(x >=1000000000)return10;return9;}return8;}if(x >=100000){if(x >=1000000)return7;return6;}return5;}if(x >=100){if(x >=1000)return4;return3;}if(x >=10)return2;return1;}// partial-specialization optimization for 8-bit numberstemplate<>int numDigits(char n){// if you have the time, replace this with a static initialization to avoid// the initial overhead & unnecessary branchstaticchar x[256]={0};if(x[0]==0){for(char c =1; c !=0; c++)
x[c]= numDigits((int32_t)c);
x[0]=1;}return x[n];}
Probablemente más rápido que mi respuesta, bien hecho. Para mayor eficiencia, si sabe que sus números de entrada serán en su mayoría pequeños (supongo que menos de 100,000), entonces invierta las pruebas: si (x <10) devuelve 1; si (x <100) devuelve 2; etc., para que la función haga menos pruebas y salga más rápido.
squelart
29
O quizás reordene y anide las declaraciones if, para hacer una búsqueda binaria en lugar de una búsqueda lineal.
dave4420
1
Esa no es una buena idea. Qué sucede cuando la arquitectura se expande a enteros de 256 bits. Debe recordar volver y modificar este código. En la vida real, eso no sucederá y, probablemente, esto se usará para construir un búfer del tamaño correcto, ahora se está abriendo a todo tipo de problemas de búfer por ejecución en arquitecturas más grandes.
Martin York
3
suponiendo una distribución uniforme de números, la búsqueda lineal inversa (comenzando desde los dígitos máximos hasta 1) puede ser más rápida en promedio que la búsqueda binaria, ya que hay muchos más números con N dígitos que con N-1 dígitos graphics.stanford.edu/~ seander / ...
fa.
66
No me preocuparía mucho por los enteros de 256 o 128 bits. A menos que necesite contar la cantidad de electrones en el Universo (10 ^ 78 la última vez que lo hice), 64 bits funcionarán bastante bien. Las máquinas de 32 bits duraron ~~ 15 años. Supongo que las máquinas de 64 bits durarán mucho más. Para un número mayor, la aritmética de multiprecisión estará bien, y dudo si la eficiencia del cómputo de dígitos computacionales será importante.
Ira Baxter
74
La forma más simple es hacer:
unsignedGetNumberOfDigits(unsigned i){return i >0?(int) log10 ((double) i)+1:1;}
log10 se define en <cmath>o <math.h>. Debería hacer un perfil de esto para ver si es más rápido que cualquiera de los otros publicados aquí. No estoy seguro de cuán robusto es esto con respecto a la precisión de punto flotante. Además, el argumento no está firmado como valores negativos y el registro no se mezcla realmente.
Para entradas de 32 bits y flotantes de 56 bits, esto probablemente funcione. Si la entrada es larga (64 bits), los 56 bits del registro de doble precisión pueden hacer que esto produzca la respuesta incorrecta en casos de valores cercanos a valores grandes de 10 ^ n. Espere problemas por encima de 2 ^ 50.
Ira Baxter
1
También está la cuestión de cuán precisas son las funciones de registro. No he comprobado cuán precisos son en las bibliotecas modernas, y no me sentiría cómodo confiando ciegamente en que sean buenos para una parte en mil millones.
David Thornley
@DavidThornley: log u otras funciones matemáticas son perfectamente precisas a menos que se especifique en la línea de comandos del compilador. algunos se convertirán a intrínsecos x86 en tiempo de compilación. algunos no existen y se expandirán en fórmulas de intrínsecos existentes. Por ejemplo, si se usa, -fpfastse puede ver el uso de SSE Instrinsics en lugar de x87, lo que ofrece menos garantía en la precisión IIRC. pero por defecto no hay problema.
v.oddou
@DavidThornley: es más que precisión. La pregunta es si está garantizado o no ese log10 (10 ^ k) ≥ k para todos los k relevantes. Es decir, se garantiza que cualquier error de redondeo inevitable vaya en la dirección correcta. k + eps como resultado funciona, k - eps no. Y "Perfectamente preciso" es ingenuo.
Esto puede o no ser más rápido que el enfoque de bucle desenrollado que tomé: necesitaría perfilar la diferencia (a largo plazo debería ser insignificante).
Vitali
De acuerdo, la creación de perfiles es la única forma de saberlo con certeza. Actualicé mi respuesta con ese comentario, ya que la respuesta ceil (log10 ()) de Ben S ha desaparecido.
squelart
11
Broma práctica: esta es la forma más eficiente (el número de dígitos se calcula en tiempo de compilación):
template<unsignedlonglong N,size_t base=10>struct numberlength
{enum{ value =1+ numberlength<N/base, base>::value };};template<size_t base>struct numberlength<0, base>{enum{ value =0};};
Puede ser útil para determinar el ancho requerido para el campo numérico en formato, elementos de entrada, etc.
Primero, su solución no funciona para 0. Segundo, su solución no es aplicable al caso general de una variable. En tercer lugar, si está utilizando un literal constante, ya sabe cuántos dígitos tiene.
Vitali
Funciona para 0 también. También funciona para cualquier base. El resto son puntos válidos que ya describí.
blinnov.com
3
No creo que lo haga en realidad. Falla en 0y también falla en base 1:) y da divide por cero errores si la base se da como 0. Sin embargo, se puede arreglar. De todos modos, estoy revisando una publicación muy antigua, lo siento, es solo que creo que esto no tiene por qué ser una broma y podría ser útil.
tjm
9
Vea Bit Twiddling Hacks para una versión mucho más corta de la respuesta que aceptó. También tiene la ventaja de encontrar la respuesta antes si su entrada se distribuye normalmente, verificando primero las constantes grandes. (v >= 1000000000)captura el 76% de los valores, por lo que comprobar que primero será, en promedio, más rápido.
No está claro si el bit-twiddling es realmente más rápido. Incluso en el peor de los casos, mi enfoque modificado requiere 4 comparaciones (podría ser capaz de reducirlo a 3 si examiné la partición más a fondo, aunque parece poco probable). Dudo seriamente que eso vaya a ser superado por las operaciones aritméticas + las cargas de memoria (aunque si se accede lo suficiente, desaparecerán en el caché de la CPU). Recuerde, en el ejemplo que dan, también ocultan la base de registro 2 como alguna función abstracta de IntegerLogBase2 (que en sí misma no es barata).
Vitali
Solo como seguimiento, sí, si los números se distribuyen normalmente, hacer la verificación en orden es más rápido. Sin embargo, tiene el caso degenerado de ser el doble de lento en el peor de los casos. El enfoque dividido por número de dígitos en lugar de espacio de entrada significa que el comportamiento no tiene un caso degenerado y siempre funciona de manera óptima. Además, recuerde que está asumiendo que los números se distribuirán uniformemente. De hecho, son más propensos a seguir alguna distribución relacionada con <a href=" en.wikipedia.org/wiki/...> sería mi conjetura.
Vitali
Los trucos de twiddling no son más rápidos que el método de partición anterior, pero son potencialmente interesantes si tuviera un caso más general como un flotante aquí.
Corwin Joy
1
Los trucos de twiddling sugieren una forma de obtener int log10, dado int log2. Sugiere varias formas de obtener int log2, principalmente con pocas comparaciones / ramas. (Creo que estás subestimando el costo de las ramas impredecibles, Vitali). Si puede utilizar inmx x86 asm, la instrucción BSR le dará el log2 int de un valor (es decir, el índice de bits del bit de conjunto más significativo). Es un poco lento en K8 (latencia de 10 ciclos), pero rápido en Core 2 (latencia de 2 o 3 ciclos). Incluso en K8, puede ser más rápido que las comparaciones.
Peter Cordes
En K10, lzcnt cuenta los ceros iniciales, por lo que es casi lo mismo que bsr, pero una entrada de 0 ya no es un caso especial con resultados indefinidos. Latencias: BSR: 4, LZCNT: 2.
Peter Cordes
8
convertir a cadena y luego usar funciones integradas
Si bien esto es eficiente en términos de LOC, como se señaló en la respuesta aceptada, el uso del registro probablemente no dará el mejor rendimiento.
Ian
@ Ian ¿Por qué no? Son solo un par de instrucciones de FPU. Millas mejor que todas las ramas y bucles en otras respuestas.
Marqués de Lorne
5
Un póster anterior sugirió un bucle que se divide entre 10. Dado que las multiplicaciones en máquinas modernas son mucho más rápidas, recomendaría el siguiente código:
int digits =1, pten=10;while( pten <= number ){ digits++; pten*=10;}
el diablo está en los detalles - lo que sucede con say std :: numeric_limits <int> :: max == number - podría tener un problema para terminar
pgast
2
Si le preocupa ese caso, puede agregar un IF adicional para manejar valores muy grandes.
Ira Baxter
2
Debo observar que en las máquinas x86, el compilador puede implementar una multiplicación por una constante 10, como se usa en este caso, como LEA R2, [8 * R1 + R1], AGREGAR R1, R2, por lo que se necesitan 2 relojes como máximo. Las multiplicaciones por variables toman decenas de relojes, y las divisiones son mucho peores.
Ira Baxter
La ventaja del enfoque de división es que no necesita preocuparse por los números negativos.
Johannes Schaub - litb
1
Comparé el enfoque de multiplicación (con fabs para eliminar el problema de los signos) versus el enfoque de división. En mi máquina, el enfoque de división es un factor 2 más lento que el enfoque de multiplicación. Si esto es una optimización prematura o no, realmente depende de dónde y cómo se llama.
Spacemoose
5
La arquitectura ppc tiene un poco de instrucción de conteo. Con eso, puede determinar la base de registro 2 de un entero positivo en una sola instrucción. Por ejemplo, 32 bits sería:
#define log_2_32_ppc(x)(31-__cntlzw(x))
Si puede manejar un pequeño margen de error en valores grandes, puede convertirlo a la base 10 de registro con otras pocas instrucciones:
Esto es específico de la plataforma y es un poco impreciso, pero tampoco implica ramas, división o conversión a coma flotante. Todo depende de lo que necesites.
Solo conozco las instrucciones de ppc, pero otras arquitecturas deberían tener instrucciones similares.
Esta solución calcula log2 (15) = 4 bits y log2 (9) = 4 bits. Pero 15 y 9 requieren diferentes números de dígitos decimales para imprimir. Por lo tanto, no funciona, a menos que a veces no le importe imprimir sus números con demasiados dígitos. Pero en ese caso, siempre puede elegir "10" como respuesta para int.
Ira Baxter
Wow, una función aproximada. Agradable.
doug65536
4
#include<iostream>#include<math.h>usingnamespace std;int main(){double num;int result;
cout<<"Enter a number to find the number of digits, not including decimal places: ";
cin>>num;
result =((num<=1)?1: log10(num)+1);
cout<<"Number of digits "<<result<<endl;return0;}
Esta es probablemente la forma más sencilla de resolver su problema, suponiendo que solo le importen los dígitos antes del decimal y suponiendo que cualquier cosa menor que 10 es solo 1 dígito.
Me gusta la respuesta de Ira Baxter. Aquí hay una variante de plantilla que maneja los diversos tamaños y se ocupa de los valores enteros máximos (actualizados para izar el check-out del límite superior del bucle):
#include<boost/integer_traits.hpp>template<typename T> T max_decimal(){
T t =1;for(unsigned i = boost::integer_traits<T>::digits10; i;--i)
t *=10;return t;}template<typename T>unsigned digits(T v){if(v <0) v =-v;if(max_decimal<T>()<= v)return boost::integer_traits<T>::digits10 +1;unsigned digits =1;
T boundary =10;while(boundary <= v){
boundary *=10;++digits;}return digits;}
Para obtener realmente el rendimiento mejorado al levantar la prueba adicional del ciclo, debe especializarse max_decimal () para devolver constantes para cada tipo en su plataforma. Un compilador suficientemente mágico podría optimizar la llamada a max_decimal () a una constante, pero la especialización es mejor con la mayoría de los compiladores de hoy. Tal como está, esta versión es probablemente más lenta porque max_decimal cuesta más que las pruebas eliminadas del bucle.
Desea hacer que el límite superior verifique un condicional separado probado primero para que no lo verifique en cada iteración del bucle.
Ira Baxter
No quieres poner 10 en esa temperatura. El compilador podría considerar multiplicar por t para multiplicar por una variable real, y utilizar una instrucción de multiplicación de propósito general. Si en su lugar escribió "resultado * = 10;" el compilador seguramente notará la multiplicación por 10 constantes e implementará eso con unos pocos cambios y adiciones, lo cual es extremadamente rápido.
Ira Baxter
Si la multiplicación por t siempre fue una multiplicación por 10, entonces sí, el compilador podría reducir la fuerza. Sin embargo, t no es invariante en bucle en este caso (es solo una modificación de una función de potencia entera que tenía por ahí). La optimización correcta es la especialización en el tipo que devuelve una constante. Sin embargo, tiene razón en que, en este caso, la función siempre está elevando 10 a una potencia, no un entero arbitrario a una potencia, y la reducción de la fuerza da una buena victoria. Así que hice un cambio ... ¡Esta vez más cambios realmente quedan como ejercicio! (Stack Overflow es un gran sumidero ...)
enero
1
#include<stdint.h>// uint32_t [available since C99]/// Determine the number of digits for a 32 bit integer./// - Uses at most 4 comparisons./// - (cX) 2014 [email protected]/// - \see http://stackoverflow.com/questions/1489830/#27669966/** #d == Number length vs Number of comparisons == #c
\code
#d | #c #d | #c
---+--- ---+---
10 | 4 5 | 4
9 | 4 4 | 4
8 | 3 3 | 3
7 | 3 2 | 3
6 | 3 1 | 3
\endcode
*/unsignedNumDigits32bs(uint32_t x){return// Num-># Digits->[0-9] 32->bits bs->Binary Search( x >=100000u// [6-10] [1-5]?// [6-10]( x >=10000000u// [8-10] [6-7]?// [8-10]( x >=100000000u// [9-10] [8]?// [9-10]( x >=1000000000u// [10] [9]?10:9):8):// [6-7]( x >=1000000u// [7] [6]?7:6)):// [1-5]( x >=100u// [3-5] [1-2]?// [3-5]( x >=1000u// [4-5] [3]?// [4-5]( x >=10000u// [5] [4]?5:4):3):// [1-2]( x >=10u// [2] [1]?2:1)));}
Otro fragmento de código, que hace básicamente lo mismo que Vitali, pero emplea la búsqueda binaria. La matriz Powers se inicializa de forma diferida una vez por cada instancia de tipo sin signo. La sobrecarga de tipo firmado se encarga del signo menos.
#include<limits>#include<type_traits>#include<array>template<class T>size_tNumberOfDecPositions( T v,typename std::enable_if<std::is_unsigned<T>::value>::type*=0){typedef std::array<T,std::numeric_limits<T>::digits10+1> array_type;static array_type powers_of_10;if( powers_of_10.front()==0){
T n =1;for( T& i: powers_of_10 ){
i = n;
n *=10;}}size_t l =0, r = powers_of_10.size(), p;while( l+1< r ){
p =(l+r)/2;if( powers_of_10[p]<= v )
l = p;else
r = p;}return l +1;};template<class T>size_tNumberOfDecPositions( T v,typename std::enable_if<std::is_signed<T>::value>::type*=0){typedeftypename std::make_unsigned<T>::type unsigned_type;if( v <0)returnNumberOfDecPositions(static_cast<unsigned_type>(-v))+1;elsereturnNumberOfDecPositions(static_cast<unsigned_type>(v));}
Si a alguien le importa una mayor optimización, tenga en cuenta que el primer elemento de la matriz de poderes nunca se usa, y laparece con +12 veces.
en caso de que se necesite el número de dígitos Y el valor de cada posición de dígitos, use esto:
int64_t= number, digitValue, digits =0;// or "int" for 32bitwhile(number !=0){
digitValue = number %10;
digits ++;
number /=10;}
digitle da el valor en la posición del número que se procesa actualmente en el bucle. por ejemplo, para el número 1776, el valor del dígito es:
6 en el 1er bucle
7 en el 2 ° bucle
7 en el 3 ° bucle
1 en el 4 ° bucle
para el número entero 'X' desea saber la cantidad de dígitos, bien sin usar ningún bucle, esta solución actúa en una fórmula en una sola línea, por lo que esta es la solución más óptima que he visto para este problema.
int x =1000;
cout<<numberOfDigits =1+floor(log10(x))<<endl ;
Falla para INT_MAX y también para números negativos.
Ranu
@ranu falla para INT_MAX ¿cómo? Cuando el argumento se convierte a double? ¿O se refiere a alguna entrada entera imposible con dígitos decimales INT_MAX? ¿Cuál también fallaría en cualquier otra respuesta aquí?
Marqués de Lorne
0
int numberOfDigits(int n){if(n<=9){return1;}return1+ numberOfDigits(n/10);}
Esto es lo que haría, si lo desea para la base 10. Es bastante rápido y no obtendrá un overflock de apilamiento de enteros enteros.
int num,dig_quant =0;
cout<<"\n\n\t\t--Count the digits in Number--\n\n";
cout<<"Enter Number: ";
cin>>num;for(int i =1; i<=num; i*=10){if(num / i >0){
dig_quant +=1;}}
cout<<"\n"<<number<<" include "<<dig_quant<<" digit"
cout<<"\n\nGoodbye...\n\n";
Si más rápido es más eficiente, esta es una mejora en la mejora de andrei alexandrescu . Su versión ya era más rápida que la forma ingenua (dividiendo por 10 en cada dígito). La versión a continuación es de tiempo constante y más rápido al menos en x86-64 y ARM para todos los tamaños, pero ocupa el doble de código binario, por lo que no es tan amigable para la caché.
Los puntos de referencia para esta versión vs la versión de alexandrescu en mi PR en Facebook locura .
Estaba trabajando en un programa que requería que verificara si el usuario respondía correctamente cuántos dígitos había en un número, por lo que tuve que desarrollar una forma de verificar la cantidad de dígitos en un número entero. Terminó siendo algo relativamente fácil de resolver.
Esta terminó siendo mi respuesta, que actualmente funciona con números con menos de 10 ^ 1000 dígitos (se puede cambiar cambiando el valor del exponente).
PD: Sé que esta respuesta tiene diez años de retraso, pero llegué aquí en 2020 para que otras personas puedan usarla.
Por supuesto, podría usarse cualquier otra implementación de un conjunto ordenado powers_and_maxy, si se supiera que habría agrupamiento, pero no se sabe dónde podría estar el clúster, tal vez sería mejor una implementación de árbol autoajustable
int numberOfDigits(double number){if(number <0){
number*=-1;}int i=0;while(number > pow(10, i))
i++;
cout <<"This number has "<< i <<" digits"<< endl;return i;}
Respuestas:
Bueno, la forma más eficiente, suponiendo que conozca el tamaño del número entero, sería una búsqueda. Debería ser más rápido que el enfoque basado en el logaritmo mucho más corto. Si no le importa contar el '-', elimine el + 1.
fuente
La forma más simple es hacer:
log10 se define en
<cmath>
o<math.h>
. Debería hacer un perfil de esto para ver si es más rápido que cualquiera de los otros publicados aquí. No estoy seguro de cuán robusto es esto con respecto a la precisión de punto flotante. Además, el argumento no está firmado como valores negativos y el registro no se mezcla realmente.fuente
-fpfast
se puede ver el uso de SSE Instrinsics en lugar de x87, lo que ofrece menos garantía en la precisión IIRC. pero por defecto no hay problema.Quizás entendí mal la pregunta, pero ¿no es así?
fuente
Nota: "0" tendrá 0 dígitos! Si necesita que 0 parezca tener 1 dígito, use:
(Gracias Kevin Fegan)
Al final, use un generador de perfiles para saber cuál de todas las respuestas aquí será más rápida en su máquina ...
fuente
Broma práctica: esta es la forma más eficiente (el número de dígitos se calcula en tiempo de compilación):
Puede ser útil para determinar el ancho requerido para el campo numérico en formato, elementos de entrada, etc.
fuente
0
y también falla en base1
:) y da divide por cero errores si la base se da como0
. Sin embargo, se puede arreglar. De todos modos, estoy revisando una publicación muy antigua, lo siento, es solo que creo que esto no tiene por qué ser una broma y podría ser útil.Vea Bit Twiddling Hacks para una versión mucho más corta de la respuesta que aceptó. También tiene la ventaja de encontrar la respuesta antes si su entrada se distribuye normalmente, verificando primero las constantes grandes.
(v >= 1000000000)
captura el 76% de los valores, por lo que comprobar que primero será, en promedio, más rápido.fuente
convertir a cadena y luego usar funciones integradas
fuente
fuente
Un póster anterior sugirió un bucle que se divide entre 10. Dado que las multiplicaciones en máquinas modernas son mucho más rápidas, recomendaría el siguiente código:
fuente
La arquitectura ppc tiene un poco de instrucción de conteo. Con eso, puede determinar la base de registro 2 de un entero positivo en una sola instrucción. Por ejemplo, 32 bits sería:
Si puede manejar un pequeño margen de error en valores grandes, puede convertirlo a la base 10 de registro con otras pocas instrucciones:
Esto es específico de la plataforma y es un poco impreciso, pero tampoco implica ramas, división o conversión a coma flotante. Todo depende de lo que necesites.
Solo conozco las instrucciones de ppc, pero otras arquitecturas deberían tener instrucciones similares.
fuente
Esta es probablemente la forma más sencilla de resolver su problema, suponiendo que solo le importen los dígitos antes del decimal y suponiendo que cualquier cosa menor que 10 es solo 1 dígito.
fuente
Me gusta la respuesta de Ira Baxter. Aquí hay una variante de plantilla que maneja los diversos tamaños y se ocupa de los valores enteros máximos (actualizados para izar el check-out del límite superior del bucle):
Para obtener realmente el rendimiento mejorado al levantar la prueba adicional del ciclo, debe especializarse max_decimal () para devolver constantes para cada tipo en su plataforma. Un compilador suficientemente mágico podría optimizar la llamada a max_decimal () a una constante, pero la especialización es mejor con la mayoría de los compiladores de hoy. Tal como está, esta versión es probablemente más lenta porque max_decimal cuesta más que las pruebas eliminadas del bucle.
Dejaré todo eso como ejercicio para el lector.
fuente
fuente
Otro fragmento de código, que hace básicamente lo mismo que Vitali, pero emplea la búsqueda binaria. La matriz Powers se inicializa de forma diferida una vez por cada instancia de tipo sin signo. La sobrecarga de tipo firmado se encarga del signo menos.
Si a alguien le importa una mayor optimización, tenga en cuenta que el primer elemento de la matriz de poderes nunca se usa, y
l
aparece con+1
2 veces.fuente
en caso de que se necesite el número de dígitos Y el valor de cada posición de dígitos, use esto:
digit
le da el valor en la posición del número que se procesa actualmente en el bucle. por ejemplo, para el número 1776, el valor del dígito es:6 en el 1er bucle
7 en el 2 ° bucle
7 en el 3 ° bucle
1 en el 4 ° bucle
fuente
fuente
fuente
para el número entero 'X' desea saber la cantidad de dígitos, bien sin usar ningún bucle, esta solución actúa en una fórmula en una sola línea, por lo que esta es la solución más óptima que he visto para este problema.
fuente
double
? ¿O se refiere a alguna entrada entera imposible con dígitos decimales INT_MAX? ¿Cuál también fallaría en cualquier otra respuesta aquí?Esto es lo que haría, si lo desea para la base 10. Es bastante rápido y no obtendrá un overflock de apilamiento de enteros enteros.
fuente
fuente
Si más rápido es más eficiente, esta es una mejora en la mejora de andrei alexandrescu . Su versión ya era más rápida que la forma ingenua (dividiendo por 10 en cada dígito). La versión a continuación es de tiempo constante y más rápido al menos en x86-64 y ARM para todos los tamaños, pero ocupa el doble de código binario, por lo que no es tan amigable para la caché.
Los puntos de referencia para esta versión vs la versión de alexandrescu en mi PR en Facebook locura .
Funciona en
unsigned
, nosigned
.fuente
Estaba trabajando en un programa que requería que verificara si el usuario respondía correctamente cuántos dígitos había en un número, por lo que tuve que desarrollar una forma de verificar la cantidad de dígitos en un número entero. Terminó siendo algo relativamente fácil de resolver.
Esta terminó siendo mi respuesta, que actualmente funciona con números con menos de 10 ^ 1000 dígitos (se puede cambiar cambiando el valor del exponente).
PD: Sé que esta respuesta tiene diez años de retraso, pero llegué aquí en 2020 para que otras personas puedan usarla.
fuente
donde
powers_and_max
tenemos(10^n)-1
para todos losn
que(10^n) <
std::numeric_limits<type>::max()
y
std::numeric_limits<type>::max()
en una matriz:Aquí hay una prueba simple:
Por supuesto, podría usarse cualquier otra implementación de un conjunto ordenado
powers_and_max
y, si se supiera que habría agrupamiento, pero no se sabe dónde podría estar el clúster, tal vez sería mejor una implementación de árbol autoajustablefuente
manera efectiva
fuente
Actualización de C ++ 11 de la solución preferida:
evita la creación de instancias de plantilla con doble, et. Alabama.
fuente
fuente
Esta es mi forma de hacer eso:
fuente
Aquí hay un enfoque diferente:
Esto puede no ser eficiente, solo algo diferente de lo que otros sugirieron.
fuente