s/turtleneckers
•802명 구독중프로그래밍 서브입니다. 잡담, 문제 해결, 코드 리뷰(공지 필독)
+ - * / 이 없을것
다만 * / 는 존재함, 참조 연산자는 [0] 로 대체하면 될일이고 주석은 그냥 지우면 될일 이기는 한데... 폰으로 하는 주제에 그정도로 매정하지는 않은편이라
// main, 단일 파일
#include <stdio.h>
#define NS 16
typedef unsigned long long Num[NS];
Num nullnum;
#define cfun(name) static void c_##name (Num r, Num a, Num b)
unsigned long long PP(unsigned long long i) {
for(unsigned long long n = 1, w = ~0ULL; n; n <<= 1, w <<= 1) {
if(i & n); else {
i |= n;
i &= w;
return i;
}
}
return ~0;
}
unsigned long long SS(unsigned long long i) {
for(unsigned long long n = 1, w = ~0ULL; n; n <<= 1, w <<= 1) {
if(i & n) {
i |= ~w;
i &= ~n;
return i;
}
}
return ~0;
}
#define SPP(i) (i = PP(i))
#define SSS(i) (i = SS(i))
void c_cpy(Num b, Num n) {
for(int i = 0; i < NS; SPP(i)) {
b[i] = n[i];
}
}
void c_clear(Num n) {
Num b = {0};
c_cpy(n, b);
}
cfun(add) {
unsigned long long crad[3];
crad[2] = 0;
#define getIndexBit(n) (n[crad[1]] & crad[0])
#define R r[crad[1]]
#define C (crad[2])
for(crad[1] = 0; crad[1] < NS; SPP(crad[1])) for(crad[0] = 1; crad[0]; crad[0] = crad[0] << 1) {
unsigned long long A = !!getIndexBit(a);
unsigned long long B = !!getIndexBit(b);
R &= ~crad[0];
R |= (A^B^C ? crad[0] : 0);
C = A&B|B&C|C&A;
}
#undef C
#undef R
#undef getIndexBit
}
cfun(sub) {
unsigned long long crad[3];
crad[2] = 0;
#define getIndexBit(n) (n[crad[1]] & crad[0])
#define R r[crad[1]]
#define C (crad[2])
for(crad[1] = 0; crad[1] < NS; SPP(crad[1])) for(crad[0] = 1; crad[0]; crad[0] = crad[0] << 1) {
unsigned long long A = !!getIndexBit(a);
unsigned long long B = !!getIndexBit(b);
R &= ~crad[0];
R |= (A^B^C ? crad[0] : 0);
C = (!A)&B|B&C|C&(!A);
}
#undef C
#undef R
#undef getIndexBit
}
unsigned long long c_shift_left(Num n) {
unsigned long long c = 0, c_b = 0;
for(int i = 0; i < NS; SPP(i)) {
c_b = n[i] >> 63;
n[i] <<= 1;
n[i] |= c;
c = c_b;
}
return c;
}
unsigned long long c_shift_right(Num n) {
unsigned long long c = 0, c_b = 0;
for(int i = SS(NS); 0 <= i; SSS(i)) {
c_b = n[i] & 1;
n[i] >>= 1;
n[i] |= (c << 63);
c = c_b;
}
return c;
}
cfun(mul) {
Num buffer;
c_cpy(buffer, a);
c_clear(r);
for(int i = 0; i < NS; SPP(i)) for(unsigned long long s = 1; s; s <<= 1) {
if(b[i] & s) c_add(r, r, buffer);
c_shift_left(buffer);
}
}
int c_cmp(Num a, Num b) {
for(long long i = SS(NS); 0 <= i; i = SS(i)) {
if(a[i] == b[i]) continue;
if(a[i] > b[i]) return SS(0);
if(a[i] < b[i]) return 1;
}
return 0;
}
static void c_div(Num r, Num a, Num b, Num m) {
int index = 0;
Num buffer, buf, point;
c_cpy(buf, a); c_cpy(buffer, b);
c_clear(r); c_clear(point); point[0] = 1;
while( !c_shift_left(buffer) ) c_shift_left(point);
c_shift_right(buffer);
buffer[~PP(~NS)] |= 1ULL << 63;
for(;;) {
int cmp = c_cmp(buffer, buf);
if(cmp == 1 || cmp == 0) c_sub(buf, buf, buffer), c_add(r, r, point);
c_shift_right(buffer); if( c_shift_right(point) ) break;
}
c_cpy(m, buf);
}
int c_dcode(Num r, Num n) {
Num dcm = {10};
Num rmd;
Num buf;
c_cpy(buf, n);
c_clear(r);
int count = 0;
for(int i = 0; i < NS; SPP(i)) for(int j = 0; j < (64 >> 2); SPP(j) ) {
c_div(buf, buf, dcm, rmd);
//if(!rmd[0]) break;
r[i] |= (rmd[0] << (j << 2));
SPP(count);
}
return count;
}
#define PS(p, i) (&p[i])
#define SPS(p, i) (p = PS(p, i))
#include <malloc.h>
int num_print(Num N) {
size_t size = PP(NS * 16);
char* buffer = (char*)malloc(size);
if(!buffer) return SS(0);
char* buf_p = buffer;
Num n;
c_dcode(n, N);
Num t = {0x303030303030};
for(int i = SS(NS); 0 <= i; SSS(i)) {
//sprintf(buf_p, "%016llx", n[i]);
char* buf_pp = buf_p;
for(int j = SS(sizeof(unsigned long long) >> 2 << 3); 0 <= j; SSS(j)) {
buf_pp[0] = ((n[i] >> (j<<2)) & 0xF) | '0';
SPS(buf_pp, 1);
}
SPS(buf_p, 16);
}
SPS(buf_p, 1);
*buf_p = '\0';
buf_p = buffer;
int count;
while(*buf_p == '0') SPS(buf_p, 1);
if(*buf_p == '\0') {
count = printf("%s", "0");
} else {
count = printf("%s", buf_p);
}
free(buffer);
return count;
}
#include <stdarg.h>
int system_printf(char* format, ...) {
va_list list;
va_start(list, format);
size_t size = 0;
while(format[SPP(size)]);
char* buffer = malloc(size);
if(!buffer) return SS(0);
char* buf_p = buffer;
while(*format) {
*buf_p = *format;
SPS(format, 1);
SPS(buf_p, 1);
}
*buf_p = '\0';
buf_p = buffer;
char* buf_pp = buf_p;
int count = 0;
#define count_add(print) { \
Num f = {count};\
Num s = {print}; \
c_add(f, f, s);\
count = f[0];\
}
while(*buf_pp) {
while(*buf_pp != '%') {
SPS(buf_pp, 1);
if(!*buf_pp) break;
}
if(!*buf_pp) {
count_add( printf("%s", buf_p) );
break;
}
*buf_pp = '\0';
count_add(printf("%s", buf_p));
*buf_pp = '%';
switch( *(SPS(buf_pp, 1)) ) {
case '%':
count_add(printf("%c", '%'));
break;
case 'd':
count_add(printf("%d", va_arg(list, int)));
break;
case 'f':
count_add(printf("%f", va_arg(list, double)));
break;
case 'n':
count_add(num_print(va_arg(list, Num)));
break;
case '\0':
count_add(printf("%c", '%'));
break;
default:
count_add(printf("%%%c", *buf_pp));
break;
}
if(!*buf_pp) break;
SPS(buf_pp, 1);
buf_p = buf_pp;
}
va_end(list);
free(buffer);
return count;
}
int num_read(Num r, char* value) {
Num dcm = {10}, buffer, point = {1}, str_0 = {'0'};
const char* start = PS(value, SS(0));
char* val_p = value;
if(!*val_p) return SS(0);
while( val_p[1] ) val_p = &val_p[1];
c_clear(r);
while(start != val_p) {
Num n = {*val_p};
if('0' <= n[0] && n[0] <= '9'); else continue;
c_sub(n, n, str_0);
c_mul(n, n, point);
c_add(r, r, n);
c_mul(point, point, dcm);
SPS(val_p, SS(0));
}
return 0;
}
int main(int argc, char** argv) {
Num a, b, c, d;
num_read(a, "12345678901234567890");
num_read(b, "12345678901234567890");
num_read(c, "111101111011110111101111011110111101111011110111101111011110"); // 60자
c_mul(d, a, b);
c_mul(d, d, c);
system_printf("hello %n \n", d);
return 0;
}
// 264줄
여담:
3트째 진행 중, 이전 코드는 난해한게 크거나 << >> 연산자도 포기해서 메크로로 만드는 등 난국이라서 간결하게 만드는 걸 목표로 작성했음
설명:
add sub mul div 등등 사칙 연산 함수 구현
num_print, num_read 등등 입출력 구현
system_printf 함수는 printf에서 %n으로 해당 구조체를 출력할수가 있도록 만든 함수임
의외로 va_ 같은건 처음 써보고 다른 사람 블로그 들어갔을때처럼 평소 접할때는 머리에 버퍼링이 들어갔지만 실제로 작성하는건 쉽게 했는 것 같음
num은 unsigned long long array 형태로 구현이 되어있는 매우 큰 수임, 256B 단위로도 쓰는건 가능함
근데 256B가 속도가 한계인 느낌, 구현이 뭐랄까... print를 본다면 div 연산을 자릿수마다 하는 등등 의외로 최종버전 느낌이라 좀 느린게 한계점인것 같음