Browse Source

Added infinite integers and required operations.

long_to_char
Cameron Weinfurt 3 years ago
parent
commit
83a68932ce
  1. 15
      Makefile
  2. 231
      infint.c
  3. 32
      infint.h
  4. 32
      main.c

15
Makefile

@ -1,19 +1,22 @@
objs = main.o token.o expr.o parse.o
objs = main.o token.o expr.o parse.o infint.o
build: $(objs)
gcc -o infcalc $(objs) -g
clang -o infcalc $(objs) -g -O2
clean:
rm *.o infcalc
main.o: main.c expr.h
gcc -c main.c -o main.o -g
clang -c main.c -o main.o -g -O2
token.o: token.c token.h
gcc -c token.c -o token.o -g
clang -c token.c -o token.o -g -O2
expr.o: expr.c expr.h
gcc -c expr.c -o expr.o -g
clang -c expr.c -o expr.o -g -O2
parse.o: parse.c parse.h token.h expr.h
gcc -c parse.c -o parse.o -g
clang -c parse.c -o parse.o -g -O2
infint.o: infint.c infint.h
clang -c infint.c -o infint.o -g -O2

231
infint.c

@ -0,0 +1,231 @@
#include "infint.h"
infint_t *infint_from_uint64(uint64_t n) {
infint_t *ii = malloc(sizeof(infint_t));
ii->next = ii->prev = NULL;
ii->data = n;
return ii;
}
void infint_push(infint_t *ii, uint64_t n) {
if (ii->next == NULL) {
ii->next = malloc(sizeof(infint_t));
ii->next->data = n;
ii->next->next = NULL;
ii->next->prev = ii;
}
}
void infint_print(infint_t *ii) {
while (ii->next != NULL) ii = ii->next;
printf("0x%lX", ii->data);
while (ii->prev != NULL) {
ii = ii->prev;
printf("%016lX", ii->data);
}
}
void infint_destroy(infint_t *ii) {
while (ii) {
infint_t *ii_next = ii->next;
free(ii);
ii = ii_next;
}
}
void infint_pad(infint_t *ii1, infint_t *ii2) {
while (ii1->next && ii2->next) {
ii1 = ii1->next;
ii2 = ii2->next;
}
while (ii1->next) {
infint_push(ii2, 0);
ii1 = ii1->next;
ii2 = ii2->next;
}
while (ii2->next) {
infint_push(ii1, 0);
ii1 = ii1->next;
ii2 = ii2->next;
}
}
infint_t *infint_clone(infint_t *src) {
infint_t *dest, *dest_ptr;
dest_ptr = dest = infint_from_uint64(src->data);
while (src->next) {
src = src->next;
infint_push(dest_ptr, src->data);
dest_ptr = dest_ptr->next;
}
return dest;
}
void infint_invert(infint_t *ii) {
ii->data ^= -1;
while (ii->next) {
ii = ii->next;
ii->data ^= -1;
}
}
void infint_add(infint_t *ii, uint64_t n) {
ii->data += n;
// Modern compilers optimize this conditional to checking the carry flag.
if (ii->data < n) {
do {
if (ii->next) {
ii = ii->next;
ii->data += 1;
}
else
{
infint_push(ii, 1);
return;
}
} while (ii->data < 1);
}
}
void infint_add2(infint_t *ii1, infint_t *ii2) {
infint_add(ii1, ii2->data);
while(ii1->next && ii2->next) {
ii1 = ii1->next;
ii2 = ii2->next;
infint_add(ii1, ii2->data);
}
while(ii2->next) {
ii2 = ii2->next;
infint_push(ii1, ii2->data);
ii1 = ii1->next;
}
}
char infint_sub(infint_t *ii, uint64_t n) {
// These operations preserve the fact that ii holds an unsigned integer.
// Any borrow generated is returned so that it can be handled seperately.
if (infint_lt(ii, n)) {
// n being greater than ii implies ii only has one node.
n ^= -1;
ii->data ^= -1;
ii->data -= n;
return 1;
}
else {
ii->data ^= -1;
ii->data += n;
if (ii->next) {
do {
ii = ii->next;
ii->data ^= -1;
ii->data += 1;
} while (ii->data < 1);
}
while(ii->next != NULL) {
ii = ii->next;
ii->data ^= -1;
}
while (ii->data == 0) {
ii = ii->prev;
free(ii->next);
ii->next = NULL;
}
return 0;
}
}
char infint_sub2(infint_t *ii1, infint_t *ii2) {
if (infint_lt2(ii1, ii2)) {
infint_pad(ii1, ii2);
infint_invert(ii1);
infint_invert(ii2);
infint_sub(ii1, ii2->data);
while(ii1->next) {
ii1 = ii1->next;
ii2 = ii2->next;
infint_sub(ii1, ii2->data);
}
return 1;
}
else {
infint_invert(ii1);
infint_add2(ii1, ii2);
infint_invert(ii1);
while (ii1->next) ii1 = ii1->next;
while (ii1->data == 0) {
ii1 = ii1->prev;
free(ii1->next);
ii1->next = NULL;
}
return 0;
}
}
// Optimizers seem to struggle with the fact that imulq places the result in
// registers: rax for the lower bytes and rdx for the upper bytes on x86. A
// small amount of inline assembly was used to enforce this feature with the
// cost of this program now only working on 64bit x86 machines.
void infint_mult(infint_t *ii, uint64_t n) {
uint64_t carry = 0;
do {
asm (
"movq (%1), %%rax\n"
"imulq %2\n"
"addq %0, %%rax\n"
"adcq $0, %%rdx\n"
"movq %%rax, (%1)\n"
"movq %%rdx, %0"
: "+rm" (carry)
: "rdi" (ii), "rsi" (n)
: "rax", "rdx"
);
if(ii->next == NULL) {
if(carry)
infint_push(ii, carry);
return;
}
ii = ii->next;
} while(1);
}
void infint_mult2(infint_t *ii1, infint_t *ii2) {
infint_t *acc, *acc_ptr, *tmp;
acc = infint_clone(ii1);
infint_mult(acc, ii2->data);
acc_ptr = acc;
while (ii2->next) {
if(acc_ptr->next == NULL) infint_push(acc_ptr, 0);
acc_ptr = acc_ptr->next;
ii2 = ii2->next;
tmp = infint_clone(ii1);
infint_mult(tmp, ii2->data);
infint_add2(acc_ptr, tmp);
infint_destroy(tmp);
}
infint_destroy(ii1->next);
ii1->next = acc->next;
ii1->next->prev = ii1;
ii1->data = acc->data;
free(acc);
}
char infint_lt(infint_t *ii, uint64_t n) {
return !(ii->next) || ii->data < n;
}
char infint_lt2(infint_t *ii1, infint_t *ii2) {
while (ii1->next && ii2->next) {
ii1 = ii1->next;
ii2 = ii2->next;
}
if (ii1->next) {
return 0;
}
else if (ii2->next) {
return 1;
}
else {
return ii1->data < ii2->data;
}
}

32
infint.h

@ -0,0 +1,32 @@
#ifndef INFNUMH
#define INFNUMH
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct infint_t {
uint64_t data;
struct infint_t *next, *prev;
} infint_t;
typedef struct infnum_t {
struct infint_t *top, *bot;
} infnum_t;
infint_t* infint_from_uint64(uint64_t n);
infint_t* infint_clone(infint_t *src);
void infint_push(infint_t *ii, uint64_t n);
void infint_destroy(infint_t *ii);
void infint_print(infint_t *ii);
void infint_invert(infint_t *ii);
void infint_add(infint_t *ii, uint64_t n);
void infint_add2(infint_t *ii1, infint_t *ii2);
char infint_sub(infint_t *ii, uint64_t n);
char infint_sub2(infint_t *ii1, infint_t *ii2);
void infint_mult(infint_t *ii, uint64_t n);
void infint_mult2(infint_t *ii1, infint_t *ii2);
char infint_lt(infint_t *ii, uint64_t n);
char infint_lt2(infint_t *ii1, infint_t *ii2);
#endif

32
main.c

@ -1,7 +1,35 @@
#include <stdio.h>
#include <stdlib.h>
#include "expr.h"
#include "infint.h"
int main() {
infint_t *test1, *test2;
test1 = infint_from_uint64(1 << 23);
test2 = infint_from_uint64(1 << 24);
infint_push(test1, 1);
printf("test1 = ");
infint_print(test1);
printf("\n");
printf("test2 = ");
infint_print(test2);
printf(" * 0x%lX = ", ((uint64_t)1) << 56);
infint_mult(test2, ((uint64_t)1) << 56);
infint_print(test2);
printf("\n");
printf("test3 = test1 * test2 = ");
infint_mult2(test1, test2);
infint_print(test1);
printf("\n");
infint_destroy(test1);
infint_destroy(test2);
}
/*#include "expr.h"
#include "parse.h"
int main() {
@ -16,4 +44,4 @@ int main() {
print_expr_tree(e, 0);
destroy_expr(e);
}
}*/
Loading…
Cancel
Save