¿Cuál es una forma muy eficiente de determinar cuántos dígitos hay en un entero en C ++?
¿Cuál es una forma muy eficiente de determinar cuántos dígitos hay en un entero en C ++?
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.
// generic solution
template <class T>
int numDigits(T number)
{
int digits = 0;
if (number < 0) digits = 1; // remove this line if '-' counts as a digit
while (number) {
number /= 10;
digits++;
}
return digits;
}
// partial specialization optimization for 32-bit numbers
template<>
int numDigits(int32_t x)
{
if (x == MIN_INT) return 10 + 1;
if (x < 0) return numDigits(-x) + 1;
if (x >= 10000) {
if (x >= 10000000) {
if (x >= 100000000) {
if (x >= 1000000000)
return 10;
return 9;
}
return 8;
}
if (x >= 100000) {
if (x >= 1000000)
return 7;
return 6;
}
return 5;
}
if (x >= 100) {
if (x >= 1000)
return 4;
return 3;
}
if (x >= 10)
return 2;
return 1;
}
// partial-specialization optimization for 8-bit numbers
template <>
int numDigits(char n)
{
// if you have the time, replace this with a static initialization to avoid
// the initial overhead & unnecessary branch
static char 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];
}
La forma más simple es hacer:
unsigned GetNumberOfDigits (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.
-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í?
int NumDigits(int x)
{
x = abs(x);
return (x < 10 ? 1 :
(x < 100 ? 2 :
(x < 1000 ? 3 :
(x < 10000 ? 4 :
(x < 100000 ? 5 :
(x < 1000000 ? 6 :
(x < 10000000 ? 7 :
(x < 100000000 ? 8 :
(x < 1000000000 ? 9 :
10)))))))));
}
int digits = 0; while (number != 0) { number /= 10; digits++; }
Nota: "0" tendrá 0 dígitos! Si necesita que 0 parezca tener 1 dígito, use:
int digits = 0; do { number /= 10; digits++; } while (number != 0);
(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 ...
Broma práctica: esta es la forma más eficiente (el número de dígitos se calcula en tiempo de compilación):
template <unsigned long long 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.
0
y 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.
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.
int x = 1000;
int numberOfDigits = x ? static_cast<int>(log10(abs(x))) + 1 : 1;
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; }
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:
#define log_10_estimate_32_ppc(x) (9-(((__cntlzw(x)*1233)+1545)>>12))
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.
#include <iostream>
#include <math.h>
using namespace 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;
return 0;
}
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.
Dejaré todo eso como ejercicio para el lector.
#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 adolfo.dimare@gmail.com
/// - \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
*/
unsigned NumDigits32bs(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_t NumberOfDecPositions ( 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_t NumberOfDecPositions ( T v, typename std::enable_if<std::is_signed<T>::value>::type* = 0 )
{
typedef typename std::make_unsigned<T>::type unsigned_type;
if ( v < 0 )
return NumberOfDecPositions ( static_cast<unsigned_type>(-v) ) + 1;
else
return NumberOfDecPositions ( 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 l
aparece con +1
2 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 32bit
while (number != 0) {
digitValue = number % 10;
digits ++;
number /= 10;
}
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
// Meta-program to calculate number of digits in (unsigned) 'N'.
template <unsigned long long N, unsigned base=10>
struct numberlength
{ // http://stackoverflow.com/questions/1489830/
enum { value = ( 1<=N && N<base ? 1 : 1+numberlength<N/base, base>::value ) };
};
template <unsigned base>
struct numberlength<0, base>
{
enum { value = 1 };
};
{
assert( (1 == numberlength<0,10>::value) );
}
assert( (1 == numberlength<1,10>::value) );
assert( (1 == numberlength<5,10>::value) );
assert( (1 == numberlength<9,10>::value) );
assert( (4 == numberlength<1000,10>::value) );
assert( (4 == numberlength<5000,10>::value) );
assert( (4 == numberlength<9999,10>::value) );
/// Determine the number of digits for a 64 bit integer.
/// - Uses at most 5 comparisons.
/// - (cX) 2014 adolfo.dimare@gmail.com
/// - \see http://stackoverflow.com/questions/1489830/#27670035
/** #d == Number length vs Number of comparisons == #c
\code
#d | #c #d | #c #d | #c #d | #c
---+--- ---+--- ---+--- ---+---
20 | 5 15 | 5 10 | 5 5 | 5
19 | 5 14 | 5 9 | 5 4 | 5
18 | 4 13 | 4 8 | 4 3 | 4
17 | 4 12 | 4 7 | 4 2 | 4
16 | 4 11 | 4 6 | 4 1 | 4
\endcode
*/
unsigned NumDigits64bs(uint64_t x) {
return // Num-># Digits->[0-9] 64->bits bs->Binary Search
( x >= 10000000000ul // [11-20] [1-10]
?
( x >= 1000000000000000ul // [16-20] [11-15]
? // [16-20]
( x >= 100000000000000000ul // [18-20] [16-17]
? // [18-20]
( x >= 1000000000000000000ul // [19-20] [18]
? // [19-20]
( x >= 10000000000000000000ul // [20] [19]
? 20
: 19
)
: 18
)
: // [16-17]
( x >= 10000000000000000ul // [17] [16]
? 17
: 16
)
)
: // [11-15]
( x >= 1000000000000ul // [13-15] [11-12]
? // [13-15]
( x >= 10000000000000ul // [14-15] [13]
? // [14-15]
( x >= 100000000000000ul // [15] [14]
? 15
: 14
)
: 13
)
: // [11-12]
( x >= 100000000000ul // [12] [11]
? 12
: 11
)
)
)
: // [1-10]
( x >= 100000ul // [6-10] [1-5]
? // [6-10]
( x >= 10000000ul // [8-10] [6-7]
? // [8-10]
( x >= 100000000ul // [9-10] [8]
? // [9-10]
( x >= 1000000000ul // [10] [9]
? 10
: 9
)
: 8
)
: // [6-7]
( x >= 1000000ul // [7] [6]
? 7
: 6
)
)
: // [1-5]
( x >= 100ul // [3-5] [1-2]
? // [3-5]
( x >= 1000ul // [4-5] [3]
? // [4-5]
( x >= 10000ul // [5] [4]
? 5
: 4
)
: 3
)
: // [1-2]
( x >= 10ul // [2] [1]
? 2
: 1
)
)
)
);
}
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 ;
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í?
int numberOfDigits(int n){
if(n<=9){
return 1;
}
return 1 + 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 .
Funciona en unsigned
, no signed
.
inline uint32_t digits10(uint64_t v) {
return 1
+ (std::uint32_t)(v>=10)
+ (std::uint32_t)(v>=100)
+ (std::uint32_t)(v>=1000)
+ (std::uint32_t)(v>=10000)
+ (std::uint32_t)(v>=100000)
+ (std::uint32_t)(v>=1000000)
+ (std::uint32_t)(v>=10000000)
+ (std::uint32_t)(v>=100000000)
+ (std::uint32_t)(v>=1000000000)
+ (std::uint32_t)(v>=10000000000ull)
+ (std::uint32_t)(v>=100000000000ull)
+ (std::uint32_t)(v>=1000000000000ull)
+ (std::uint32_t)(v>=10000000000000ull)
+ (std::uint32_t)(v>=100000000000000ull)
+ (std::uint32_t)(v>=1000000000000000ull)
+ (std::uint32_t)(v>=10000000000000000ull)
+ (std::uint32_t)(v>=100000000000000000ull)
+ (std::uint32_t)(v>=1000000000000000000ull)
+ (std::uint32_t)(v>=10000000000000000000ull);
}
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.
double check=0, exponent=1000;
while(check<=1)
{
check=number/pow(10, exponent);
exponent--;
}
exponent=exponent+2;
cout<<exponent<<endl;
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.
template <typename type>
class number_of_decimal_digits {
const powers_and_max<type> mPowersAndMax;
public:
number_of_decimal_digits(){
}
inline size_t ndigits( type i) const {
if(i<0){
i += (i == std::numeric_limits<type>::min());
i=-i;
}
const type* begin = &*mPowersAndMax.begin();
const type* end = begin+mPowersAndMax.size();
return 1 + std::lower_bound(begin,end,i) - begin;
}
inline size_t string_ndigits(const type& i) const {
return (i<0) + ndigits(i);
}
inline size_t operator[](const type& i) const {
return string_ndigits(i);
}
};
donde powers_and_max
tenemos (10^n)-1
para todos los n
que
(10^n) <
std::numeric_limits<type>::max()
y std::numeric_limits<type>::max()
en una matriz:
template <typename type>
struct powers_and_max : protected std::vector<type>{
typedef std::vector<type> super;
using super::const_iterator;
using super::size;
type& operator[](size_t i)const{return super::operator[](i)};
const_iterator begin()const {return super::begin();}
const_iterator end()const {return super::end();}
powers_and_max() {
const int size = (int)(log10(double(std::numeric_limits<type>::max())));
int j = 0;
type i = 10;
for( ; j<size ;++j){
push_back(i-1);//9,99,999,9999 etc;
i*=10;
}
ASSERT(back()<std::numeric_limits<type>::max());
push_back(std::numeric_limits<type>::max());
}
};
Aquí hay una prueba simple:
number_of_decimal_digits<int> ndd;
ASSERT(ndd[0]==1);
ASSERT(ndd[9]==1);
ASSERT(ndd[10]==2);
ASSERT(ndd[-10]==3);
ASSERT(ndd[-1]==2);
ASSERT(ndd[-9]==2);
ASSERT(ndd[1000000000]==10);
ASSERT(ndd[0x7fffffff]==10);
ASSERT(ndd[-1000000000]==11);
ASSERT(ndd[0x80000000]==11);
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 autoajustable
manera efectiva
int num;
int count = 0;
while(num)
{
num /= 10;
++count;
}
#include <iostream>
int main()
{
int num;
std::cin >> num;
std::cout << "number of digits for " << num << ": ";
int count = 0;
while(num)
{
num /= 10;
++count;
}
std::cout << count << '\n';
return 0;
}
Actualización de C ++ 11 de la solución preferida:
#include <limits>
#include <type_traits>
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer, unsigned int>::type
numberDigits(T value) {
unsigned int digits = 0;
if (value < 0) digits = 1;
while (value) {
value /= 10;
++digits;
}
return digits;
}
evita la creación de instancias de plantilla con doble, et. Alabama.
Esta es mi forma de hacer eso:
int digitcount(int n)
{
int count = 1;
int temp = n;
while (true)
{
temp /= 10;
if (temp != 0) ++count;
if (temp == 0) break;
}
return count;
}
Aquí hay un enfoque diferente:
digits = sprintf(numArr, "%d", num); // where numArr is a char array
if (num < 0)
digits--;
Esto puede no ser eficiente, solo algo diferente de lo que otros sugirieron.