gcc를 사용하여 __uint128_t 번호를 인쇄하는 방법
그곳 있습니까 거기에.PRIu128
는행동을 같은과 비슷한 행동 하는PRIu64
부터에서<inttypes.h>
:
printf("%" PRIu64 "\n", some_uint64_value);
또는 수동으로 숫자로 변환:
int print_uint128(uint128_t n) {
if (n == 0) return printf("0\n");
char str[40] = {0}; // log10(1 << 128) + '\0'
char *s = str + sizeof(str) - 1; // start at the end
while (n != 0) {
if (s == str) return -1; // never happens
*--s = "0123456789"[n % 10]; // save last digit
n /= 10; // drop it
}
return printf("%s\n", s);
}
유일한 선택지인가?
참고 주의:uint128_t
에대한 저만의 형식입니다를 위해 혼자서 typedef 있다.__uint128_t
.
아니요, 라이브러리에서 이러한 유형의 인쇄를 지원하지 않습니다.C 표준에서는 확장 정수형도 아닙니다.
뒷면부터 인쇄를 시작하는 것은 좋지만, 더 큰 덩어리가 필요할 수도 있습니다.P99의 일부 테스트에서는 다음과 같은 기능을 사용합니다.
uint64_t const d19 = UINT64_C(10000000000000000000);
10에10의 최대제곱으로서에 맞는 가장 큰 강대국으로서.uint64_t
.
소수점 이하에서는, 이러한 큰 숫자는 곧바로 판독할 수 없게 되기 때문에, 보다 간단하게 16 진수로 인쇄하는 방법도 있습니다.그러면 이렇게 하면 돼요.
uint64_t low = (uint64_t)x;
// This is UINT64_MAX, the largest number in 64 bit
// so the longest string that the lower half can occupy
char buf[] = { "18446744073709551615" };
sprintf(buf, "%" PRIX64, low);
아랫부분을 얻어서 기본적으로 같은 것을 얻습니다.
uint64_t high = (x >> 64);
윗부분을 위해서.
GCC 4.7.1 매뉴얼에는 다음과 같이 기재되어 있습니다.
6.8 128비트 정수
연장선상으로 정수 스칼라 타입 확장으로서정수 스칼라 타입.
__int128
목표 정수 모드 충분히 128비트를 개최할 넓이가에 지원된다.는 128비트를 유지할 수 있는 충분한 폭의 정수 모드를 가진 타깃으로 지원됩니다.단순히 간단하게 쓰기 쓰__int128
들어 서명된 128비트 정수, 또는 정수의경우 또는 있는 128비트 부호.unsigned __int128
부호 없는 128비트 정수.부호 없는 128비트정수의 경우.에는 GCC에 지원 GCC에서는 유형의 정수 정수를 나타내는 것을 지원하지 않습니다 형식의 정수 상수를 표현하는 것이다.__int128
우리가 목표 를 가진 타겟에 대해서long long
128비트보다 작은 정수입니다.
흥미롭게도, 비록 그것이 다음 사항을 언급하지는 않지만__uint128_t
엄격한 경고가 설정된 경우에도 이 유형은 허용됩니다.
#include <stdio.h>
int main(void)
{
__uint128_t u128 = 12345678900987654321;
printf("%llx\n", (unsigned long long)(u128 & 0xFFFFFFFFFFFFFFFF));
return(0);
}
컴파일:
$ gcc -O3 -g -std=c99 -Wall -Wextra -pedantic xxx.c -o xxx
xxx.c: In function ‘main’:
xxx.c:6:24: warning: integer constant is so large that it is unsigned [enabled by default]
$
(이것은 Mac OS X 10.7.4의 홈 컴파일 GCC 4.7.1을 사용한 것입니다).
를 상수로 0x12345678900987654321
컴파일러는 다음과 같이 말합니다.
xxx.c: In function ‘main’:
xxx.c:6:24: warning: integer constant is too large for its type [enabled by default]
그래서, 이 생물들을 조종하는 것은 쉽지 않습니다.10진수 상수와 16진수 상수의 출력은 다음과 같습니다.
ab54a98cdc6770b1
5678900987654321
10진수 인쇄의 경우 값이 UINT64_MAX보다 큰지 여부를 확인하는 것이 가장 좋습니다.그렇다면 UINT64_MAX보다 작은 10의 최대제곱으로 나누어 그 숫자를 인쇄합니다(이 과정을 두 번 반복해야 할 수도 있습니다).그리고 UINT64_MAX보다 작은 10의 최대제곱을 인쇄합니다.선두에 0을 붙입니다.
그 결과 다음과 같은 결과가 초래됩니다.
#include <stdio.h>
#include <inttypes.h>
/*
** Using documented GCC type unsigned __int128 instead of undocumented
** obsolescent typedef name __uint128_t. Works with GCC 4.7.1 but not
** GCC 4.1.2 (but __uint128_t works with GCC 4.1.2) on Mac OS X 10.7.4.
*/
typedef unsigned __int128 uint128_t;
/* UINT64_MAX 18446744073709551615ULL */
#define P10_UINT64 10000000000000000000ULL /* 19 zeroes */
#define E10_UINT64 19
#define STRINGIZER(x) # x
#define TO_STRING(x) STRINGIZER(x)
static int print_u128_u(uint128_t u128)
{
int rc;
if (u128 > UINT64_MAX)
{
uint128_t leading = u128 / P10_UINT64;
uint64_t trailing = u128 % P10_UINT64;
rc = print_u128_u(leading);
rc += printf("%." TO_STRING(E10_UINT64) PRIu64, trailing);
}
else
{
uint64_t u64 = u128;
rc = printf("%" PRIu64, u64);
}
return rc;
}
int main(void)
{
uint128_t u128a = ((uint128_t)UINT64_MAX + 1) * 0x1234567890ABCDEFULL +
0xFEDCBA9876543210ULL;
uint128_t u128b = ((uint128_t)UINT64_MAX + 1) * 0xF234567890ABCDEFULL +
0x1EDCBA987654320FULL;
int ndigits = print_u128_u(u128a);
printf("\n%d digits\n", ndigits);
ndigits = print_u128_u(u128b);
printf("\n%d digits\n", ndigits);
return(0);
}
그 출력은 다음과 같습니다.
24197857200151252746022455506638221840
38 digits
321944928255972408260334335944939549199
39 digits
하다를 사용해서 할수 있어요.bc
:
$ bc
bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
ibase = 16
1234567890ABCDEFFEDCBA9876543210
24197857200151252746022455506638221840
F234567890ABCDEF1EDCBA987654320F
321944928255972408260334335944939549199
quit
$
분명히 16진수에서는 프로세스가 더 단순합니다. 단 두 번의 작업으로 이동 및 마스크 및 인쇄가 가능합니다.8진수에서는 64는 3의 배수가 아니기 때문에 10진수 연산과 유사한 단계를 거쳐야 합니다.
print_u128_u()
인쇄된 문자 됩니다.printf()
결과를 문자열 버퍼로 포맷하기 위해 코드를 조정하는 것은 프로그래밍에서 완전히 단순한 연습은 아니지만 매우 어려운 것은 아닙니다.
내장된 솔루션은 없지만 분할/계수는 비쌉니다.이동만으로 이진수를 10진수로 변환할 수 있습니다.
static char *qtoa(uint128_t n) {
static char buf[40];
unsigned int i, j, m = 39;
memset(buf, 0, 40);
for (i = 128; i-- > 0;) {
int carry = !!(n & ((uint128_t)1 << i));
for (j = 39; j-- > m + 1 || carry;) {
int d = 2 * buf[j] + carry;
carry = d > 9;
buf[j] = carry ? d - 10 : d;
}
m = j;
}
for (i = 0; i < 38; i++) {
if (buf[i]) {
break;
}
}
for (j = i; j < 39; j++) {
buf[j] += '0';
}
return buf + i;
}
(하지만 128비트 나눗셈/모듈러스는 생각보다 비싸지 않은 것 같습니다. 4 및 GCC 4.7의 3. "Clang 3.1" "Phenom 9600"-O2
OP 2-3번입니다.)
gcc를 사용하여 하는 방법_uint128_t 입니다.
PRIu64 의와하는 PRIu128 이 ?
아니요. 대신 10진수로 인쇄하려면 문자열로 인쇄하십시오.
는 이 합니다.x
typedef signed __int128 int128_t;
typedef unsigned __int128 uint128_t;
// Return pointer to the end
static char *uint128toa_helper(char *dest, uint128_t x) {
if (x >= 10) {
dest = uint128toa_helper(dest, x / 10);
}
*dest = (char) (x % 10 + '0');
return ++dest;
}
char *int128toa(char *dest, int128_t x) {
if (x < 0) {
*dest = '-';
*uint128toa_helper(dest + 1, (uint128_t) (-1 - x) + 1) = '\0';
} else {
*uint128toa_helper(dest, (uint128_t) x) = '\0';
}
return dest;
}
char *uint128toa(char *dest, uint128_t x) {
*uint128toa_helper(dest, x) = '\0';
return dest;
}
테스트 최악의 경우 버퍼 크기: 41
int main(void) {
char buf[41];
puts("1234567890123456789012345678901234567890");
puts(uint128toa(buf, 0));
puts(uint128toa(buf, 1));
puts(uint128toa(buf, (uint128_t) -1));
int128_t mx = ((uint128_t) -1) / 2;
puts(int128toa(buf, -mx - 1));
puts(int128toa(buf, -mx));
puts(int128toa(buf, -1));
puts(int128toa(buf, 0));
puts(int128toa(buf, 1));
puts(int128toa(buf, mx));
return 0;
}
산출량
1234567890123456789012345678901234567890
0
1
340282366920938463463374607431768211455
-170141183460469231731687303715884105728
-170141183460469231731687303715884105727
-1
0
1
170141183460469231731687303715884105727
부호 없는 64/128비트 숫자를 십진법으로 인쇄하고 싶었고 바퀴를 다시 만들고 싶지 않았습니다.따라서 "pu128()"에는 <10^19, <10^38, 그 이외의 경우)의 3가지 케이스가 있습니다.아마 가장 빠르지는 않겠지만, 휴대할 수 있어야 합니다.UINT128_MAX 매크로와 UINT128_C 매크로를 정의합니다.
$ gcc -Wall -Wextra -pedantic lu.c
$ ./a.out
0
10000000000000000000
18446744073709551615
0
10000000000000000000
18446744073709551615
100000000000000000000000000000000000000
340282366920938463463374607431768211455
$
$ cat lu.c
#include <stdio.h>
#include <inttypes.h>
#define UINT128_C(u) ((__uint128_t)u)
void pu64(__uint64_t u) { printf("%" PRIu64, u); }
void pu640(__uint64_t u) { printf("%019" PRIu64, u); }
#define D19_ UINT64_C(10000000000000000000)
const __uint128_t d19_ = D19_;
const __uint128_t d38_ = UINT128_C(D19_)*D19_;
const __uint128_t UINT128_MAX = UINT128_C(UINT64_MAX)<<64 | UINT64_MAX;
void pu128(__uint128_t u)
{
if (u < d19_) pu64(u);
else if (u < d38_) { pu64(u/d19_); pu640(u%d19_); }
else { pu64(u/d38_); u%=d38_; pu640(u/d19_); pu640(u%d19_); }
}
int main()
{
pu64(0); puts("");
pu64(d19_); puts("");
pu64(UINT64_MAX); puts("");
pu128(0); puts("");
pu128(d19_); puts("");
pu128(UINT64_MAX); puts("");
pu128(d38_); puts("");
pu128(UINT128_MAX); puts("");
}
$
위의 아벨렌키의 대답에 따라, 나는 이것을 생각해냈다.
void uint128_to_str_iter(uint128_t n, char *out,int firstiter){
static int offset=0;
if (firstiter){
offset=0;
}
if (n == 0) {
return;
}
uint128_to_str_iter(n/10,out,0);
out[offset++]=n%10+0x30;
}
char* uint128_to_str(uint128_t n){
char *out=calloc(sizeof(char),40);
uint128_to_str_iter(n, out, 1);
return out;
}
의도한 대로 작동하는 것 같습니다.
Sebastian의 답변에 따르면, 이것은 스레드 세이프가 아닌 g++로 서명된 int128에 대한 것입니다.
// g++ -Wall fact128.c && a.exe
// 35! overflows 128bits
#include <stdio.h>
char * sprintf_int128( __int128_t n ) {
static char str[41] = { 0 }; // sign + log10(2**128) + '\0'
char *s = str + sizeof( str ) - 1; // start at the end
bool neg = n < 0;
if( neg )
n = -n;
do {
*--s = "0123456789"[n % 10]; // save last digit
n /= 10; // drop it
} while ( n );
if( neg )
*--s = '-';
return s;
}
__int128_t factorial( __int128_t i ) {
return i < 2 ? i : i * factorial( i - 1 );
}
int main( ) {
for( int i = 0; i < 35; i++ )
printf( "fact(%d)=%s\n", i, sprintf_int128( factorial( i ) ) );
return 0;
}
__int128_t를 사용하는 경우 연산자 cin과 cout을 재정의할 수 있습니다.__int128_t는 문자열 및 cin/cout 문자열로만 변환해야 합니다.
typedef __int128_t lint;
istream& operator >> (istream &in, lint &x) {
string s;
in >> s;
for (lint i = s.size() - 1, p = 1; i >= 0; i--, p *= 10) x += p * (s[i] - '0');
return in;
}
ostream& operator << (ostream &out, lint x) {
string s;
while (x > 0) {
s.push_back(x % 10 + '0');
x /= 10;
}
reverse(s.begin(), s.end());
out << s;
return out;
}
3번과 거의 같다
unsigned __int128 g = ...........;
printf ("g = 0x%lx%lx\r\n", (uint64_t) (g >> 64), (uint64_t) g);
이것은 C++용이지만, 부호 없는 128비트 ints에 대한 이 질문의 C++ 버전을 찾지 못했기 때문에 여기에 남겨두겠습니다.
다음은 uint128을 Base-10 문자열로 변환하는 간단하고 읽기 쉬운 방법입니다(이 문자열은 인쇄 또는 원하는 작업을 수행할 수 있습니다).
std::string toString(__uint128_t num) {
std::string str;
do {
int digit = num % 10;
str = std::to_string(digit) + str;
num = (num - digit) / 10;
} while (num != 0);
return str;
}
필요한 경우 한 번에 하나씩이 아닌 더 큰 청크로 숫자를 가져오면 몇 배 더 빠르게 만들 수 있습니다.단, 각 청크에서 선두 0이 손실되지 않았는지 확인하고 다시 추가해야 합니다.
std::string toString(__uint128_t num) {
auto tenPow19 = 10000000000000000000;
std::string str;
do {
uint64_t digits = num % tenPow19;
auto digitsStr = std::to_string(digits);
auto leading0s = (digits != num) ? std::string(19 - digitsStr.length(), '0') : "";
str = leading0s + digitsStr + str;
num = (num - digits) / tenPow19;
} while (num != 0);
return str;
}
다음의 간단한 매크로를 사용할 수 있습니다.
typedef __int128_t int128 ;
typedef __uint128_t uint128 ;
uint128 x = (uint128) 123;
printf("__int128 max %016"PRIx64"%016"PRIx64"\n",(uint64)(x>>64),(uint64)x);
이것은 0 ~ UINT128_을 지원하는 Leffler의 답변 수정 버전입니다.맥스.
/* UINT64_MAX 18446744073709551615ULL */
#define P10_UINT64 10000000000000000000ULL /* 19 zeroes */
#define E10_UINT64 19
#define STRINGIZER(x) # x
#define TO_STRING(x) STRINGIZER(x)
int print_uint128_decimal(__uint128_t big) {
size_t rc = 0;
size_t i = 0;
if (big >> 64) {
char buf[40];
while (big / P10_UINT64) {
rc += sprintf(buf + E10_UINT64 * i, "%." TO_STRING(E10_UINT64) PRIu64, (uint64_t)(big % P10_UINT64));
++i;
big /= P10_UINT64;
}
rc += printf("%" PRIu64, (uint64_t)big);
while (i--) {
fwrite(buf + E10_UINT64 * i, sizeof(char), E10_UINT64, stdout);
}
} else {
rc += printf("%" PRIu64, (uint64_t)big);
}
return rc;
}
그리고 이것을 시도해 보세요.
print_uint128_decimal(-1); // Assuming -1's complement being 0xFFFFF...
C++ 배리언트이 기능을 템플릿으로 사용하여 특정 C 버전을 생성할 수 있습니다.
template< typename I >
void print_uint(I value)
{
static_assert(std::is_unsigned< I >::value, "!");
if (value == 0) {
putchar_unlocked('0');
return;
}
I rev = value;
I count = 0;
while ((rev % 10) == 0) {
++count;
rev /= 10;
}
rev = 0;
while (value != 0) {
rev = (rev * 10) + (value % 10);
value /= 10;
}
while (rev != 0) {
putchar_unlocked('0' + (rev % 10));
rev /= 10;
}
while (0 != count) {
--count;
putchar_unlocked('0');
}
}
이전 답변에서는 "printf()"를 기반으로 128비트 숫자를 인쇄하는 방법을 보여드렸습니다.
256비트 부호 없는 정수형 uint256_t를 다음과 같이 구현했습니다.
typedef __uint128_t uint256_t[2];
필요한 조작을 실장했습니다.예를 들어 __uint128_t를 인수로 하고 그 결과 uint256_t를 계산합니다.
uint256_t에 대해 16진 인쇄를 했는데, 10진 인쇄를 원하게 되었습니다.그러나 현재 uint256_t에는 "mod_256()"만 있고 "div()"는 없기 때문에 많은 답변에서 볼 수 있는 "n/=10"은 옵션이 아닙니다.동작하는 (느린) 솔루션을 찾았습니다.또, 인쇄는 시간 외에만 사용하고 있기 때문에, 이것은 허용됩니다.코드는 다음 GIST에서 찾을 수 있습니다(컴파일 명령 세부 정보 포함).
https://gist.github.com/Hermann-SW/83c8ab9e10a0bb64d770af543ed08445
arg를 사용하여 sqr.cpp를 실행하면 UINT256_MAX만 출력되고 종료됩니다.
if (argc>1) { pu256(UINT256_MAX); puts(""); return 0; }
$ ./sqr 1
115792089237316195423570985008687907853269984665640564039457584007913129639935
$
가장 까다로운 부분은 사용된 최대 자리까지 올라가 첫 번째 자리를 빼고 출력하기 위한 재귀 호출이었습니다.재귀가 나머지를 처리한다."pu256()" 함수는 10 "mul10()"에 의한 고속 곱셈을 사용했습니다.
...
void mul10(uint256_t d, uint256_t x)
{
uint256_t t = { x[0], x[1] };
shl_256(t, 2);
add_256(d, x, t);
shl_256(d, 1);
}
const uint256_t UINT256_MAX_10th = UINT256( UINT128(0x1999999999999999, 0x9999999999999999), UINT128(0x9999999999999999, 0x999999999999999A) );
void pu256_(uint256_t v, uint256_t t, const uint256_t o)
{
if (!lt_256(v, t) && le_256(o, UINT256_MAX_10th))
{
uint256_t nt, no = { t[0], t[1] };
mul10(nt, t);
pu256_(v, nt, no);
}
char d = '0';
while (le_256(o, v))
{
sub_256(v, v, o);
++d;
}
putchar(d);
}
void pu256(const uint256_t u)
{
if ((u[1]==0) && (u[0]==0)) putchar('0');
else
{
uint256_t v = { u[0], u[1] }, t = UINT256( 0, 10 ), o = UINT256( 0, 1 );
pu256_(v, t, o);
}
}
...
전술한 바와 같이 이 접근방식은 정수형 결측 나눗셈 연산에 대해서만 의미가 있습니다.
언급URL : https://stackoverflow.com/questions/11656241/how-to-print-uint128-t-number-using-gcc
'programing' 카테고리의 다른 글
vue.dister Web 컴포넌트 등록 (0) | 2022.08.17 |
---|---|
Java 보안:잘못된 키 크기 또는 기본 매개 변수입니까? (0) | 2022.08.17 |
오류: 함수가 로컬 변수의 주소를 반환합니다. (0) | 2022.08.17 |
어레이를 컨트롤러에서 vue.js v-for로 전달하는 방법 (0) | 2022.08.10 |
"continue" 키워드는 무엇이며 Java에서는 어떻게 동작합니까? (0) | 2022.08.10 |