25 ответов:
ну, самый эффективный способ, предполагая, что вы знаете размер целого числа, будет поиск. Должно быть быстрее, чем гораздо более короткий логарифмический подход. Если вы не заботитесь о подсчете ' - ' удалить + 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]; }
самый простой способ это сделать:
unsigned GetNumberOfDigits (unsigned i) { return i > 0 ? (int) log10 ((double) i) + 1 : 1; }log10 определяется в
<cmath>или<math.h>. Вам понадобится профиль, чтобы увидеть, если это быстрее, чем любой из других, размещенных здесь. Я не уверен, насколько это надежно в отношении точности с плавающей точкой. Кроме того, аргумент не имеет знака, поскольку отрицательные значения и журнал на самом деле не смешиваются.
возможно, я неправильно понял вопрос, но разве это не сделать это?
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++; }Примечание: "0" будет иметь 0 цифр! Если вам нужно 0, чтобы иметь 1 цифру, используйте:
int digits = 0; do { number /= 10; digits++; } while (number != 0);(Спасибо Кевин Фега)
в конце концов, используйте профилировщик, чтобы узнать, какой из всех ответов здесь будет быстрее на вашем компьютере...
шутка: Это the наиболее эффективный способ (количество цифр вычисляется во время компиляции):
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 }; };может быть полезно, чтобы определить ширину, необходимую для поля количество в форматирование, элементы ввода и т. д.
посмотреть Немного Вертя Хаки для гораздо более короткой версии ответа, который вы приняли. Он также имеет преимущество поиска ответа раньше, если ваш вход нормально распределен, сначала проверяя большие константы.
(v >= 1000000000)ловит 76% значений, поэтому проверка, что первый будет в среднем быстрее.
преобразовать в строку, а затем использовать встроенные функции
unsigned int i; cout<< to_string(i).length()<<endl;
предыдущий плакат предложил цикл, который делится на 10. Поскольку умножение на современных машинах намного быстрее, я бы рекомендовал вместо этого следующий код:
int digits = 1, pten=10; while ( pten <= number ) { digits++; pten*=10; }
архитектура ppc имеет инструкцию по подсчету бит. При этом вы можете определить лог-базу 2 положительного целого числа в одной инструкции. Например, 32 бит будет:
#define log_2_32_ppc(x) (31-__cntlzw(x))Если вы можете обрабатывать небольшую погрешность при больших значениях, вы можете преобразовать ее в log base 10 с помощью еще нескольких инструкций:
#define log_10_estimate_32_ppc(x) (9-(((__cntlzw(x)*1233)+1545)>>12))это специфично для платформы и немного неточно, но также не включает в себя ветви, разделение или преобразование в плавающую точку. Все зависит от того, что вам нужно.
Я знаю только инструкции ppc от руки, но другие архитектуры должны иметь аналогичные инструкции.
#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; }Это, вероятно, самый простой способ решения вашей проблемы, предполагая, что вы заботитесь только о цифрах перед десятичным числом и предполагая, что что-то меньше 10-это всего лишь 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 */ 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 ) ) ); }
Мне нравится ответ Айры Бакстера. Вот вариант шаблона, который обрабатывает различные размеры и имеет дело с максимальными целыми значениями (обновляется для подъема верхней границы проверки из цикла):
#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; }чтобы на самом деле получить улучшенную производительность от подъема дополнительного теста из цикла, вам нужно специализировать max_decimal() для возврата констант для каждого типа на вашей платформе. Достаточно волшебный компилятор может оптимизировать вызов max_decimal() до константы, но специализация лучше с большинством компиляторов сегодня. В нынешнем виде эта версия, вероятно, медленнее, потому что max_decimal стоит больше, чем тесты, удаленные из цикла.
Я оставлю все это в качестве упражнения для читателя.
/// Determine the number of digits for a 64 bit integer. /// - Uses at most 5 comparisons. /// - (cX) 2014 [email protected] /// - \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 ) ) ) ); }
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); } };, где в
powers_and_maxу нас есть(10^n)-1для всехnтакое, что
(10^n) <std::numeric_limits<type>::max()и
std::numeric_limits<type>::max()в массиве: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()); } };вот простой тест:
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);конечно, любая другая реализация упорядоченного набора может быть использована для
powers_and_maxи если бы было знание, что будет кластеризация, но нет знания о том, где кластер может быть, возможно, самонастраивающаяся реализация дерева может быть лучший
эффективным способом
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; }
еще один фрагмент кода, делая в основном то же самое, что и Виталий, но использует двоичный поиск. Массив полномочий лениво инициализируется один раз на экземпляр типа без знака. Знаковый тип перегрузки заботится о знаке минус.
#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) ); }Если кто-то заботится о дальнейшей оптимизации, обратите внимание, что первый элемент массива полномочия никогда не используется, а
lпоявляется+12 раза.
в случае, если количество цифр и значение каждой позиции необходимо использовать так:
int64_t = number, digitValue, digits = 0; // or "int" for 32bit while (number != 0) { digitValue = number % 10; digits ++; number /= 10; }
digitдает вам значение в позиции номер, который в настоящее время обрабатывается в цикле. например, для числа 1776 значение цифры:
6 в 1 цикл
7 во 2-м цикле
7 в 3-м цикле
1 в 4-м цикле
C++11 обновление предпочтительного решения:
#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; }предотвращает создание экземпляра шаблона с помощью double, et. Эл.
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; }
// 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) );
int numberOfDigits(int n){ if(n<=9){ return 1; } return 1 + numberOfDigits(n/10); }Это то, что я бы сделал, если вы хотите его для базы 10.Его довольно быстро, и вы, вероятно, не получите стека переполнения купить подсчет целых чисел
для целого числа " X " вы хотите знать количество цифр , хорошо , без использования какого-либо цикла, это решение действует в одной формуле только в одной строке, поэтому это самое оптимальное решение, которое я когда-либо видел для этой проблемы .
int x = 1000 ; cout<<numberOfDigits = 1+floor(log10(x))<<endl ;
Это мой способ сделать это:
int digitcount(int n) { int count = 1; int temp = n; while (true) { temp /= 10; if (temp != 0) ++count; if (temp == 0) break; } return count; }
вот другой подход:
digits = sprintf(numArr, "%d", num); // where numArr is a char array if (num < 0) digits--;Это не может быть эффективным, просто что-то другое, чем то, что другие предлагали.
Comments