C에서 1123456789에서 1,123,456,789까지의 숫자를 포맷하려면 어떻게 해야 합니까?
하면 C의 숫자를 C 언어 할 수 요?1123456789
로로 합니다.1,123,456,789
.printf("%'10d\n", 1123456789);
지만만소소소소소
조언 좀 해주시겠어요?솔루션은 단순할수록 좋습니다.
가 printf를 하는 '
플래그(POSIX 2008에서 요구된 대로)는 로케일을 적절히 설정하는 것만으로 실행할 수 있습니다.예제:
#include <stdio.h>
#include <locale.h>
int main(void)
{
setlocale(LC_NUMERIC, "");
printf("%'d\n", 1123456789);
return 0;
}
구축 및 실행:
$ ./example
1,123,456,789
Mac OS X 및 Linux (Ubuntu 10.10)에서 테스트 완료.
할 수 하세요).INT_MIN
2개의 보완을 사용하는 경우 이를 관리하려면 추가 코드가 필요합니다.)
void printfcomma2 (int n) {
if (n < 1000) {
printf ("%d", n);
return;
}
printfcomma2 (n/1000);
printf (",%03d", n%1000);
}
void printfcomma (int n) {
if (n < 0) {
printf ("-");
n = -n;
}
printfcomma2 (n);
}
요약:
- 가 " " 를 호출합니다.
printfcomma
는 단순히 양수(은 "-"와 함께 사용할 수입니다)로 으로 처리됩니다.INT_MIN
를 참조해 주세요. - 「 」를
printfcomma2
1돌려줍니다. - 그렇지 않으면 재귀는 다음 레벨 업으로 호출됩니다(따라서 1,234,567은 1,234로 호출되고 그 후 1로 호출됩니다).이 경우 1,000 미만의 수치가 검출됩니다.
- 그런 다음 해당 번호가 인쇄되고 재귀 트리로 돌아가서 쉼표와 다음 숫자를 인쇄합니다.
또한 보다 간결한 버전도 있습니다.단, 모든 레벨에서 음수를 체크할 때 불필요한 처리를 합니다(재귀 레벨의 수가 한정되어 있기 때문에 이것이 문제가 되는 것은 아닙니다).이 프로그램은 완벽한 테스트 프로그램입니다.
#include <stdio.h>
void printfcomma (int n) {
if (n < 0) {
printf ("-");
printfcomma (-n);
return;
}
if (n < 1000) {
printf ("%d", n);
return;
}
printfcomma (n/1000);
printf (",%03d", n%1000);
}
int main (void) {
int x[] = {-1234567890, -123456, -12345, -1000, -999, -1,
0, 1, 999, 1000, 12345, 123456, 1234567890};
int *px = x;
while (px != &(x[sizeof(x)/sizeof(*x)])) {
printf ("%-15d: ", *px);
printfcomma (*px);
printf ("\n");
px++;
}
return 0;
}
출력은 다음과 같습니다.
-1234567890 : -1,234,567,890
-123456 : -123,456
-12345 : -12,345
-1000 : -1,000
-999 : -999
-1 : -1
0 : 0
1 : 1
999 : 999
1000 : 1,000
12345 : 12,345
123456 : 123,456
1234567890 : 1,234,567,890
재귀를 신뢰하지 않는 사용자를 위한 반복적인 솔루션(재귀의 유일한 문제는 스택 공간인 경향이 있지만 64비트 정수라도 깊이가 몇 단계밖에 되지 않기 때문에 여기서는 문제가 되지 않습니다).
void printfcomma (int n) {
int n2 = 0;
int scale = 1;
if (n < 0) {
printf ("-");
n = -n;
}
while (n >= 1000) {
n2 = n2 + scale * (n % 1000);
n /= 1000;
scale *= 1000;
}
printf ("%d", n);
while (scale != 1) {
scale /= 1000;
n = n2 / scale;
n2 = n2 % scale;
printf (",%03d", n);
}
}
다 '먹다'를 만들어 냅니다.2,147,483,647
★★★★★★에INT_MAX
.
위의 모든 코드는 쉼표로 구분된 세 자리 그룹용이지만 공백과 같은 다른 문자도 사용할 수 있습니다.
void printfspace2 (int n) {
if (n < 1000) {
printf ("%d", n);
return;
}
printfspace2 (n/1000);
printf (" %03d", n%1000);
}
void printfspace (int n) {
if (n < 0) {
printf ("-");
n = -n;
}
printfspace2 (n);
}
egads! 저는 항상 gcc/g++와 glibc를 Linux에서 사용하고 있습니다.그래서 ' 연산자는 비표준일 수도 있지만, 심플한 것이 마음에 듭니다.
#include <stdio.h>
#include <locale.h>
int main()
{
int bignum=12345678;
setlocale(LC_ALL,"");
printf("Big number: %'d\n",bignum);
return 0;
}
다음 출력을 제공합니다.
빅 넘버: 12,345,678
거기 있는 '셋로케일' 통화만 기억하면 됩니다. 그렇지 않으면 아무것도 포맷되지 않습니다.
나 자신도 비슷한 일을 해야 했지만 직접 인쇄하는 것보다 버퍼에 들어가야 했다.내가 생각해낸 건 이거야역방향으로 동작합니다.
unsigned int IntegerToCommaString(char *String, unsigned long long Integer)
{
unsigned int Digits = 0, Offset, Loop;
unsigned long long Copy = Integer;
do {
Digits++;
Copy /= 10;
} while (Copy);
Digits = Offset = ((Digits - 1) / 3) + Digits;
String[Offset--] = '\0';
Copy = Integer;
Loop = 0;
do {
String[Offset] = '0' + (Copy % 10);
if (!Offset--)
break;
if (Loop++ % 3 == 2)
String[Offset--] = ',';
Copy /= 10;
} while (1);
return Digits;
}
이는 부호 없는 정수만을 위해 설계되었으며 버퍼 크기가 충분한지 확인해야 합니다.
#include <stdio.h>
void punt(long long n){
char s[28];
int i = 27;
if(n<0){n=-n; putchar('-');}
do{
s[i--] = n%10 + '0';
if(!(i%4) && n>9)s[i--]='.';
n /= 10;
}while(n);
puts(&s[++i]);
}
int main(){
punt(2134567890);
punt(987);
punt(9876);
punt(-987);
punt(-9876);
punt(-654321);
punt(0);
punt(1000000000);
punt(0x7FFFFFFFFFFFFFFF);
punt(0x8000000000000001); // -max + 1 ...
}
솔루션에서는 가 아닌 .를 사용하고 있습니다.이 변경은 독자에게 맡겨집니다.
C에서 이것을 하는 정말 간단한 방법은 없습니다.int-to-string 함수를 수정하기만 하면 됩니다.
void format_number(int n, char * out) {
int i;
int digit;
int out_index = 0;
for (i = n; i != 0; i /= 10) {
digit = i % 10;
if ((out_index + 1) % 4 == 0) {
out[out_index++] = ',';
}
out[out_index++] = digit + '0';
}
out[out_index] = '\0';
// then you reverse the out string as it was converted backwards (it's easier that way).
// I'll let you figure that one out.
strrev(out);
}
다른 해결책으로,를 into른른른 an an an an an an an an the an the the the the 에 저장함으로써int
입니다. 7은 7은 7인 경우 7은 7은 7은 7은 7은 7이 됩니다.long long int
type은 9,223,372,036,854,775,807 ~ -9,223,372,036,854,775,807 범위의 숫자를 처리할 수 있습니다(부호 없는 값은 아닙니다).
비재귀 인쇄 기능
static void printNumber (int numbers[8], int loc, int negative)
{
if (negative)
{
printf("-");
}
if (numbers[1]==-1)//one number
{
printf("%d ", numbers[0]);
}
else
{
printf("%d,", numbers[loc]);
while(loc--)
{
if(loc==0)
{// last number
printf("%03d ", numbers[loc]);
break;
}
else
{ // number in between
printf("%03d,", numbers[loc]);
}
}
}
}
주요 함수 호출
static void getNumWcommas (long long int n, int numbers[8])
{
int i;
int negative=0;
if (n < 0)
{
negative = 1;
n = -n;
}
for(i = 0; i < 7; i++)
{
if (n < 1000)
{
numbers[i] = n;
numbers[i+1] = -1;
break;
}
numbers[i] = n%1000;
n/=1000;
}
printNumber(numbers, i, negative);// non recursive print
}
테스트 출력
-9223372036854775807: -9,223,372,036,854,775,807
-1234567890 : -1,234,567,890
-123456 : -123,456
-12345 : -12,345
-1000 : -1,000
-999 : -999
-1 : -1
0 : 0
1 : 1
999 : 999
1000 : 1,000
12345 : 12,345
123456 : 123,456
1234567890 : 1,234,567,890
9223372036854775807 : 9,223,372,036,854,775,807
main() 함수:
int numberSeparated[8];
long long int number = 1234567890LL;
getNumWcommas(number, numberSeparated);
되는 는, 주세요.int numberSeparated[8];
의 getNumWcommas
getNumWcommas(number)
.
여기 매우 간단한 구현이 있습니다.이 함수에는 에러 체크가 포함되어 있지 않습니다.버퍼 사이즈는 호출자가 확인해야 합니다.또한 음수에도 효과가 없습니다.그러한 개선은 독자들에게 연습으로 남는다.
void format_commas(int n, char *out)
{
int c;
char buf[20];
char *p;
sprintf(buf, "%d", n);
c = 2 - strlen(buf) % 3;
for (p = buf; *p != 0; p++) {
*out++ = *p;
if (c == 1) {
*out++ = ',';
}
c = (c + 1) % 3;
}
*--out = 0;
}
사항: 구구항 require:<stdio.h>
+<string.h>
.
: 장 : 결, on on on on on on on on on 에 따라 짧고 쉬운,format
scanf
family . - 아, 가 없다고 합니다.소수점 오른쪽에 쉼표가 없다고 가정합니다.
void add_commas(char *in, char *out) {
int len_in = strlen(in);
int len_int = -1; /* len_int(123.4) = 3 */
for (int i = 0; i < len_in; ++i) if (in[i] == '.') len_int = i;
int pos = 0;
for (int i = 0; i < len_in; ++i) {
if (i>0 && i<len_int && (len_int-i)%3==0)
out[pos++] = ',';
out[pos++] = in[i];
}
out[pos] = 0; /* Append the '\0' */
}
예를 들어, 포맷된 이중을 인쇄하려면:
#include <stdio.h>
#include <string.h>
#define COUNT_DIGIT_MAX 100
int main() {
double sum = 30678.7414;
char input[COUNT_DIGIT_MAX+1] = { 0 }, output[COUNT_DIGIT_MAX+1] = { 0 };
snprintf(input, COUNT_DIGIT_MAX, "%.2f", sum/12);
add_commas(input, output);
printf("%s\n", output);
}
출력:
2,556.56
꽤 쉽게 할 수 있다...
//Make sure output buffer is big enough and that input is a valid null terminated string
void pretty_number(const char* input, char * output)
{
int iInputLen = strlen(input);
int iOutputBufferPos = 0;
for(int i = 0; i < iInputLen; i++)
{
if((iInputLen-i) % 3 == 0 && i != 0)
{
output[iOutputBufferPos++] = ',';
}
output[iOutputBufferPos++] = input[i];
}
output[iOutputBufferPos] = '\0';
}
호출 예:
char szBuffer[512];
pretty_number("1234567", szBuffer);
//strcmp(szBuffer, "1,234,567") == 0
제 답변은 질문의 그림과 같은 형식의 결과는 아니지만, 경우에 따라서는 간단한 원라이너 또는 매크로로 실제 요구를 충족시킬 수 있습니다.필요에 따라 1,000개 이상의 그룹을 생성하도록 확장할 수 있습니다.
결과는 다음과 같습니다.
Value: 0'000'012'345
코드:
printf("Value: %llu'%03lu'%03lu'%03lu\n", (value / 1000 / 1000 / 1000), (value / 1000 / 1000) % 1000, (value / 1000) % 1000, value % 1000);
이것은 오래되고 답변이 많지만, 질문은 "쉼표를 추가하는 루틴을 어떻게 쓸 수 있는가?"가 아니라 "C에서 어떻게 할 수 있는가?"였습니다.코멘트는 이 방향을 가리키고 있습니다만, GCC를 탑재한 Linux 시스템에서는 다음과 같이 대응하고 있습니다.
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
unsetenv("LC_ALL");
setlocale(LC_NUMERIC, "");
printf("%'lld\n", 3141592653589);
}
실행 시 다음 메시지가 나타납니다.
$ cc -g comma.c -o comma && ./comma
3,141,592,653,589
를 LC_ALL
에 변수입니다.unsetenv
는 필요 없습니다.
저는 C프로그래밍을 처음 합니다.여기 제 간단한 코드가 있습니다.
int main()
{
// 1223 => 1,223
int n;
int a[10];
printf(" n: ");
scanf_s("%d", &n);
int i = 0;
while (n > 0)
{
int temp = n % 1000;
a[i] = temp;
n /= 1000;
i++;
}
for (int j = i - 1; j >= 0; j--)
{
if (j == 0)
{
printf("%d.", a[j]);
}
else printf("%d,",a[j]);
}
getch();
return 0;
}
@Greg Hewgill을 기반으로 하지만 음수를 고려하여 문자열 크기를 반환합니다.
size_t str_format_int_grouped(char dst[16], int num)
{
char src[16];
char *p_src = src;
char *p_dst = dst;
const char separator = ',';
int num_len, commas;
num_len = sprintf(src, "%d", num);
if (*p_src == '-') {
*p_dst++ = *p_src++;
num_len--;
}
for (commas = 2 - num_len % 3;
*p_src;
commas = (commas + 1) % 3)
{
*p_dst++ = *p_src++;
if (commas == 1) {
*p_dst++ = separator;
}
}
*--p_dst = '\0';
return (size_t)(p_dst - dst);
}
아마 로케일 인식 버전이 흥미로울 것입니다.
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <limits.h>
static int next_group(char const **grouping) {
if ((*grouping)[1] == CHAR_MAX)
return 0;
if ((*grouping)[1] != '\0')
++*grouping;
return **grouping;
}
size_t commafmt(char *buf, /* Buffer for formatted string */
int bufsize, /* Size of buffer */
long N) /* Number to convert */
{
int i;
int len = 1;
int posn = 1;
int sign = 1;
char *ptr = buf + bufsize - 1;
struct lconv *fmt_info = localeconv();
char const *tsep = fmt_info->thousands_sep;
char const *group = fmt_info->grouping;
char const *neg = fmt_info->negative_sign;
size_t sep_len = strlen(tsep);
size_t group_len = strlen(group);
size_t neg_len = strlen(neg);
int places = (int)*group;
if (bufsize < 2)
{
ABORT:
*buf = '\0';
return 0;
}
*ptr-- = '\0';
--bufsize;
if (N < 0L)
{
sign = -1;
N = -N;
}
for ( ; len <= bufsize; ++len, ++posn)
{
*ptr-- = (char)((N % 10L) + '0');
if (0L == (N /= 10L))
break;
if (places && (0 == (posn % places)))
{
places = next_group(&group);
for (int i=sep_len; i>0; i--) {
*ptr-- = tsep[i-1];
if (++len >= bufsize)
goto ABORT;
}
}
if (len >= bufsize)
goto ABORT;
}
if (sign < 0)
{
if (len >= bufsize)
goto ABORT;
for (int i=neg_len; i>0; i--) {
*ptr-- = neg[i-1];
if (++len >= bufsize)
goto ABORT;
}
}
memmove(buf, ++ptr, len + 1);
return (size_t)len;
}
#ifdef TEST
#include <stdio.h>
#define elements(x) (sizeof(x)/sizeof(x[0]))
void show(long i) {
char buffer[32];
commafmt(buffer, sizeof(buffer), i);
printf("%s\n", buffer);
commafmt(buffer, sizeof(buffer), -i);
printf("%s\n", buffer);
}
int main() {
long inputs[] = {1, 12, 123, 1234, 12345, 123456, 1234567, 12345678 };
for (int i=0; i<elements(inputs); i++) {
setlocale(LC_ALL, "");
show(inputs[i]);
}
return 0;
}
#endif
이것은 버그를 가지고 있습니다(그러나 매우 사소한 것으로 생각됩니다).가 가장 를 2의 하려고 하기 때문입니다.N = -N;
2의 덧셈에서 최대 음수는 더 큰 형식으로 승격하지 않는 한 대응하는 양수를 가지지 않습니다.이것을 회피하는 한 가지 방법은 대응하는 부호 없는 타입의 번호를 승격하는 것입니다(다만, 다소 간단하지 않습니다).
재귀 또는 문자열 처리가 없는 경우 다음과 같은 수학적 접근법:
#include <stdio.h>
#include <math.h>
void print_number( int n )
{
int order_of_magnitude = (n == 0) ? 1 : (int)pow( 10, ((int)floor(log10(abs(n))) / 3) * 3 ) ;
printf( "%d", n / order_of_magnitude ) ;
for( n = abs( n ) % order_of_magnitude, order_of_magnitude /= 1000;
order_of_magnitude > 0;
n %= order_of_magnitude, order_of_magnitude /= 1000 )
{
printf( ",%03d", abs(n / order_of_magnitude) ) ;
}
}
원칙적으로는 팍스의 재귀 솔루션과 비슷하지만, 사전에 규모 순서를 계산함으로써 재귀가 회피됩니다(아마도 상당한 비용이 들 것입니다).
또한 수천을 구분하기 위해 사용되는 실제 문자는 로케일에 따라 다릅니다.
편집:개선에 대해서는 아래 @Chux의 코멘트를 참조해 주세요.
또 다른 반복 함수
int p(int n) {
if(n < 0) {
printf("-");
n = -n;
}
int a[sizeof(int) * CHAR_BIT / 3] = { 0 };
int *pa = a;
while(n > 0) {
*++pa = n % 1000;
n /= 1000;
}
printf("%d", *pa);
while(pa > a + 1) {
printf(",%03d", *--pa);
}
}
이 십진법 형식의 가장 슬림하고 크기 및 속도 효율이 뛰어난 구현을 다음에 나타냅니다.
const char *formatNumber (
int value,
char *endOfbuffer,
bool plus)
{
int savedValue;
int charCount;
savedValue = value;
if (unlikely (value < 0))
value = - value;
*--endOfbuffer = 0;
charCount = -1;
do
{
if (unlikely (++charCount == 3))
{
charCount = 0;
*--endOfbuffer = ',';
}
*--endOfbuffer = (char) (value % 10 + '0');
}
while ((value /= 10) != 0);
if (unlikely (savedValue < 0))
*--endOfbuffer = '-';
else if (unlikely (plus))
*--endOfbuffer = '+';
return endOfbuffer;
}
다음과 같이 사용합니다.
char buffer[16];
fprintf (stderr, "test : %s.", formatNumber (1234567890, buffer + 16, true));
출력:
test : +1,234,567,890.
장점:
역순서 포맷으로 인해 문자열 버퍼의 끝을 차지하는 함수입니다.마지막으로 생성된 문자열(strrev)을 리버링할 필요가 없습니다.
이 함수는 이후 모든 문자열에서 사용할 수 있는 문자열을 1개 생성합니다.printf/sprintf 콜에 의존하거나 여러 개의 printf/sprintf 콜을 필요로 하지 않습니다.이것은 매우 느리고 항상 컨텍스트에 따라 다릅니다.
- 분할 연산자의 최소 수(/, %)입니다.
Secure format_commas(음수 포함):
VS < 2015 에서는 snprintf 를 실장하고 있지 않기 때문에, 이 조작할 필요가 있습니다.
#if defined(_WIN32)
#define snprintf(buf,len, format,...) _snprintf_s(buf, len,len, format, __VA_ARGS__)
#endif
그리고 나서.
char* format_commas(int n, char *out)
{
int c;
char buf[100];
char *p;
char* q = out; // Backup pointer for return...
if (n < 0)
{
*out++ = '-';
n = abs(n);
}
snprintf(buf, 100, "%d", n);
c = 2 - strlen(buf) % 3;
for (p = buf; *p != 0; p++) {
*out++ = *p;
if (c == 1) {
*out++ = '\'';
}
c = (c + 1) % 3;
}
*--out = 0;
return q;
}
사용 예:
size_t currentSize = getCurrentRSS();
size_t peakSize = getPeakRSS();
printf("Current size: %d\n", currentSize);
printf("Peak size: %d\n\n\n", peakSize);
char* szcurrentSize = (char*)malloc(100 * sizeof(char));
char* szpeakSize = (char*)malloc(100 * sizeof(char));
printf("Current size (f): %s\n", format_commas((int)currentSize, szcurrentSize));
printf("Peak size (f): %s\n", format_commas((int)currentSize, szpeakSize));
free(szcurrentSize);
free(szpeakSize);
@ 솔루션의. 단, @paxdiablo를 합니다.WCHAR
★★★★★★★★★★★★★★★★★」wsprinf
:
static WCHAR buffer[10];
static int pos = 0;
void printfcomma(const int &n) {
if (n < 0) {
wsprintf(buffer + pos, TEXT("-"));
pos = lstrlen(buffer);
printfcomma(-n);
return;
}
if (n < 1000) {
wsprintf(buffer + pos, TEXT("%d"), n);
pos = lstrlen(buffer);
return;
}
printfcomma(n / 1000);
wsprintf(buffer + pos, TEXT(",%03d"), n % 1000);
pos = lstrlen(buffer);
}
void my_sprintf(const int &n)
{
pos = 0;
printfcomma(n);
}
C++의 std:: 문자열을 최소한의 오버헤드로 반환값으로 사용하고 std 라이브러리 함수(sprintf, to_string 등)를 사용하지 않습니다.
string group_digs_c(int num)
{
const unsigned int BUF_SIZE = 128;
char buf[BUF_SIZE] = { 0 }, * pbuf = &buf[BUF_SIZE - 1];
int k = 0, neg = 0;
if (num < 0) { neg = 1; num = num * -1; };
while(num)
{
if (k > 0 && k % 3 == 0)
*pbuf-- = ',';
*pbuf-- = (num % 10) + '0';
num /= 10;
++k;
}
if (neg)
*pbuf = '-';
else
++pbuf;
int cc = buf + BUF_SIZE - pbuf;
memmove(buf, pbuf, cc);
buf[cc] = 0;
string rv = buf;
return rv;
}
휴대용 .sprintf
:
#include <stdio.h>
// assuming out points to an array of sufficient size
char *format_commas(char *out, int n, int min_digits) {
int len = sprintf(out, "%.*d", min_digits, n);
int i = (*out == '-'), j = len, k = (j - i - 1) / 3;
out[j + k] = '\0';
while (k-- > 0) {
j -= 3;
out[j + k + 3] = out[j + 2];
out[j + k + 2] = out[j + 1];
out[j + k + 1] = out[j + 0];
out[j + k + 0] = ',';
}
return out;
}
이 코드는 다른 정수 유형에 쉽게 적용할 수 있습니다.
여기에는 흥미로운 기고가 많다.일부는 모든 사건을 다루었고 일부는 다루지 않았다.테스트에 대한 기여 중 4개를 선택하고 테스트 중에 몇 가지 실패 사례를 찾은 후 자체 솔루션을 추가했습니다.
나는 정확성과 속도를 모두 테스트했다.OP는 1개의 양수에 대해서만 솔루션을 요구했지만, 가능한 모든 수를 커버하지 않는 투고를 업그레이드했습니다(따라서, 아래의 코드는 원래의 투고와 조금 다를 수 있습니다).제외된 케이스에는 0, 음수 및 최소수(INT_MIN)가 포함됩니다.
선언된 유형을 "int"에서 "long long"으로 변경했는데, 이는 보다 일반적이고 모든 int가 long long으로 승격되기 때문입니다.또한 콜 인터페이스를 표준화하여 번호뿐만 아니라 포맷된 문자열(기여 내용 등)을 포함하는 버퍼를 포함하도록 하고 버퍼에 포인터를 반환했습니다.
char* funcName(긴 긴 숫자_to_format, char* 문자열_buffer);
버퍼 파라미터를 포함하는 것은 함수를 사용하는 것보다 "더 좋은" 것으로 간주됩니다.1) 스태틱버퍼를 포함하는 것(재입력하지 않는 것)또는 2) 버퍼용 공간을 할당하는 것(발신자가 메모리를 할당 해제하는 것이 필요함)또는 3) 결과를 stdout에 직접 인쇄하는 것(출력이 GUI W를 대상으로 할 수 있으므로 일반적으로 유용하지는 않습니다.idget, file, pty, pipe 등).
원고를 참조하기 쉽도록, 원래의 투고와 같은 기능명을 사용하려고 했습니다.속도 테스트를 의미 있게 하기 위해 정확도 테스트를 통과하기 위해 기여 함수를 필요에 따라 수정했습니다.비교하기 위해 더 많은 기여 기술을 테스트하려는 경우에 대비하여 결과가 여기에 포함되어 있습니다.결과 생성에 사용되는 모든 코드와 테스트 코드를 아래에 나타냅니다.
결과는 다음과 같습니다.
Accuracy Test (test cases: LLONG_MIN, -999, -99, 0, 99, 999, LLONG_MAX):
----------------------------------------------------
print_number:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
fmtLocale:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
fmtCommas:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
format_number:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
itoa_commas:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
Speed Test: (1 million calls, values reflect average time per call)
----------------------------------------------------
print_number: 0.747 us (microsec) per call
fmtLocale: 0.222 us (microsec) per call
fmtCommas: 0.212 us (microsec) per call
format_number: 0.124 us (microsec) per call
itoa_commas: 0.085 us (microsec) per call
모든 기술은 고속(노트북에서는 1마이크로초 미만)이기 때문에 수백만 개의 숫자를 포맷할 필요가 없는 한 어떤 기술도 허용됩니다.가장 읽기 쉬운 기술을 선택하는 것이 가장 좋습니다.
코드는 다음과 같습니다.
#line 2 "comma.c"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <locale.h>
#include <limits.h>
// ----------------------------------------------------------
char* print_number( long long n, char buf[32] ) {
long long order_of_magnitude = (n == 0) ? 1
: (long long)pow( 10, ((long long)floor(log10(fabs(n))) / 3) * 3 ) ;
char *ptr = buf;
sprintf(ptr, "%d", n / order_of_magnitude ) ;
for( n %= order_of_magnitude, order_of_magnitude /= 1000;
order_of_magnitude > 0;
n %= order_of_magnitude, order_of_magnitude /= 1000 )
{
ptr += strlen(ptr);
sprintf(ptr, ",%03d", abs(n / order_of_magnitude) );
}
return buf;
}
// ----------------------------------------------------------
char* fmtLocale(long long i, char buf[32]) {
sprintf(buf, "%'lld", i); // requires setLocale in main
return buf;
}
// ----------------------------------------------------------
char* fmtCommas(long long num, char dst[32]) {
char src[27];
char *p_src = src;
char *p_dst = dst;
const char separator = ',';
int num_len, commas;
num_len = sprintf(src, "%lld", num);
if (*p_src == '-') {
*p_dst++ = *p_src++;
num_len--;
}
for (commas = 2 - num_len % 3;
*p_src;
commas = (commas + 1) % 3)
{
*p_dst++ = *p_src++;
if (commas == 1) {
*p_dst++ = separator;
}
}
*--p_dst = '\0';
return dst;
}
// ----------------------------------------------------------
char* format_number(long long n, char out[32]) {
int digit;
int out_index = 0;
long long i = (n < 0) ? -n : n;
if (i == LLONG_MIN) i = LLONG_MAX; // handle MIN, offset by 1
if (i == 0) { out[out_index++] = '0'; } // handle 0
for ( ; i != 0; i /= 10) {
digit = i % 10;
if ((out_index + 1) % 4 == 0) {
out[out_index++] = ',';
}
out[out_index++] = digit + '0';
}
if (n == LLONG_MIN) { out[0]++; } // correct for offset
if (n < 0) { out[out_index++] = '-'; }
out[out_index] = '\0';
// then you reverse the out string
for (int i=0, j = strlen(out) - 1; i<=j; ++i, --j) {
char tmp = out[i];
out[i] = out[j];
out[j] = tmp;
}
return out;
}
// ----------------------------------------------------------
char* itoa_commas(long long i, char buf[32]) {
char* p = buf + 31;
*p = '\0'; // terminate string
if (i == 0) { *(--p) = '0'; return p; } // handle 0
long long n = (i < 0) ? -i : i;
if (n == LLONG_MIN) n = LLONG_MAX; // handle MIN, offset by 1
for (int j=0; 1; ++j) {
*--p = '0' + n % 10; // insert digit
if ((n /= 10) <= 0) break;
if (j % 3 == 2) *--p = ','; // insert a comma
}
if (i == LLONG_MIN) { p[24]++; } // correct for offset
if (i < 0) { *--p = '-'; }
return p;
}
// ----------------------------------------------------------
// Test Accuracy
// ----------------------------------------------------------
void test_accuracy(char* name, char* (*func)(long long n, char* buf)) {
char sbuf[32]; // string buffer
long long nbuf[] = { LLONG_MIN, -999, -99, 0, 99, 999, LLONG_MAX };
printf("%s:\n", name);
printf(" %s", func(nbuf[0], sbuf));
for (int i=1; i < sizeof(nbuf) / sizeof(long long int); ++i) {
printf(", %s", func(nbuf[i], sbuf));
}
printf("\n");
}
// ----------------------------------------------------------
// Test Speed
// ----------------------------------------------------------
void test_speed(char* name, char* (*func)(long long n, char* buf)) {
int cycleCount = 1000000;
//int cycleCount = 1;
clock_t start;
double elapsed;
char sbuf[32]; // string buffer
start = clock();
for (int i=0; i < cycleCount; ++i) {
char* s = func(LLONG_MAX, sbuf);
}
elapsed = (double)(clock() - start) / (CLOCKS_PER_SEC / 1000000.0);
printf("%14s: %7.3f us (microsec) per call\n", name, elapsed / cycleCount);
}
// ----------------------------------------------------------
int main(int argc, char* argv[]){
setlocale(LC_ALL, "");
printf("\nAccuracy Test: (LLONG_MIN, -999, 0, 99, LLONG_MAX)\n");
printf("----------------------------------------------------\n");
test_accuracy("print_number", print_number);
test_accuracy("fmtLocale", fmtLocale);
test_accuracy("fmtCommas", fmtCommas);
test_accuracy("format_number", format_number);
test_accuracy("itoa_commas", itoa_commas);
printf("\nSpeed Test: 1 million calls\n\n");
printf("----------------------------------------------------\n");
test_speed("print_number", print_number);
test_speed("fmtLocale", fmtLocale);
test_speed("fmtCommas", fmtCommas);
test_speed("format_number", format_number);
test_speed("itoa_commas", itoa_commas);
return 0;
}
void printfcomma ( long long unsigned int n)
{
char nstring[100];
int m;
int ptr;
int i,j;
sprintf(nstring,"%llu",n);
m=strlen(nstring);
ptr=m%3;
if (ptr)
{ for (i=0;i<ptr;i++) // print first digits before comma
printf("%c", nstring[i]);
printf(",");
}
j=0;
for (i=ptr;i<m;i++) // print the rest inserting commas
{
printf("%c",nstring[i]);
j++;
if (j%3==0)
if(i<(m-1)) printf(",");
}
}
// separate thousands
int digit;
int idx = 0;
static char buffer[32];
char* p = &buffer[32];
*--p = '\0';
for (int i = fCounter; i != 0; i /= 10)
{
digit = i % 10;
if ((p - buffer) % 4 == 0)
*--p = ' ';
*--p = digit + '0';
}
언급URL : https://stackoverflow.com/questions/1449805/how-to-format-a-number-from-1123456789-to-1-123-456-789-in-c
'source' 카테고리의 다른 글
Java 멀티스레딩에서 Count Down Latch는 어떻게 사용됩니까? (0) | 2022.07.17 |
---|---|
ld.exe: 출력 파일을 열 수 없습니다...: 권한이 거부되었습니다. (0) | 2022.07.17 |
nuxt.js Vuex Vuejs 정의되지 않은 속성 'getters'를 읽을 수 없습니다. (0) | 2022.07.17 |
오류: 유감스럽게도 비 Gradle Java 모듈과 > Android-Gradle 모듈을 하나의 프로젝트에 포함할 수 없습니다. (0) | 2022.07.17 |
pthread_cond_wait 대 세마포 (0) | 2022.07.17 |