Как определить количество цифр целого числа в C?

Например,

n = 3432, result 4

n = 45, result 2

n = 33215, result 5

n = -357, result 3

Я думаю, я мог бы просто превратить его в строку, а затем получить длину строки, но это кажется запутанным и хакерским.

22 ответа

Решение
floor (log10 (abs (x))) + 1

http://en.wikipedia.org/wiki/Logarithm

Рекурсивный подход:-)

int numPlaces (int n) {
    if (n < 0) return numPlaces ((n == INT_MIN) ? MAX_INT: -n);
    if (n < 10) return 1;
    return 1 + numPlaces (n / 10);
}

Или итеративный:

int numPlaces (int n) {
    int r = 1;
    if (n < 0) n = (n == INT_MIN) ? INT_MAX: -n;
    while (n > 9) {
        n /= 10;
        r++;
    }
    return r;
}

Или грубая скорость:

int numPlaces (int n) {
    if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
    if (n < 10) return 1;
    if (n < 100) return 2;
    if (n < 1000) return 3;
    if (n < 10000) return 4;
    if (n < 100000) return 5;
    if (n < 1000000) return 6;
    if (n < 10000000) return 7;
    if (n < 100000000) return 8;
    if (n < 1000000000) return 9;
    /*      2147483647 is 2^31-1 - add more ifs as needed
       and adjust this final return as well. */
    return 10;
}

Выше были изменены, чтобы улучшить процесс MININT. В любых странных системах, которые не следуют разумным правилам дополнения 2n два для целых чисел, они могут нуждаться в дальнейшей корректировке.

Необработанная скоростная версия фактически превосходит версию с плавающей запятой, измененную ниже:

int numPlaces (int n) {
    if (n == 0) return 1;
    return floor (log10 (abs (n))) + 1;
}

С сотней миллионов итераций я получаю следующие результаты:

Raw speed with 0:            0 seconds
Raw speed with 2^31-1:       1 second
Iterative with 2^31-1:       5 seconds
Recursive with 2^31-1:       6 seconds
Floating point with 1:       6 seconds
Floating point with 2^31-1:  7 seconds

Это на самом деле меня немного удивило - я думал, что чипы Intel имеют приличный FPU, но я предполагаю, что общие операции FP все еще не могут конкурировать с оптимизированным вручную целочисленным кодом.

Обновите следующие предложения Stormsoul:

Тестирование многократного итерационного решения с помощью stormsoul дает результат в 4 секунды, поэтому, несмотря на то, что оно намного быстрее, чем решение с итерационным делением, оно все равно не соответствует оптимизированному решению if-Statement.

Выбор аргументов из пула из 1000 случайно сгенерированных чисел увеличил общее время до 2 секунд, поэтому, несмотря на то, что, возможно, было какое-то преимущество иметь один и тот же аргумент каждый раз, это по-прежнему самый быстрый подход в списке.

Компиляция с -O2 улучшила скорость, но не относительные позиции (я увеличил число итераций в десять раз, чтобы проверить это).

Любой дальнейший анализ должен серьезно затронуть внутреннюю работу эффективности ЦП (различные типы оптимизации, использование кэшей, прогнозирование ветвлений, какой у вас процессор на самом деле, температуру окружающей среды в помещении и т. Д.), Которая будет помешать моей оплачиваемой работе:-). Это было интересное развлечение, но в какой-то момент отдача от инвестиций для оптимизации становится слишком маленькой, чтобы иметь значение. Я думаю, что у нас есть достаточно решений, чтобы ответить на вопрос (который был, в конце концов, не о скорости).

Дальнейшее обновление:

Это будет мое последнее обновление к этому ответу за исключением явных ошибок, которые не зависят от архитектуры. Вдохновленный доблестными усилиями stormsoul по измерению, я публикую свою тестовую программу (измененную в соответствии с собственной тестовой программой stormsoul) вместе с некоторыми примерами рисунков для всех методов, показанных в ответах здесь. Имейте в виду, что это на конкретной машине, ваш пробег может варьироваться в зависимости от того, где вы его запускаете (именно поэтому я публикую тестовый код).

Делай с этим как хочешь:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#include <time.h>

#define numof(a) (sizeof(a) / sizeof(a[0]))

/* Random numbers and accuracy checks. */

static int rndnum[10000];
static int rt[numof(rndnum)];

/* All digit counting functions here. */

static int count_recur (int n) {
    if (n < 0) return count_recur ((n == INT_MIN) ? INT_MAX : -n);
    if (n < 10) return 1;
    return 1 + count_recur (n / 10);
}

static int count_diviter (int n) {
    int r = 1;
    if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
    while (n > 9) {
        n /= 10;
        r++;
    }
    return r;
}

static int count_multiter (int n) {
    unsigned int num = abs(n);
    unsigned int x, i;
    for (x=10, i=1; ; x*=10, i++) {
        if (num < x)
            return i;
        if (x > INT_MAX/10)
            return i+1;
    }
}

static int count_ifs (int n) {
    if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
    if (n < 10) return 1;
    if (n < 100) return 2;
    if (n < 1000) return 3;
    if (n < 10000) return 4;
    if (n < 100000) return 5;
    if (n < 1000000) return 6;
    if (n < 10000000) return 7;
    if (n < 100000000) return 8;
    if (n < 1000000000) return 9;
    /*      2147483647 is 2^31-1 - add more ifs as needed
    and adjust this final return as well. */
    return 10;
}

static int count_revifs (int n) {
    if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
    if (n > 999999999) return 10;
    if (n > 99999999) return 9;
    if (n > 9999999) return 8;
    if (n > 999999) return 7;
    if (n > 99999) return 6;
    if (n > 9999) return 5;
    if (n > 999) return 4;
    if (n > 99) return 3;
    if (n > 9) return 2;
    return 1;
}

static int count_log10 (int n) {
    if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
    if (n == 0) return 1;
    return floor (log10 (n)) + 1;
}

static int count_bchop (int n) {
    int r = 1;
    if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
    if (n >= 100000000) {
        r += 8;
        n /= 100000000;
    }
    if (n >= 10000) {
        r += 4;
        n /= 10000;
    }
    if (n >= 100) {
        r += 2;
        n /= 100;
    }
    if (n >= 10)
        r++;

    return r;
}

/* Structure to control calling of functions. */

typedef struct {
    int (*fnptr)(int);
    char *desc;
} tFn;

static tFn fn[] = {
    NULL,                              NULL,
    count_recur,    "            recursive",
    count_diviter,  "     divide-iterative",
    count_multiter, "   multiply-iterative",
    count_ifs,      "        if-statements",
    count_revifs,   "reverse-if-statements",
    count_log10,    "               log-10",
    count_bchop,    "          binary chop",
};
static clock_t clk[numof (fn)];

int main (int c, char *v[]) {
    int i, j, k, r;
    int s = 1;

    /* Test code:
        printf ("%11d %d\n", INT_MIN, count_recur(INT_MIN));
        for (i = -1000000000; i != 0; i /= 10)
            printf ("%11d %d\n", i, count_recur(i));
        printf ("%11d %d\n", 0, count_recur(0));
        for (i = 1; i != 1000000000; i *= 10)
            printf ("%11d %d\n", i, count_recur(i));
        printf ("%11d %d\n", 1000000000, count_recur(1000000000));
        printf ("%11d %d\n", INT_MAX, count_recur(INT_MAX));
    /* */

    /* Randomize and create random pool of numbers. */

    srand (time (NULL));
    for (j = 0; j < numof (rndnum); j++) {
        rndnum[j] = s * rand();
        s = -s;
    }
    rndnum[0] = INT_MAX;
    rndnum[1] = INT_MIN;

    /* For testing. */
    for (k = 0; k < numof (rndnum); k++) {
        rt[k] = (fn[1].fnptr)(rndnum[k]);
    }

    /* Test each of the functions in turn. */

    clk[0] = clock();
    for (i = 1; i < numof (fn); i++) {
        for (j = 0; j < 10000; j++) {
            for (k = 0; k < numof (rndnum); k++) {
                r = (fn[i].fnptr)(rndnum[k]);
                /* Test code:
                    if (r != rt[k]) {
                        printf ("Mismatch error [%s] %d %d %d %d\n",
                            fn[i].desc, k, rndnum[k], rt[k], r);
                        return 1;
                    }
                /* */
            }
        }
        clk[i] = clock();
    }

    /* Print out results. */

    for (i = 1; i < numof (fn); i++) {
        printf ("Time for %s: %10d\n", fn[i].desc, (int)(clk[i] - clk[i-1]));
    }

    return 0;
}

Помните, что вам нужно убедиться, что вы используете правильную командную строку для ее компиляции. В частности, вам может понадобиться явно перечислить математическую библиотеку, чтобы получить log10() за работой. Командная строка, которую я использовал под Debian, была gcc -o testprog testprog.c -lm,

И, с точки зрения результатов, вот таблица лидеров для моей среды:

Уровень оптимизации 0:

Time for reverse-if-statements:       1704
Time for         if-statements:       2296
Time for           binary chop:       2515
Time for    multiply-iterative:       5141
Time for      divide-iterative:       7375
Time for             recursive:      10469
Time for                log-10:      26953

Уровень оптимизации 3:

Time for         if-statements:       1047
Time for           binary chop:       1156
Time for reverse-if-statements:       1500
Time for    multiply-iterative:       2937
Time for      divide-iterative:       5391
Time for             recursive:       8875
Time for                log-10:      25438

Кратчайший ответ: snprintf(0,0,"%+d",n)-1

Псевдоалгоритм двоичного поиска, чтобы получить не цифру r в v..

if (v < 0 ) v=-v;

r=1;

if (v >= 100000000)
{
  r+=8;
  v/=100000000;
}

if (v >= 10000) {
    r+=4;
    v/=10000;
}

if (v >= 100) {
    r+=2;
    v/=100;
}

if( v>=10)
{
    r+=1;
}

return r;

Разделите на 10 в цикле, пока результат не достигнет нуля. Количество итераций будет соответствовать количеству десятичных цифр.

Предполагая, что вы ожидаете получить 0 цифр в нулевом значении:

int countDigits( int value )
{
    int result = 0;
    while( value != 0 ) {
       value /= 10;
       result++;
    }
    return result;
}

Вот очень быстрый метод вычисления количества десятичных цифр Кендалла Виллетса :

      int count_digits(uint32_t n) {
#if defined(__has_builtin) && __has_builtin(__builtin_clz)
  // This increments the upper 32 bits (log10(T) - 1) when >= T is added.
  #  define K(T) (((sizeof(#T) - 1ull) << 32) - T)
  static const uint64_t table[] = {
      K(0),          K(0),          K(0),           // 8
      K(10),         K(10),         K(10),          // 64
      K(100),        K(100),        K(100),         // 512
      K(1000),       K(1000),       K(1000),        // 4096
      K(10000),      K(10000),      K(10000),       // 32k
      K(100000),     K(100000),     K(100000),      // 256k
      K(1000000),    K(1000000),    K(1000000),     // 2048k
      K(10000000),   K(10000000),   K(10000000),    // 16M
      K(100000000),  K(100000000),  K(100000000),   // 128M
      K(1000000000), K(1000000000), K(1000000000),  // 1024M
      K(1000000000), K(1000000000)                  // 4B
  };
  return (n + table[__builtin_clz(n | 1) ^ 31]) >> 32u;
#else
  int count = 1;
  for (;;) {
    if (n < 10) return count;
    if (n < 100) return count + 1;
    if (n < 1000) return count + 2;
    if (n < 10000) return count + 3;
    n /= 10000u;
    count += 4;
  }
  return count;
#endif
}

Быстрый путь зависит от __builtin_clz который доступен в GCC и clang, но благодаря резервному варианту, который работает достаточно хорошо count_digits полностью портативен.

Это генерирует очень эффективный код (Godbolt):

      count_digits(unsigned int):
  mov edx, edi
  mov eax, edi
  or edx, 1
  bsr edx, edx
  movsx rdx, edx
  add rax, QWORD PTR count_digits(unsigned int)::table[0+rdx*8]
  shr rax, 32
  ret

Версия с постоянной стоимостью, использующая сборку x86 и справочную таблицу:

int count_bsr(int i) {
    struct {
            int max;
            int count;
    } static digits[32] = {
            { 9, 1 }, { 9, 1 }, { 9, 1 }, { 9, 1 },
            { 99, 2 }, { 99, 2 }, { 99, 2 },
            { 999, 3 }, { 999, 3 }, { 999, 3 },
            { 9999, 4 }, { 9999, 4 }, { 9999, 4 }, { 9999, 4 },
            { 99999, 5 }, { 99999, 5 }, { 99999, 5 },
            { 999999, 6 }, { 999999, 6 }, { 999999, 6 },
            { 9999999, 7 }, { 9999999, 7 }, { 9999999, 7 }, { 9999999, 7 },
            { 99999999, 8 }, { 99999999, 8 }, { 99999999, 8 },
            { 999999999, 9 }, { 999999999, 9 }, { 999999999, 9 },
            { INT_MAX, 10 }, { INT_MAX, 10 }
    };
        register const int z = 0;
        register unsigned log2;
        if (i < 0) i = -i;
        __asm__ __volatile__ (
                "bsr %1, %0;"  \
                "cmovz %2, %0;"\
                : "=r" (log2)  \
                : "rm" (i), "r"(z));
        return digits[log2].count + ( i > digits[log2].max );
}

Еще один, с меньшей таблицей поиска и приближением log10, взятым отсюда.

int count_bsr2( int i ) {
    static const unsigned limits[] =
            {0, 10, 100, 1000, 10000, 100000,
             1000000, 10000000, 100000000, 1000000000};
        register const int z = 0;
        register int l, log2;
        if (i < 0) i = -i;
        __asm__ __volatile__ (
                "bsr %1, %0;"  \
                "cmovz %2, %0;"\
                : "=r" (log2)  \
                : "rm" (i), "r"(z));
       l = (log2 + 1) * 1233 >> 12;
       return (l + ((unsigned)i >= limits[l]));
}

Оба из них используют тот факт, что в x86 -INT_MIN равен INT_MIN.

Обновить:

Согласно предложению, здесь приведены временные параметры для count_bsr и немного более быстрых 64-битных подпрограмм count_bsr_mod only по сравнению с бинарным поиском и бинарными алгоритмами chop с использованием очень хорошей тестовой программы paxdiablo, модифицированной для генерации множеств со случайным распределением знаков. Тесты были построены с использованием gcc 4.9.2 с использованием опций "-O3 -falign-functions=16 -falign-jumps=16 -march=corei7-avx" и выполнялись в спокойной в противном случае системе Sandy Bridge с отключенными состояниями турбо и сна.

Время для бср мод:     270000  
Время для BSR:     340000  
Время для бинарной отбивной:     800000  
Время для двоичного поиска:     770000  
Время для бинарного поиска мод:     470000  

Источник для теста,

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#include <time.h>

#define numof(a) (sizeof(a) / sizeof(a[0]))

/* Random numbers and accuracy checks. */

static int rndnum[10000];
static int rt[numof(rndnum)];

/* All digit counting functions here. */

static int count_bchop (int n) {
    int r = 1;
    if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
    if (n >= 100000000) {
        r += 8;
        n /= 100000000;
    }
    if (n >= 10000) {
        r += 4;
        n /= 10000;
    }
    if (n >= 100) {
        r += 2;
        n /= 100;
    }
    if (n >= 10)
        r++;

    return r;
}

static int count_bsearch(int i)
{
    if (i < 0)
    {
        if (i == INT_MIN)
            return 11; // special case for -2^31 because 2^31 can't fit in a two's complement 32-bit integer
        i = -i;
    }
    if              (i < 100000) {
        if          (i < 1000) {
            if      (i < 10)         return 1;
            else if (i < 100)        return 2;
            else                     return 3;
        } else {
            if      (i < 10000)      return 4;
            else                     return 5;
        }
    } else {
        if          (i < 10000000) {
            if      (i < 1000000)    return 6;
            else                     return 7;
        } else {
            if      (i < 100000000)  return 8;
            else if (i < 1000000000) return 9;
            else                     return 10;
        }
    }
}

// Integer log base 10, modified binary search.
static int count_bsearch_mod(int i) {
   unsigned x = (i >= 0) ? i : -i;
   if (x > 99)
      if (x > 999999)
         if (x > 99999999)
            return 9 + (x > 999999999);
         else
            return 7 + (x > 9999999);
      else
         if (x > 9999)
            return 5 + (x > 99999);
         else
            return 3 + (x > 999);
   else
         return 1 + (x > 9);
}

static int count_bsr_mod(int i) {
    struct {
            int m_count;
            int m_threshold;
    } static digits[32] =
    {
      { 1, 9 }, { 1, 9 }, { 1, 9 }, { 1, 9 },
      { 2, 99 }, { 2, 99 }, { 2, 99 },
      { 3, 999 }, { 3, 999 }, { 3, 999 },
      { 4, 9999 }, { 4, 9999 }, { 4, 9999 }, { 4, 9999 },
      { 5, 99999 }, { 5, 99999 }, { 5, 99999 },
      { 6, 999999 }, { 6, 999999 }, { 6, 999999 },
      { 7, 9999999 }, { 7, 9999999 }, { 7, 9999999 }, { 7, 9999999 },
      { 8, 99999999 }, { 8, 99999999 }, { 8, 99999999 },
      { 9, 999999999 }, { 9, 999999999 }, { 9, 999999999 },
      { 10, INT_MAX }, { 10, INT_MAX }
    };
        __asm__ __volatile__ (
            "cdq                    \n\t"
            "xorl %%edx, %0         \n\t"
            "subl %%edx, %0         \n\t"
            "movl %0, %%edx         \n\t"
            "bsrl %0, %0            \n\t"
            "shlq $32, %%rdx        \n\t"
            "movq %P1(,%q0,8), %q0  \n\t"
            "cmpq %q0, %%rdx        \n\t"
            "setg %%dl              \n\t"
            "addl %%edx, %0         \n\t"
                : "+a"(i)
                : "i"(digits)
                : "rdx", "cc"
        );
    return i;
}

static int count_bsr(int i) {
    struct {
            int max;
            int count;
    } static digits[32] = {
            { 9, 1 }, { 9, 1 }, { 9, 1 }, { 9, 1 },
            { 99, 2 }, { 99, 2 }, { 99, 2 },
            { 999, 3 }, { 999, 3 }, { 999, 3 },
            { 9999, 4 }, { 9999, 4 }, { 9999, 4 }, { 9999, 4 },
            { 99999, 5 }, { 99999, 5 }, { 99999, 5 },
            { 999999, 6 }, { 999999, 6 }, { 999999, 6 },
            { 9999999, 7 }, { 9999999, 7 }, { 9999999, 7 }, { 9999999, 7 },
            { 99999999, 8 }, { 99999999, 8 }, { 99999999, 8 },
            { 999999999, 9 }, { 999999999, 9 }, { 999999999, 9 },
            { INT_MAX, 10 }, { INT_MAX, 10 }
    };
        register const int z = 0;
        register unsigned log2;
        if (i < 0) i = -i;
        __asm__ __volatile__ (
                "bsr %1, %0;"  \
                "cmovz %2, %0;"\
                : "=r" (log2)  \
                : "rm" (i), "r"(z));
        return digits[log2].count + ( i > digits[log2].max );
}

/* Structure to control calling of functions. */

typedef struct {
    int (*fnptr)(int);
    const char *desc;
} tFn;

static tFn fn[] = {
 {   NULL,                              NULL },
 {   count_bsr_mod,  "              bsr mod" },
 {   count_bsr,      "                  bsr" },
 {   count_bchop,    "          binary chop" },
 {   count_bsearch,  "        binary search" },
 {   count_bsearch_mod,"    binary search mod"}
};
static clock_t clk[numof (fn)];

int main (int c, char *v[]) {
    int i, j, k, r;
    int s = 1;

    /* Test code:
        printf ("%11d %d\n", INT_MIN, count_bsearch(INT_MIN));
        //for (i = -1000000000; i != 0; i /= 10)
        for (i = -999999999; i != 0; i /= 10)
            printf ("%11d %d\n", i, count_bsearch(i));
        printf ("%11d %d\n", 0, count_bsearch(0));
        for (i = 1; i != 1000000000; i *= 10)
            printf ("%11d %d\n", i, count_bsearch(i));
        printf ("%11d %d\n", 1000000000, count_bsearch(1000000000));
        printf ("%11d %d\n", INT_MAX, count_bsearch(INT_MAX));
    return 0;
    /* */

    /* Randomize and create random pool of numbers. */

    int p, n;
    p = n = 0;
    srand (time (NULL));
    for (j = 0; j < numof (rndnum); j++) {
        rndnum[j] = ((rand() & 2) - 1) * rand();
    }
    rndnum[0] = INT_MAX;
    rndnum[1] = INT_MIN;

    /* For testing. */
    for (k = 0; k < numof (rndnum); k++) {
        rt[k] = (fn[1].fnptr)(rndnum[k]);
    }

    /* Test each of the functions in turn. */

    clk[0] = clock();
    for (i = 1; i < numof (fn); i++) {
        for (j = 0; j < 10000; j++) {
            for (k = 0; k < numof (rndnum); k++) {
                r = (fn[i].fnptr)(rndnum[k]);
                /* Test code:
                    if (r != rt[k]) {
                        printf ("Mismatch error [%s] %d %d %d %d\n",
                            fn[i].desc, k, rndnum[k], rt[k], r);
                        return 1;
                    }
                /* */
            }
        }
        clk[i] = clock();
    }

    /* Print out results. */

    for (i = 1; i < numof (fn); i++) {
        printf ("Time for %s: %10d\n", fn[i].desc, (int)(clk[i] - clk[i-1]));
    }

    return 0;
}

Из Бит Тиддлинг Хаки:

Найти целочисленные логарифм базы 10 из целых чисел очевидным способом

Обратите внимание на порядок сравнений в нем.

Вот развернутый бинарный поиск без деления или умножения. В зависимости от распределения чисел, данных ему, он может или не может побить другие, сделанные с развернутыми операторами if, но всегда должен побеждать те, которые используют циклы и умножение / деление /log10.

С равномерным распределением случайных чисел, охватывающим весь диапазон, на моей машине это составляло в среднем 79% времени выполнения paxdiablo count_bchop(), 88% времени count_ifs() и 97% времени count_revifs().

С экспоненциальным распределением (вероятность того, что число, имеющее n цифр, равно вероятности того, что число имеет m цифр, где mn), count_ifs() и count_revifs () оба превзойдут мою функцию. Я не уверен, почему на этом этапе.

int count_bsearch(int i)
{
    if (i < 0)
    {
        if (i == INT_MIN)
            return 10; // special case for -2^31 because 2^31 can't fit in a two's complement 32-bit integer
        i = -i;
    }
    if              (i < 100000) {
        if          (i < 1000) {
            if      (i < 10)         return 1;
            else if (i < 100)        return 2;
            else                     return 3;
        } else {
            if      (i < 10000)      return 4;
            else                     return 5;
        }
    } else {
        if          (i < 10000000) {
            if      (i < 1000000)    return 6;
            else                     return 7;
        } else {
            if      (i < 100000000)  return 8;
            else if (i < 1000000000) return 9;
            else                     return 10;
        }
    }
}

Ты можешь сделать:floor (log10 (abs (x))) + 1Или, если вы хотите сэкономить на циклах, вы можете просто сделать сравнение

if(x<10)
  return 1;
if(x<100)
  return 2;
if(x<1000)
  return 3;
etc etc

Это позволяет избежать любых дорогостоящих в вычислительном отношении функций, таких как логарифм или даже умножение или деление. Хотя это не элегантно, это можно скрыть, заключив его в функцию. Это не сложно или сложно поддерживать, поэтому я бы не отказался от этого подхода из-за плохой практики кодирования; Я чувствую, что это будет выбросить ребенка с водой в ванной.

Я наткнулся на это во время поиска в Google: http://www.hackersdelight.org/hdcodetxt/ilog.c.txt

Быстрый бенчмарк наглядно показал выигрыш бинарных методов поиска. Код Лакшманараджа довольно хорош, у Александра Коробки на 30% быстрее, у Deadcode чуть-чуть быстрее (~10%), но я обнаружил, что следующие трюки из приведенной выше ссылки дают дополнительное улучшение на 10%.

// Integer log base 10, modified binary search.
int ilog10c(unsigned x) {
   if (x > 99)
      if (x < 1000000)
         if (x < 10000)
            return 3 + ((int)(x - 1000) >> 31);
         // return 3 - ((x - 1000) >> 31);              // Alternative.
         // return 2 + ((999 - x) >> 31);               // Alternative.
         // return 2 + ((x + 2147482648) >> 31);        // Alternative.
         else
            return 5 + ((int)(x - 100000) >> 31);
      else
         if (x < 100000000)
            return 7 + ((int)(x - 10000000) >> 31);
         else
            return 9 + ((int)((x-1000000000)&~x) >> 31);
         // return 8 + (((x + 1147483648) | x) >> 31);  // Alternative.
   else
      if (x > 9)
            return 1;
      else
            return ((int)(x - 1) >> 31);
         // return ((int)(x - 1) >> 31) | ((unsigned)(9 - x) >> 31);  // Alt.
         // return (x > 9) + (x > 0) - 1;                             // Alt.
}

Обратите внимание, что это журнал 10, а не количество цифр, поэтому digits = ilog10c(x)+1,

Не поддерживает негативы, но это легко исправить с помощью -,

if (x == MININT) return 10;  //  abs(MININT) is not defined
x = abs (x);
if (x<10) return 1;
if (x<100) return 2;
if (x<1000) return 3;
if (x<10000) return 4;
if (x<100000) return 5;
if (x<1000000) return 6;
if (x<10000000) return 7;
if (x<100000000) return 8;
if (x<1000000000) return 9;
return 10; //max len for 32-bit integers

Очень не элегантно Но быстрее, чем все другие решения. Журналы с целочисленным делением и FP стоят дорого. Если производительность не проблема, решение log10 - мое любимое решение.

    int n = 437788;
    int N = 1; 
    while (n /= 10) N++; 

Немного подстроимся под язык Си:

floor( log10( abs( (number)?number:1 ) ) + 1 );

Я знаю, что опаздываю, но этот код в + 10 раз быстрее всех других ответов.

int digits(long long x)
{
    x < 0 ? x = -x : 0;
    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 :
        x < 10000000000 ? 10 : 0;
}

...

int x = -937810;
printf("%d : %d digits\n", x, digits(x));

Из:

-937810 : 6 digits

Поскольку никто не упомянул, менее 10^ можно сделать с помощью SIMD. Вот реализация с библиотекой eve для sse2, avx2 и arm-v8.

https://godbolt.org/z/nabPsovqE

Не знаю, насколько это быстро, хотя AVX-2 выглядит неплохо

      count_digits(int):                      # @count_digits(int)
        vmovd   xmm0, edi
        vpbroadcastd    ymm0, xmm0
        vmovdqa ymm1, ymmword ptr [rip + .LCPI0_0] # ymm1 = [10,100,1000,10000,100000,1000000,10000000,100000000]
        vpcmpgtd        ymm0, ymm1, ymm0
        vmovmskps       ecx, ymm0
        bsf     edx, ecx
        add     edx, 1
        xor     esi, esi
        cmp     edi, 1000000000
        setl    sil
        mov     eax, 10
        sub     eax, esi
        test    cl, cl
        cmovne  eax, edx
        vzeroupper
        ret

Простой способ найти длину (то есть количество цифр) целого числа со знаком заключается в следующем:

while ( abs(n) > 9 )
{
    num /= 10;
    ++len;
}

куда n целое число, которое вы хотите найти длину и где len равно количеству цифр в целом числе. Это работает для обоих значений n (отрицательный или положительный).

Вызов на abs() необязательно, если вы работаете только с положительными целыми числами.

НЕ используйте пол (log10(...)). Это функции с плавающей точкой и медленные, чтобы добавить. Я считаю, что самым быстрым способом была бы эта функция:

int ilog10(int num)
{
   unsigned int num = abs(num);
   unsigned int x, i;
   for(x=10, i=1; ; x*=10, i++)
   {
      if(num < x)
         return i;
      if(x > INT_MAX/10)
         return i+1;
   }
}

Обратите внимание, что версия двоичного поиска, предложенная некоторыми людьми, может быть медленнее из-за неправильных прогнозов веток.

РЕДАКТИРОВАТЬ:

Я провел некоторое тестирование и получил действительно интересные результаты. Я рассчитал время своей функции вместе со всеми функциями, проверенными Pax, И функцией бинарного поиска, предоставленной lakshmanaraj. Тестирование выполняется следующим фрагментом кода:

start = clock();
for(int i=0; i<10000; i++)
   for(int j=0; j<10000; j++)
      tested_func(numbers[j]);
end = clock();
tested_func_times[pass] = end-start;

Где массив numbers[] содержит случайно сгенерированные числа во всем диапазоне типа int (за исключением MIN_INT). Тестирование повторялось для каждой тестируемой функции в массиве ОДИНАКОВЫЕ числа []. Весь тест был выполнен 10 раз, с результатами, усредненными по всем проходам. Код был скомпилирован с GCC 4.3.2 с уровнем оптимизации -O3.

Вот результаты:

floating-point log10:     10340ms
recursive divide:         3391ms
iterative divide:         2289ms
iterative multiplication: 1071ms
unrolled tests:           859ms
binary search:            539ms

Должен сказать, я очень удивился. Бинарный поиск работал намного лучше, чем я думал. Я проверил, как GCC скомпилировал этот код в asm. О_О. Теперь это впечатляет. Он был оптимизирован гораздо лучше, чем я думал, избегая большинства веток действительно умными способами. Не удивительно, что это БЫСТРО.

Я думаю, самый простой способ был бы:

 int digits = 0;
if (number < 0) digits = 1;
while (number) {
    number /= 10;
    digits++;
}

цифры дают ответ.

void main()
{     
    int a,i;
    printf("Enter the number :");       
    scanf("%d",&a);

    while(a>0)     
    {
        a=a/10;   
        i++;  
    }

    getch();
}

Вы можете найти количество цифр в числе, используя этот формат ceil (log10 (abs (x))), где ceil возвращает целое число, которое больше, чем число

Для C# вот очень быстрое и простое решение...

    private static int NumberOfPlaces(int n)
    {
       //fast way to get number of digits
       //converts to signed string with +/- intact then accounts for it by subtracting 1
       return n.ToString("+#;-#;+0").Length-1;
    }
Другие вопросы по тегам