Browse Source

Began switch over base100 math. Addition and some utils done.

long_to_char
Cameron Weinfurt 3 years ago
parent
commit
0d42cb18c5
  1. 301
      infint.c
  2. 34
      infint.h
  3. 28
      infint_add.c
  4. 42
      infint_util.c
  5. 34
      main.c

301
infint.c

@ -1,299 +1,2 @@
#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 && ii->data < n) {
do {
ii = ii->next;
ii->data ^= -1;
ii->data += 1;
} while (ii->data < 1);
}
ii->data ^= -1;
while(ii->prev != NULL) {
ii = ii->prev;
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);
}
void infint_shr(infint_t *ii) {
while(ii->next) ii = ii->next;
uint64_t lsb;
uint64_t msb = 0;
do {
lsb = ii->data & 1;
ii->data >>= 1;
ii->data += msb;
msb = lsb << 63;
} while (ii->prev);
}
uint64_t infint_div(infint_t *ii, uint64_t n) {
uint64_t tmp;
if (!ii->next) {
tmp = ii->data % n;
ii->data /= n;
}
else {
infint_t *i128, *ni, *ni_tmp;
while (ii->next) ii = ii->next;
i128 = infint_from_uint64(0);
ni = infint_from_uint64(n);
tmp = ii->data % n;
ii->data /= n;
do {
infint_push(i128, tmp);
ii = ii->prev;
i128->data = ii->data % n;
ii->data /= n;
while (infint_lt2(ni,i128)) {
infint_destroy(ni_tmp);
ni_tmp = infint_clone(ni);
infint_mult(ni,2);
}
infint_destroy(ni);
ni = ni_tmp;
tmp = 0;
while(!(ni->data & 1)) {
tmp += 1;
infint_sub2(i128,ni);
while(infint_lt2(ni,i128) & !(ni->data & 1)) {
infint_shr(ni);
tmp <<= 1;
}
}
ii->data += tmp;
tmp = n - i128->data;
} while (ii->prev);
}
while (ii->next) ii = ii->next;
while (ii->data == 0 && ii->prev) {
ii = ii->prev;
free(ii->next);
ii->next = NULL;
}
return tmp;
}
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;
}
}
#include "infint_util.c"
#include "infint_add.c"

34
infint.h

@ -1,34 +1,24 @@
#ifndef INFNUMH
#define INFNUMH
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
typedef struct infint_t {
uint64_t data;
struct infint_t *next, *prev;
uint8_t *data;
size_t capacity, size;
char sign;
} infint_t;
typedef struct infnum_t {
struct infint_t *top, *bot;
} infnum_t;
// Utility functions
infint_t *infint_new(size_t init_cap);
infint_t *infint_clone(infint_t *ii);
void infint_free(infint_t *ii);
char infint_grow_to(infint_t *ii, size_t size);
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);
void infint_shr(infint_t *ii);
uint64_t infint_div(infint_t *ii, uint64_t n);
char infint_lt(infint_t *ii, uint64_t n);
char infint_lt2(infint_t *ii1, infint_t *ii2);
// Addition and Subtraction
void infint_add(infint_t *ii, uint8_t n);
void infint_sub(infint_t *ii, uint8_t n);
#endif

28
infint_add.c

@ -0,0 +1,28 @@
#include "infint.h"
void infint_add(infint_t *ii, uint8_t n) {
if(ii->sign) {
ii->sign = 0;
infint_sub(ii, n);
ii->sign ^= 1;
} else {
uint16_t sum = n;
sum += ii->data[0];
ii->data[0] = sum % 100;
sum /= 100;
for (int i = 1; sum > 0; ++i) {
infint_grow_to(ii, i + 1);
sum += ii->data[i];
ii->data[i] = sum % 100;
sum /= 100;
}
}
}
void infint_sub(infint_t *ii, uint8_t n) {
if(ii->sign) {
ii->sign = 0;
infint_add(ii, n);
ii->sign = 1;
}
}

42
infint_util.c

@ -0,0 +1,42 @@
#include "infint.h"
infint_t *infint_new(size_t init_cap) {
infint_t *ii = (infint_t *) malloc(sizeof(infint_t));
ii->capacity = init_cap;
ii->size = 1;
ii->data = (uint8_t *) calloc(init_cap, sizeof(uint8_t));
ii->sign = 0;
return ii;
}
infint_t *infint_clone(infint_t *ii) {
infint_t *iic = (infint_t *) malloc(sizeof(infint_t));
iic->capacity = ii->capacity;
iic->size = ii->size;
iic->data = (uint8_t *) malloc(ii->capacity * sizeof(uint8_t));
iic->sign = ii->sign;
memcpy(ii->data, iic->data, ii->capacity);
return iic;
}
void infint_del(infint_t *ii) {
free(ii->data);
free(ii);
}
char infint_grow_to(infint_t *ii, size_t size) {
if (size > ii->capacity) {
size_t new_cap = ii->capacity * 2;
while (size > new_cap) new_cap *= 2;
uint8_t *new_data = realloc(ii->data, new_cap * sizeof(uint8_t));
if (new_data != NULL) {
memset(new_data + ii->capacity, 0, new_cap - ii->capacity);
ii->data = new_data;
ii->capacity = new_cap;
} else {
return -1;
}
}
ii->size = size;
return 0;
}

34
main.c

@ -4,34 +4,12 @@
#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");
printf("test4 = test2 / 0x100000 = ");
uint64_t rem = infint_div(test2, 0x100000);
infint_print(test2);
printf(" R %ld\n", rem);
infint_destroy(test1);
infint_destroy(test2);
infint_t *test1;
test1 = infint_new(2);
infint_add(test1, 20);
printf("%d, %d\n", test1->data[0], test1->data[1]);
infint_add(test1, 90);
printf("%d, %d\n", test1->data[0], test1->data[1]);
}
/*#include "expr.h"

Loading…
Cancel
Save