C ++에서 정수에 몇 자릿수가 있는지 결정하는 가장 효율적인 방법은 무엇입니까 ?
C ++에서 정수에 몇 자릿수가 있는지 결정하는 가장 효율적인 방법은 무엇입니까 ?
답변:
음, 정수의 크기를 알고 있다고 가정하면 가장 효율적인 방법은 조회입니다. 훨씬 짧은 대수 기반 접근 방식보다 빠릅니다. '-'계산에 신경 쓰지 않으면 + 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>
있습니다. 여기에 게시 된 다른 것보다 빠른지 확인하려면이 프로파일을 작성해야합니다. 부동 소수점 정밀도와 관련하여 이것이 얼마나 강력한 지 잘 모르겠습니다. 또한 인수는 음수 값으로 부호가 없으며 로그는 실제로 혼합되지 않습니다.
-fpfast
x87 대신 SSE instrinsics를 사용하면 정밀도 IIRC에 대한 보증이 줄어 듭니다. 그러나 기본적으로 아무런 문제가 없습니다.
아마도 나는 그 질문을 잘못 이해했지만 그렇지 않습니까?
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 자리입니다. 1 자리 숫자가 0으로 나타나려면 다음을 사용하십시오.
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 };
};
서식, 입력 요소 등에서 숫자 필드에 필요한 너비를 결정하는 데 유용 할 수 있습니다.
0
하며 기본에 실패 1
:)과베이스는 다음과 같이 주어지면 제로 오류에 의해 분할을 제공합니다 0
. 그래도 고칠 수 있습니다. 어쨌든 나는 아주 오래된 게시물을 nitpicking하고 있습니다. 죄송합니다. 이것이 농담 일 필요는 없으며 실제로 유용 할 수 있다고 생각합니다.
수락 한 답변의 훨씬 짧은 버전은 Bit Twiddling Hacks 를 참조하십시오 . 또한 큰 상수를 먼저 확인하여 입력이 정상적으로 분포되면 답변을 더 빨리 찾을 수 있다는 이점이 있습니다. (v >= 1000000000)
값의 76 %를 포착하므로 평균적으로 먼저 확인하는 것이 더 빠릅니다.
이전 포스터는 10으로 나누는 루프를 제안했습니다. 최신 컴퓨터에서는 곱하기가 훨씬 빠르므로 대신 다음 코드를 사용하는 것이 좋습니다.
int digits = 1, pten=10; while ( pten <= number ) { digits++; pten*=10; }
ppc 아키텍처에는 비트 카운팅 명령이 있습니다. 이를 통해 단일 명령어로 양의 정수의 로그베이스 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 자리라고 가정하면 문제를 해결하는 가장 간단한 방법 일 것입니다.
Ira Baxter의 답변이 마음에 듭니다. 다음은 다양한 크기를 처리하고 최대 정수 값을 처리하는 템플릿 변형입니다 (루프에서 상한 점검을 수행하도록 업데이트 됨).
#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이 루프에서 제거 된 테스트보다 비용이 많이 들기 때문에이 버전이 더 느릴 수 있습니다.
모든 것을 독자의 연습으로 남겨 두겠습니다.
#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
)
)
);
}
또 다른 코드 스 니펫은 기본적으로 Vitali와 동일하지만 이진 검색을 사용합니다. Powers 배열은 서명되지 않은 유형 인스턴스마다 한 번씩 지연 초기화됩니다. 부호있는 유형 과부하는 빼기 부호를 처리합니다.
#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 배열의 첫 번째 요소는 사용되지 않으며이 l
표시는 +1
2 번 나타납니다 .
// 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
)
)
)
);
}
정수 'X'의 경우 루프를 사용하지 않고 자릿수를 알고 싶습니다.이 솔루션은 한 줄로 하나의 수식으로 만 작동 하므로이 문제에 대해 가장 최적의 솔루션입니다.
int x = 1000 ;
cout<<numberOfDigits = 1+floor(log10(x))<<endl ;
double
? 로 변환 될 때 아니면 INT_MAX 십진수로 불가능한 정수 입력을 언급하고 있습니까? 어느 쪽도 다른 대답에 모두 실패합니까?
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";
더 빠를수록 더 효율적이며, andrei alexandrescu의 개선 입니다. 그의 버전은 이미 순진한 방법보다 빠르다 (모든 숫자에서 10으로 나눔). 아래 버전은 모든 크기의 x86-64 및 ARM에서 일정 시간 이상 빨라지지만 이진 코드의 두 배를 차지하므로 캐시 친화적이지 않습니다.
이 버전의 벤치 마크 와 페이스 북의 내 PR에서 alexandrescu의 버전은 folly 입니다.
작동 unsigned
하지 않습니다 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);
}
사용자가 숫자에 몇 자릿수가 있는지 정확하게 대답했는지 확인 해야하는 프로그램을 개발하고 있었으므로 정수의 자릿수를 확인하는 방법을 개발해야했습니다. 결국 비교적 쉽게 해결할 수 있습니다.
double check=0, exponent=1000;
while(check<=1)
{
check=number/pow(10, exponent);
exponent--;
}
exponent=exponent+2;
cout<<exponent<<endl;
이것은 내 대답으로 끝났으며 현재 10 ^ 1000 자릿수 미만의 숫자로 작동합니다 (지수 값을 변경하여 변경할 수 있음).
추신 : 나는이 답변이 10 년 늦었다는 것을 알고 있지만 2020 년에 도착하여 다른 사람들이 사용할 수 있습니다.
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;
}
선호하는 솔루션의 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 등으로 템플릿 인스턴스화를 방지합니다. 알.
이것이 내 방법입니다.
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--;
이것은 효율적이지 않을 수 있으며 다른 사람들이 제안한 것과는 다른 것입니다.