有效的方法来确定一个整数中的位数
什么是一个非常有效的方法来确定在C + +中的整数有多less数字?
那么,假定你知道整数的大小,最有效的方法就是查找。 应该比基于对数的更短的方法更快。 如果你不在乎数“ – ”,那么删除+ 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);
(感谢Kevin Fegan)
最后,使用一个分析器来知道你的机器上哪个答案会更快。
实用的笑话:这是最有效的方法(数字的数量在编译时计算):
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 }; };
可能有助于确定格式化中的数字字段所需的宽度,input元素等
请参阅Bit Twiddling Hacks获取您接受的答案的简短版本。 如果你的input是正态分布的,通过首先检查大的常量,它也可以更快地find答案。 (v >= 1000000000)
获得了76%的值,所以首先检查的平均速度会更快。
转换为string,然后使用内置函数
unsigned int i; cout<< to_string(i).length()<<endl;
以前的海报提出了一个循环,除以10。由于现代机器上的乘法速度要快很多,所以我build议使用下面的代码:
int digits = 1, pten=10; while ( pten <= number ) { digits++; pten*=10; }
ppc体系结构有一些计数指令。 用这个,你可以在一个指令中确定一个正整数的logging底数2。 例如,32位将是:
#define log_2_32_ppc(x) (31-__cntlzw(x))
如果你可以在较大的值上处理一个小的误差,你可以用下面的几条指令把它转换成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 <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; }
为了将附加testing从循环中提升出来,需要专门化max_decimal()来返回平台上每种types的常量。 一个足够神奇的编译器可以将对max_decimal()的调用优化为一个常量,但是现在大多数编译器的专业化程度会更高。 就目前而言,这个版本可能会比较慢,因为max_decimal比从循环中移除的testing花费更多。
我将把这一切留给读者作为练习。
#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 ) ) ); }
/// 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 ) ) ) ); }
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()); } };
这是一个简单的testing:
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; }
还有另一个代码片段,基本上和Vitali一样,但是使用了二进制search。 Powers数组是每个无符号types实例延迟初始化一次。 签名types过载负责减号。
#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) ); }
如果有人关心进一步的优化,请注意powers array的第一个元素是不会被使用的,而l
出现+1
两次。
如果需要使用这个数字的位数和每个数字位置的值,
int64_t = number, digitValue, digits = 0; // or "int" for 32bit while (number != 0) { digitValue = number % 10; digits ++; number /= 10; }
digit
为您提供当前在循环中处理的号码的值。 例如对于数字1776数字值是:
在第一回合6
7在第二回路
7在第三循环
1在第四循环中
C ++ 11更新的首选解决scheme:
#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的模板实例化等。 人。
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) );
对于整数'X'你想知道的位数,没有使用任何循环好,这个解决scheme在一行只有一个公式,所以这是我见过这个问题的最佳解决scheme。
int x = 1000 ; cout<<numberOfDigits = 1+floor(log10(x))<<endl ;
这是一个不同的方法:
digits = sprintf(numArr, "%d", num); // where numArr is a char array if (num < 0) digits--;
这可能效率不高,只是别人的build议。
这是我的方式来做到这一点:
int digitcount(int n) { int count = 1; int temp = n; while (true) { temp /= 10; if (temp != 0) ++count; if (temp == 0) break; } return count; }