No you should not be using the _ui versions of the functions. We are dealing with strings here, or mpz objects internally. Not any little unsigned ints.
Personally I think you should throw all that away and start again. It's a mess. It mixes up concerns, BASIC to C interfacing and big integer calculation. It's hard to understand, even for you apparently, it's hard to test.
What should happen is that the big integer maths function get split out into their own C file with their own header file. This makes them easy to understand, isolates the interface to GMP from the rest of the code, is easy to test with a test harness in C.
Then you interface.c module should only use the interface exposed by that big integers header file. It would only pass strings in and out. It should not contain any GMP calls or know anything about GMP so becomes easier to understand and test.
It's all about isolation of concerns.
To that end I have split the code into three files:
integer_strings.c - Contains the maths functions and all GMP interfacing.
integer_strings.h - Defines the interface to the above. Only strings as parameters and return values.
fibo_strings.h - The test harness for integer strings. Happens to be a fibo calculator.
Integer_strings.h
Code: Select all
//
//
// An experiment in doing integer arithmetic using GMP with all numbers represented by strings.
//
// By heater.
//
// Number base used for internal calculations by GMP.
#define IS_BASE 32
// Functions letis, addis, subis and mulis do large integer arithmetic on integers represented by strings.
void is_write(const char *s);
char* is_let(const char* s);
char* is_add(const char* s1, const char* s2);
char* is_sub(const char* s1, const char* s2);
char* is_mul(const char* s1, const char* s2);
char* is_base(const char *s, int base);
void is_init();
void is_clear();
Code: Select all
//
// An experiment in doing integer arithmetic using GMP with all numbers represented by strings.
//
// By heater.
// Modified June 11, 2019 to use base 32 strings for intermediate results.
//
#include <gmp.h>
#include <string.h>
#include "integer_strings.h"
// Functions letis, addis, subis and mulis do large integer arithmetic on integers represented by strings.
// WARNING: Not thread safe due to use of global op1, op2, res.
static mpz_t op1;
static mpz_t op2;
static mpz_t res;
char* is_base(const char *s, int base) {
mpz_set_str (op1, s, IS_BASE);
char* res_string = mpz_get_str (0, base, op1);
return res_string;
}
char* is_let(const char* s) {
return strdup(s);
}
char* is_add(const char* s1, const char* s2) {
mpz_set_str (op1, s1, IS_BASE);
mpz_set_str (op2, s2, IS_BASE);
mpz_add (res, op1, op2); // result = x * y
char* res_string = mpz_get_str (0, IS_BASE, res);
return res_string;
}
char* is_sub(const char* s1, const char* s2) {
mpz_set_str (op1, s1, IS_BASE);
mpz_set_str (op2, s2, IS_BASE);
mpz_sub (res, op1, op2); // result = x * y
char* res_string = mpz_get_str (0, IS_BASE, res);
return res_string;
}
char* is_mul(const char* s1, const char* s2) {
mpz_set_str (op1, s1, IS_BASE);
mpz_set_str (op2, s2, IS_BASE);
mpz_mul (res, op1, op2); // result = x * y
char* res_string = mpz_get_str (0, IS_BASE, res);
return res_string;
}
void is_init() {
mpz_init(op1);
mpz_init(op2);
mpz_init(res);
}
void is_clear() {
mpz_clear(op1);
mpz_clear(op2);
mpz_clear(res);
}
Code: Select all
//
// An experiment in doing integer arithmetic using GMP with all numbers represented by strings.
//
// By heater.
//
#include <stdio.h>
#include <stdlib.h>
#include "integer_strings.h"
char* fibos[3];
// Return the n'th Fibonacci number as a decimal string for integer n
char* fibo (int n) {
char* res;
if (n <= 2) {
return is_let(fibos[n]);
}
int k = (n / 2);
char* fk = fibo(k);
char* fk1 = fibo(k + 1);
char* a;
char* b;
if ((n % 2) == 0) {
a = is_add(fk1, fk1);
b = is_sub(a, fk);
res = is_mul(fk, b);
} else {
a = is_mul(fk, fk);
b = is_mul(fk1, fk1);
res = is_add(a, b);
}
free(a);
free(b);
free(fk);
free(fk1);
return res;
}
int main(int argc, char* argv[]) {
int n = 4784969; // The first Fibonacci number with a million digits
if (argc >= 2) {
n = atoi(argv[1]);
}
is_init();
fibos[0] = is_let("0");
fibos[1] = is_let("1");
fibos[2] = is_let("1");
char* f = fibo(n);
char* f10 = is_base(f, 10);
puts(f10);
free(f10);
free(f);
free(fibos[0]);
free(fibos[1]);
free(fibos[2]);
is_clear();
return (0);
}
Code: Select all
$ gcc -Wall -g -O0 -o fibo_strings fibo_strings.c integer_strings.c -lgmp
$ time ./fibo_strings | head -c 32 ; time ./fibo_strings | tail -c 32
10727395641800477229364813596225
real 0m1.946s
user 0m1.891s
sys 0m0.016s
4856539211500699706378405156269
real 0m1.957s
user 0m1.906s
sys 0m0.063s
All in the fibo repository: https://github.com/ZiCog/fibo_4784969/tree/master/c