Refactor bigints, add int and float conv functions
Added functions to convert from/to ints/floats. Floats are converted according to basic Steele&White algorithm (without speedup).
This commit is contained in:
21
src/String/Core.c
Normal file
21
src/String/Core.c
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <BH/String.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
void BH_StringFree(char *string)
|
||||
{
|
||||
free(string);
|
||||
}
|
||||
|
||||
|
||||
char *BH_StringCopy(const char *string)
|
||||
{
|
||||
char *result;
|
||||
|
||||
result = malloc(strlen(string) + 1);
|
||||
if (result)
|
||||
strcpy(result, string);
|
||||
|
||||
return result;
|
||||
}
|
||||
814
src/String/Float.c
Normal file
814
src/String/Float.c
Normal file
@@ -0,0 +1,814 @@
|
||||
#include <BH/String.h>
|
||||
#include <BH/Util.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define BUFSIZE 309
|
||||
#define DIGITS 70
|
||||
#define NORMAL 0
|
||||
#define ABSOLUTE 1
|
||||
#define RELATIVE 2
|
||||
|
||||
|
||||
typedef struct BInt {
|
||||
int size;
|
||||
uint16_t data[DIGITS];
|
||||
} BInt;
|
||||
|
||||
|
||||
struct DragonState
|
||||
{
|
||||
BInt r;
|
||||
BInt s;
|
||||
BInt mm;
|
||||
BInt mp;
|
||||
BInt tmp[5];
|
||||
int cutoff;
|
||||
int k;
|
||||
};
|
||||
|
||||
|
||||
static const BInt BInt1 = {1, {1}};
|
||||
static const BInt BInt10 = {1, {10}};
|
||||
|
||||
|
||||
static const uint8_t clzLookup[256] =
|
||||
{
|
||||
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
|
||||
static int BIntClz(uint16_t value)
|
||||
{
|
||||
if (value & 0xFF00)
|
||||
return clzLookup[(value >> 8) & 0xFF];
|
||||
else
|
||||
return 8 + clzLookup[value & 0xFF];
|
||||
}
|
||||
|
||||
|
||||
static void BIntTrim(BInt *in)
|
||||
{
|
||||
while (in->size && !in->data[in->size - 1])
|
||||
in->size--;
|
||||
}
|
||||
|
||||
|
||||
static int BIntCompare(const BInt *a,
|
||||
const BInt *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Compare by lengths */
|
||||
i = a->size - b->size;
|
||||
if (a->size - b->size)
|
||||
return a->size - b->size;
|
||||
|
||||
/* Compare by blocks */
|
||||
for (i = a->size; i; i--)
|
||||
{
|
||||
if (a->data[i - 1] < b->data[i - 1])
|
||||
return -1;
|
||||
else if (a->data[i - 1] > b->data[i - 1])
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void BIntAdd(const BInt *a,
|
||||
const BInt *b,
|
||||
BInt *out)
|
||||
{
|
||||
uint32_t carry;
|
||||
int i;
|
||||
|
||||
assert(a->size + 1 <= DIGITS);
|
||||
assert(b->size + 1 <= DIGITS);
|
||||
|
||||
/* Addition loop */
|
||||
carry = 0;
|
||||
for (i = 0; i < a->size || i < b->size; i++)
|
||||
{
|
||||
if (i < a->size)
|
||||
carry += a->data[i];
|
||||
if (i < b->size)
|
||||
carry += b->data[i];
|
||||
|
||||
out->data[i] = carry & 0xFFFF;
|
||||
carry = (carry >> 16);
|
||||
}
|
||||
|
||||
/* Handle new digit */
|
||||
if (carry)
|
||||
out->data[i++] = carry;
|
||||
|
||||
out->size = i;
|
||||
}
|
||||
|
||||
|
||||
static void BIntSub(const BInt *a,
|
||||
const BInt *b,
|
||||
BInt *out)
|
||||
{
|
||||
uint32_t carry;
|
||||
int i;
|
||||
|
||||
/* Main subtraction loop */
|
||||
carry = 0;
|
||||
for (i = 0; i < a->size || i < b->size; i++)
|
||||
{
|
||||
if (i < a->size)
|
||||
carry += a->data[i];
|
||||
if (i < b->size)
|
||||
carry -= b->data[i];
|
||||
|
||||
out->data[i] = carry & 0xFFFF;
|
||||
carry = (carry & 0xFFFF0000) | (carry >> 16);
|
||||
}
|
||||
|
||||
/* Trim leading zeros */
|
||||
out->size = a->size;
|
||||
BIntTrim(out);
|
||||
}
|
||||
|
||||
|
||||
static void BIntMul(const BInt *a,
|
||||
const BInt *b,
|
||||
BInt *out)
|
||||
{
|
||||
uint32_t carry;
|
||||
int i, j;
|
||||
|
||||
assert(a->size + b->size <= DIGITS);
|
||||
|
||||
/* Zero out the result */
|
||||
memset(out->data, 0, sizeof(out->data));
|
||||
for (i = 0; i < DIGITS; i++)
|
||||
out->data[i] = 0;
|
||||
|
||||
/* Multiplication loop */
|
||||
for (i = 0; i < a->size; i++)
|
||||
{
|
||||
carry = 0;
|
||||
for (j = 0; j < b->size; j++)
|
||||
{
|
||||
carry += out->data[i + j];
|
||||
carry += (uint32_t)a->data[i] * (uint32_t)b->data[j];
|
||||
out->data[i + j] = carry & 0xFFFF;
|
||||
carry = (carry >> 16);
|
||||
}
|
||||
out->data[i + j] += carry;
|
||||
}
|
||||
|
||||
/* Trim leading zeros */
|
||||
out->size = a->size + b->size;
|
||||
BIntTrim(out);
|
||||
}
|
||||
|
||||
|
||||
static void BIntMulDigit(const BInt *a,
|
||||
uint16_t b,
|
||||
BInt *out)
|
||||
{
|
||||
uint32_t carry;
|
||||
int i;
|
||||
|
||||
assert(a->size + 1 <= DIGITS);
|
||||
|
||||
/* Multiplication loop */
|
||||
carry = 0;
|
||||
for (i = 0; i < a->size; i++)
|
||||
{
|
||||
carry += (uint32_t)a->data[i] * b;
|
||||
out->data[i] = carry & 0xFFFF;
|
||||
carry = (carry >> 16);
|
||||
}
|
||||
out->data[i] = carry;
|
||||
|
||||
/* Trim leading zeros */
|
||||
out->size = a->size + 1;
|
||||
BIntTrim(out);
|
||||
}
|
||||
|
||||
|
||||
static void BIntLsh(const BInt *in,
|
||||
int amount,
|
||||
BInt *out)
|
||||
{
|
||||
int blocks, bits, i;
|
||||
uint16_t low, high;
|
||||
|
||||
blocks = amount / 16;
|
||||
bits = amount % 16;
|
||||
|
||||
assert(in->size + blocks + (bits > 0) <= DIGITS);
|
||||
|
||||
if (!in->size)
|
||||
{
|
||||
out->size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Main shift loop */
|
||||
if (bits)
|
||||
{
|
||||
high = 0;
|
||||
for (i = in->size + blocks; i > blocks; i--)
|
||||
{
|
||||
low = in->data[i - blocks - 1] >> (16 - bits);
|
||||
out->data[i] = low | high;
|
||||
high = in->data[i - blocks - 1] << bits;
|
||||
}
|
||||
out->data[i] = high;
|
||||
out->size = in->size + blocks + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = in->size; i; i--)
|
||||
out->data[i - 1 + blocks] = in->data[i - 1];
|
||||
out->size = in->size + blocks;
|
||||
}
|
||||
|
||||
/* Trim leading zeros and zero out lower blocks */
|
||||
BIntTrim(out);
|
||||
for (i = blocks; i; i--)
|
||||
out->data[i - 1] = 0;
|
||||
}
|
||||
|
||||
|
||||
static void BIntRsh(const BInt *in,
|
||||
int amount,
|
||||
BInt *out)
|
||||
{
|
||||
int blocks, bits, i;
|
||||
uint16_t low, high;
|
||||
|
||||
blocks = amount / 16;
|
||||
bits = amount % 16;
|
||||
|
||||
/* Zero size input or shift is bigger then input */
|
||||
if (in->size == 0 || in->size <= blocks)
|
||||
{
|
||||
out->size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Shift and copy parts of two blocks */
|
||||
low = in->data[blocks] >> bits;
|
||||
high = 0;
|
||||
for (i = 0; i < in->size - blocks - 1; i++)
|
||||
{
|
||||
high = in->data[i + blocks + 1] << (16 - bits);
|
||||
out->data[i] = low | high;
|
||||
low = in->data[i + blocks + 1] >> bits;
|
||||
}
|
||||
out->data[in->size - blocks - 1] = low;
|
||||
|
||||
/* Trim leading zeros */
|
||||
out->size = in->size - blocks;
|
||||
BIntTrim(out);
|
||||
}
|
||||
|
||||
|
||||
static uint16_t BIntGuess(const BInt *a,
|
||||
const BInt *b)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
if (BIntCompare(a, b) < 0)
|
||||
return 0;
|
||||
|
||||
tmp = a->data[a->size - 1];
|
||||
if (a->size != b->size)
|
||||
tmp = tmp << 16 | a->data[a->size - 2];
|
||||
|
||||
return tmp / b->data[b->size - 1];
|
||||
}
|
||||
|
||||
|
||||
static void BIntDiv(const BInt *a,
|
||||
const BInt *b,
|
||||
BInt *q,
|
||||
BInt *r,
|
||||
BInt *tmp)
|
||||
{
|
||||
uint16_t digit;
|
||||
int shift;
|
||||
|
||||
/* Handle case where a is less then b */
|
||||
if (BIntCompare(a, b) < 0)
|
||||
{
|
||||
*r = *a;
|
||||
q->size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Normilize input to reduce tries */
|
||||
shift = BIntClz(b->data[b->size - 1]);
|
||||
BIntLsh(a, shift, &tmp[0]);
|
||||
BIntLsh(b, shift, &tmp[1]);
|
||||
|
||||
/* Prepare first step of the division */
|
||||
q->size = 0;
|
||||
r->size = 0;
|
||||
while (BIntCompare(r, &tmp[1]) < 0)
|
||||
{
|
||||
BIntLsh(r, 16, r);
|
||||
r->data[0] = tmp[0].data[--tmp[0].size];
|
||||
r->size += !r->size;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Make a guess and check */
|
||||
digit = BIntGuess(r, &tmp[1]);
|
||||
BIntMulDigit(&tmp[1], digit, &tmp[2]);
|
||||
while (BIntCompare(r, &tmp[2]) < 0)
|
||||
{
|
||||
--digit;
|
||||
BIntSub(&tmp[2], &tmp[1], &tmp[2]);
|
||||
}
|
||||
|
||||
/* Store digit in quotient */
|
||||
BIntSub(r, &tmp[2], r);
|
||||
BIntLsh(q, 16, q);
|
||||
q->data[0] = digit;
|
||||
q->size += !q->size;
|
||||
|
||||
/* Fetch next digit or exit */
|
||||
if (!tmp[0].size)
|
||||
break;
|
||||
|
||||
BIntLsh(r, 16, r);
|
||||
r->data[0] = tmp[0].data[--tmp[0].size];
|
||||
if (!r->size)
|
||||
r->size = 1;
|
||||
}
|
||||
|
||||
/* Normilize remainder */
|
||||
BIntRsh(r, shift, r);
|
||||
}
|
||||
|
||||
|
||||
static void dragonFixup(struct DragonState *state,
|
||||
int precision,
|
||||
int mode,
|
||||
uint64_t f)
|
||||
{
|
||||
if (f == (((uint64_t)1) << 52))
|
||||
{
|
||||
BIntLsh(&state->mp, 1, &state->mp);
|
||||
BIntLsh(&state->r, 1, &state->r);
|
||||
BIntLsh(&state->s, 1, &state->s);
|
||||
}
|
||||
state->k = 0;
|
||||
|
||||
BIntDiv(&state->s, &BInt10, &state->tmp[0], &state->tmp[1], state->tmp + 2);
|
||||
if (state->tmp[1].size)
|
||||
BIntAdd(&state->tmp[0], &BInt1, &state->tmp[0]);
|
||||
|
||||
while (BIntCompare(&state->r, &state->tmp[0]) < 0)
|
||||
{
|
||||
state->k -= 1;
|
||||
BIntMulDigit(&state->r, 10, &state->r);
|
||||
BIntMulDigit(&state->mm, 10, &state->mm);
|
||||
BIntMulDigit(&state->mp, 10, &state->mp);
|
||||
BIntDiv(&state->s, &BInt10, &state->tmp[0], &state->tmp[1], state->tmp + 2);
|
||||
if (state->tmp[1].size)
|
||||
BIntAdd(&state->tmp[0], &BInt1, &state->tmp[0]);
|
||||
}
|
||||
|
||||
BIntLsh(&state->r, 1, &state->tmp[0]);
|
||||
BIntAdd(&state->tmp[0], &state->mp, &state->tmp[0]);
|
||||
BIntLsh(&state->s, 1, &state->tmp[1]);
|
||||
while (BIntCompare(&state->tmp[0], &state->tmp[1]) >= 0)
|
||||
{
|
||||
state->k += 1;
|
||||
BIntMulDigit(&state->s, 10, &state->s);
|
||||
BIntLsh(&state->s, 1, &state->tmp[1]);
|
||||
}
|
||||
|
||||
if (mode == NORMAL)
|
||||
state->cutoff = state->k - BUFSIZE;
|
||||
else if (mode == RELATIVE)
|
||||
state->cutoff = state->k - precision;
|
||||
else
|
||||
state->cutoff = -precision;
|
||||
}
|
||||
|
||||
|
||||
static void dragonRound(struct DragonState *state,
|
||||
char *buffer,
|
||||
int *k,
|
||||
int *size,
|
||||
int high,
|
||||
int low,
|
||||
char s)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Check if rounding up required */
|
||||
if (high == low)
|
||||
{
|
||||
BIntLsh(&state->r, 1, &state->tmp[0]);
|
||||
i = BIntCompare(&state->tmp[0], &state->s);
|
||||
if (i < 0) { low = 1; high = 0; }
|
||||
else if (i > 0) { low = 0; high = 1; }
|
||||
else low = (((s - '0') & 0x1) == 0);
|
||||
}
|
||||
|
||||
/* Perform rounding up */
|
||||
if (!low)
|
||||
{
|
||||
for (i = *size; i && buffer[i - 1] == '9'; i--)
|
||||
buffer[i - 1] = '0';
|
||||
|
||||
if (i > 0)
|
||||
buffer[i - 1]++;
|
||||
else
|
||||
{
|
||||
buffer[0] = '1';
|
||||
(*k)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void dragon(double value,
|
||||
int precision,
|
||||
int mode,
|
||||
char *buffer,
|
||||
int *size,
|
||||
int *k)
|
||||
{
|
||||
struct DragonState state;
|
||||
int low, high, e;
|
||||
uint64_t f;
|
||||
char s;
|
||||
|
||||
*k = 0;
|
||||
*size = low = high = 0;
|
||||
|
||||
/* If value is zero - do nothing */
|
||||
if (!value)
|
||||
{
|
||||
buffer[(*size)++] = '0';
|
||||
return;
|
||||
}
|
||||
|
||||
/* Prepare dragon */
|
||||
f = frexp(value, &e) * ((uint64_t)1 << 53);
|
||||
state.r.data[0] = f & 0xFFFF; state.r.data[1] = (f >> 16) & 0xFFFF;
|
||||
state.r.data[2] = (f >> 32) & 0xFFFF; state.r.data[3] = (f >> 48) & 0xFFFF;
|
||||
state.r.size = 4; BIntTrim(&state.r);
|
||||
|
||||
BIntLsh(&state.r, MAX(e - 53, 0), &state.r);
|
||||
BIntLsh(&BInt1, MAX(0, -(e - 53)), &state.s);
|
||||
BIntLsh(&BInt1, MAX(e - 53, 0), &state.mm);
|
||||
BIntLsh(&BInt1, MAX(e - 53, 0), &state.mp);
|
||||
dragonFixup(&state, precision, mode, f);
|
||||
|
||||
/* Main digit generation loop */
|
||||
*k = state.k - 1;
|
||||
while(1)
|
||||
{
|
||||
state.k -= 1;
|
||||
BIntMulDigit(&state.r, 10, &state.r);
|
||||
BIntDiv(&state.r, &state.s, &state.tmp[0], &state.r, state.tmp + 1);
|
||||
|
||||
s = '0';
|
||||
if (state.tmp[0].size)
|
||||
s += state.tmp[0].data[0];
|
||||
buffer[(*size)++] = s;
|
||||
|
||||
if (mode == NORMAL)
|
||||
{
|
||||
BIntLsh(&state.r, 1, &state.tmp[1]);
|
||||
BIntLsh(&state.s, 1, &state.tmp[2]);
|
||||
BIntSub(&state.tmp[2], &state.mp, &state.tmp[2]);
|
||||
BIntMulDigit(&state.mm, 10, &state.mm);
|
||||
BIntMulDigit(&state.mp, 10, &state.mp);
|
||||
low = BIntCompare(&state.tmp[1], &state.mm) < 0;
|
||||
high = BIntCompare(&state.tmp[1], &state.tmp[2]) > 0;
|
||||
if (low || high || state.k == state.cutoff || *size >= BUFSIZE)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!state.r.size || state.k == state.cutoff || *size >= BUFSIZE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Round digits if required */
|
||||
dragonRound(&state, buffer, k, size, high, low, s);
|
||||
}
|
||||
|
||||
|
||||
static char *formatF(char buffer[BUFSIZE],
|
||||
int precision,
|
||||
int sign,
|
||||
int k,
|
||||
int size)
|
||||
{
|
||||
char *result, *current;
|
||||
int i;
|
||||
|
||||
result = malloc(MAX(0, k) + 5 + sign + precision);
|
||||
current = result;
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
/* Add sign */
|
||||
if (sign)
|
||||
*(current++) = '-';
|
||||
|
||||
/* Pad if exponent is small */
|
||||
if (k < 0)
|
||||
{
|
||||
*(current++) = '0';
|
||||
|
||||
if (precision > 0)
|
||||
*(current++) = '.';
|
||||
|
||||
for (i = 0; i < MIN(-k - 1, precision); i++)
|
||||
*(current++) = '0';
|
||||
}
|
||||
|
||||
/* Add digits */
|
||||
for (i = 0; k >= -precision; i++, k--)
|
||||
{
|
||||
if (i < size)
|
||||
*(current++) = buffer[i];
|
||||
else
|
||||
*(current++) = '0';
|
||||
|
||||
if (k == 0 && precision > 0)
|
||||
*(current++) = '.';
|
||||
}
|
||||
|
||||
*(current++) = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static char *formatE(char buffer[BUFSIZE],
|
||||
int precision,
|
||||
int sign,
|
||||
int k,
|
||||
int size,
|
||||
int upper)
|
||||
{
|
||||
char *result, *current;
|
||||
int i;
|
||||
|
||||
result = malloc(9 + sign + precision);
|
||||
current = result;
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
/* Add sign and digits */
|
||||
if (sign)
|
||||
*(current++) = '-';
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
*(current++) = buffer[i];
|
||||
if (i == 0 && precision > 0)
|
||||
*(current++) = '.';
|
||||
}
|
||||
|
||||
/* Pad to specified precision */
|
||||
for (; i < precision + 1; i++)
|
||||
*(current++) = '0';
|
||||
|
||||
/* Add exponent symbol and sign */
|
||||
*(current++) = "eE"[upper];
|
||||
if (k < 0)
|
||||
{
|
||||
*(current++) = '-';
|
||||
k = -k;
|
||||
}
|
||||
else
|
||||
*(current++) = '+';
|
||||
|
||||
/* Convert exponent to digits and add them */
|
||||
for (size = 0; k || size < 2; size++)
|
||||
{
|
||||
buffer[size] = '0' + k % 10;
|
||||
k = k / 10;
|
||||
}
|
||||
for (; size; size--)
|
||||
*(current++) = buffer[size - 1];
|
||||
|
||||
*(current++) = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static char *generateF(double value,
|
||||
int precision,
|
||||
int sign)
|
||||
{
|
||||
char buffer[BUFSIZE];
|
||||
int size, k;
|
||||
|
||||
/* Call Dragon4 and format the digits */
|
||||
if (precision < 0)
|
||||
dragon(value, 0, NORMAL, buffer, &size, &k);
|
||||
else
|
||||
dragon(value, precision, ABSOLUTE, buffer, &size, &k);
|
||||
|
||||
if (precision < 0)
|
||||
precision = MAX(0, size - k - 1);
|
||||
|
||||
return formatF(buffer, precision, sign, k, size);
|
||||
}
|
||||
|
||||
|
||||
static char *generateE(double value,
|
||||
int precision,
|
||||
int upper,
|
||||
int sign)
|
||||
{
|
||||
char buffer[BUFSIZE];
|
||||
int size, k;
|
||||
|
||||
/* Adjust precision and call Dragon4 to generate digits */
|
||||
if (precision < 0)
|
||||
dragon(value, 0, NORMAL, buffer, &size, &k);
|
||||
else
|
||||
dragon(value, (precision + 1), RELATIVE, buffer, &size, &k);
|
||||
|
||||
if (precision < 0)
|
||||
precision = size - 1;
|
||||
|
||||
return formatE(buffer, precision, sign, k, size, upper);
|
||||
}
|
||||
|
||||
|
||||
static char *generateG(double value,
|
||||
int precision,
|
||||
int upper,
|
||||
int sign)
|
||||
{
|
||||
char buffer[BUFSIZE];
|
||||
int size, k, fixed;
|
||||
|
||||
if (precision == 0)
|
||||
precision = 1;
|
||||
|
||||
/* Call Dragon4 to generate digits */
|
||||
if (precision < 0)
|
||||
{
|
||||
dragon(value, 0, NORMAL, buffer, &size, &k);
|
||||
fixed = k >= -4 && k <= (size - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
dragon(value, precision, RELATIVE, buffer, &size, &k);
|
||||
fixed = k >= -4 && k < precision;
|
||||
|
||||
/* Remove trailing zeros and adjust precision */
|
||||
for (; size && precision > 0 && buffer[size - 1] == '0'; size--, precision--);
|
||||
}
|
||||
|
||||
if (fixed)
|
||||
{
|
||||
precision = MAX(0, size - k - 1);
|
||||
return formatF(buffer, precision, sign, k, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
precision = MAX(0, size - 1);
|
||||
return formatE(buffer, precision, sign, k, size, upper);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char *BH_StringFromDouble(double value,
|
||||
char format,
|
||||
int precision)
|
||||
{
|
||||
static const char *infStrings[] = { "inf", "-inf", "INF", "-INF" };
|
||||
static const char *nanStrings[] = { "nan", "NAN" };
|
||||
int sign, type, upper;
|
||||
|
||||
type = BH_ClassifyDouble(value);
|
||||
upper = isupper(format) > 0;
|
||||
sign = (type & BH_FP_NEGATIVE) != 0;
|
||||
|
||||
if (sign)
|
||||
value = fabs(value);
|
||||
|
||||
/* Handle NaN and Inf */
|
||||
if (type == BH_FP_INFINITE)
|
||||
return BH_StringCopy(infStrings[upper * 2 + sign]);
|
||||
else if (type == BH_FP_NAN)
|
||||
return BH_StringCopy(nanStrings[upper]);
|
||||
|
||||
if (format == 'g' || format == 'G')
|
||||
return generateG(value, precision, upper, sign);
|
||||
else if (format == 'e' || format == 'E')
|
||||
return generateE(value, precision, upper, sign);
|
||||
else
|
||||
return generateF(value, precision, sign);
|
||||
}
|
||||
|
||||
|
||||
double BH_StringToDouble(const char *string,
|
||||
size_t *size)
|
||||
{
|
||||
int nsign, esign, e, dot;
|
||||
const char *current;
|
||||
char buffer[4];
|
||||
size_t count;
|
||||
|
||||
nsign = 0; esign = 0; e = 0; count = 0; dot = 0;
|
||||
current = string;
|
||||
|
||||
/* Skip whitespace */
|
||||
while (isspace(*current))
|
||||
current++;
|
||||
|
||||
/* Leading sign */
|
||||
if (*current == '+' || *current == '-')
|
||||
{
|
||||
if (*current == '-')
|
||||
nsign = 1;
|
||||
current++;
|
||||
}
|
||||
|
||||
/* Read integer part of the float */
|
||||
for (; isdigit(*current); current++)
|
||||
{
|
||||
if (count < sizeof(buffer) && (count || *current != '0'))
|
||||
buffer[count++] = *current;
|
||||
else if (count >= sizeof(buffer))
|
||||
dot--;
|
||||
}
|
||||
|
||||
/* Read fract part of the float */
|
||||
if (*current == '.')
|
||||
current++;
|
||||
|
||||
for (; isdigit(*current); current++)
|
||||
{
|
||||
if ((count < sizeof(buffer)))
|
||||
{
|
||||
dot++;
|
||||
if ((count || *current != '0'))
|
||||
buffer[count++] = *current;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read exp part of the float */
|
||||
if (*current == 'e' || *current == 'E')
|
||||
{
|
||||
current++;
|
||||
if (*current == '+' || *current == '-')
|
||||
{
|
||||
if (*current == '-')
|
||||
esign = 1;
|
||||
current++;
|
||||
}
|
||||
|
||||
for (; isdigit(*current); current++)
|
||||
e = e * 10 + *current - '0';
|
||||
}
|
||||
|
||||
if (esign)
|
||||
e = -e;
|
||||
e -= dot;
|
||||
|
||||
if (size)
|
||||
*size = current - string;
|
||||
|
||||
BH_UNUSED(nsign);
|
||||
BH_UNUSED(BIntMul);
|
||||
return 0.0;
|
||||
}
|
||||
234
src/String/Int.c
Normal file
234
src/String/Int.c
Normal file
@@ -0,0 +1,234 @@
|
||||
#include <BH/String.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
static const char lookup[] =
|
||||
{
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
|
||||
};
|
||||
|
||||
|
||||
static void skipSpace(const char **string,
|
||||
size_t *size)
|
||||
{
|
||||
while (isspace(**string))
|
||||
{
|
||||
(*string)++;
|
||||
if (size) (*size)++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void handleSign(const char **string,
|
||||
size_t *size,
|
||||
int *sign)
|
||||
{
|
||||
*sign = 1;
|
||||
if (**string == '-')
|
||||
{
|
||||
*sign = -1; (*string)++;
|
||||
if (size) (*size)++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void guessBase(const char **string,
|
||||
size_t *size,
|
||||
int *base)
|
||||
{
|
||||
if (*base != 0)
|
||||
return;
|
||||
|
||||
*base = 10;
|
||||
if (**string != '0')
|
||||
return;
|
||||
|
||||
(*string)++;
|
||||
if (size)
|
||||
(*size)++;
|
||||
|
||||
switch (**string)
|
||||
{
|
||||
case 'x': case 'X':
|
||||
*base = 16;
|
||||
(*string)++;
|
||||
if (size)
|
||||
(*size)++;
|
||||
break;
|
||||
|
||||
case 'b': case 'B':
|
||||
*base = 2;
|
||||
(*string)++;
|
||||
if (size)
|
||||
(*size)++;
|
||||
break;
|
||||
|
||||
default:
|
||||
*base = 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define TEMPLATE_IMPL \
|
||||
char tmp[sizeof(value) * CHAR_BIT + 1]; char *current, *end, *result; \
|
||||
int sign; end = tmp + sizeof(tmp); current = end; sign = 0; \
|
||||
if (value < 0) { sign = 1; value = -value; } while (value) { \
|
||||
*(--current) = digits[value % base]; value /= base; } \
|
||||
if (sign) { *(--current) = '-'; } result = malloc(end - current + 1); \
|
||||
if (!result) { return NULL; } memcpy(result, current, end - current); \
|
||||
result[end - current] = 0; return result;
|
||||
|
||||
|
||||
char *BH_StringFromInt8s(int8_t value,
|
||||
int base)
|
||||
{
|
||||
TEMPLATE_IMPL
|
||||
}
|
||||
|
||||
|
||||
char *BH_StringFromInt16s(int16_t value,
|
||||
int base)
|
||||
{
|
||||
TEMPLATE_IMPL
|
||||
}
|
||||
|
||||
|
||||
char *BH_StringFromInt32s(int32_t value,
|
||||
int base)
|
||||
{
|
||||
TEMPLATE_IMPL
|
||||
}
|
||||
|
||||
|
||||
char *BH_StringFromInt64s(int64_t value,
|
||||
int base)
|
||||
{
|
||||
TEMPLATE_IMPL
|
||||
}
|
||||
|
||||
|
||||
#undef TEMPLATE_IMPL
|
||||
#define TEMPLATE_IMPL \
|
||||
char tmp[sizeof(value) * CHAR_BIT]; char *current, *end, *result; \
|
||||
end = tmp + sizeof(tmp); current = end; while (value) { \
|
||||
*(--current) = digits[value % base]; value /= base; } \
|
||||
result = malloc(end - current + 1); if (!result) { return NULL; } \
|
||||
memcpy(result, current, end - current); result[end - current] = 0; \
|
||||
return result;
|
||||
|
||||
|
||||
char *BH_StringFromInt8u(uint8_t value,
|
||||
int base)
|
||||
{
|
||||
TEMPLATE_IMPL
|
||||
}
|
||||
|
||||
|
||||
char *BH_StringFromInt16u(uint16_t value,
|
||||
int base)
|
||||
{
|
||||
TEMPLATE_IMPL
|
||||
}
|
||||
|
||||
|
||||
char *BH_StringFromInt32u(uint32_t value,
|
||||
int base)
|
||||
{
|
||||
TEMPLATE_IMPL
|
||||
}
|
||||
|
||||
|
||||
char *BH_StringFromInt64u(uint64_t value,
|
||||
int base)
|
||||
{
|
||||
TEMPLATE_IMPL
|
||||
}
|
||||
|
||||
|
||||
#undef TEMPLATE_IMPL
|
||||
#define TEMPLATE_IMPL(type) \
|
||||
type result = 0; int sign, flag = 0; char sym; *size = 0; \
|
||||
if (base != 0 && (base < 2 || base > 36)) { return 0; } \
|
||||
skipSpace(&string, size); handleSign(&string, size, &sign); \
|
||||
guessBase(&string, size, &base); while(*string) { sym = *(string++); \
|
||||
sym = lookup[(unsigned int)sym]; if (sym >= base || sym == -1) { break; } \
|
||||
if (size) { (*size)++; } result = result * base + sym; flag = 1; } \
|
||||
if (!result && !flag && size) { *size = 0; } return result * sign;
|
||||
|
||||
|
||||
int8_t BH_StringToInt8s(const char *string,
|
||||
size_t *size,
|
||||
int base)
|
||||
{
|
||||
TEMPLATE_IMPL(int8_t)
|
||||
}
|
||||
|
||||
|
||||
int16_t BH_StringToInt16s(const char *string,
|
||||
size_t *size,
|
||||
int base)
|
||||
{
|
||||
TEMPLATE_IMPL(int16_t)
|
||||
}
|
||||
|
||||
|
||||
int32_t BH_StringToInt32s(const char *string,
|
||||
size_t *size,
|
||||
int base)
|
||||
{
|
||||
TEMPLATE_IMPL(int32_t)
|
||||
}
|
||||
|
||||
|
||||
int64_t BH_StringToInt64s(const char *string,
|
||||
size_t *size,
|
||||
int base)
|
||||
{
|
||||
TEMPLATE_IMPL(int64_t)
|
||||
}
|
||||
|
||||
|
||||
uint8_t BH_StringToInt8u(const char *string,
|
||||
size_t *size,
|
||||
int base)
|
||||
{
|
||||
TEMPLATE_IMPL(uint8_t)
|
||||
}
|
||||
|
||||
|
||||
uint16_t BH_StringToInt16u(const char *string,
|
||||
size_t *size,
|
||||
int base)
|
||||
{
|
||||
TEMPLATE_IMPL(uint16_t)
|
||||
}
|
||||
|
||||
|
||||
uint32_t BH_StringToInt32u(const char *string,
|
||||
size_t *size,
|
||||
int base)
|
||||
{
|
||||
TEMPLATE_IMPL(uint32_t)
|
||||
}
|
||||
|
||||
|
||||
uint64_t BH_StringToInt64u(const char *string,
|
||||
size_t *size,
|
||||
int base)
|
||||
{
|
||||
TEMPLATE_IMPL(uint64_t)
|
||||
}
|
||||
|
||||
|
||||
#undef TEMPLATE_IMPL
|
||||
@@ -1,488 +0,0 @@
|
||||
#include "String.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
static const uint8_t clzLookup[256] =
|
||||
{
|
||||
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
|
||||
static const uint16_t pow10Data[] =
|
||||
{
|
||||
0x0001, 0x000A, 0x0064, 0x2710, 0xE100, 0x05F5, 0x0000, 0x6FC1,
|
||||
0x86F2, 0x0023, 0x0000, 0x0000, 0xEF81, 0x85AC, 0x415B, 0x2D6D,
|
||||
0x04EE, 0x0000, 0x0000, 0x0000, 0x0000, 0x1F01, 0xBF6A, 0xED64,
|
||||
0x6E38, 0x97ED, 0xDAA7, 0xF9F4, 0xE93F, 0x4F03, 0x0018, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3E01,
|
||||
0x2E95, 0x9909, 0x03DF, 0x38FD, 0x0F15, 0xE42F, 0x2374, 0xF5EC,
|
||||
0xD3CF, 0xDC08, 0xC404, 0xB0DA, 0xBCCD, 0x7F19, 0xA633, 0x2603,
|
||||
0xE91F, 0x024E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x7C01, 0x982E, 0x875B, 0xBED3, 0x9F72, 0xD8D9,
|
||||
0x2F87, 0x1215, 0x50C6, 0x6BDE, 0x6E70, 0xCF4A, 0xD80F, 0xD595,
|
||||
0x716E, 0x26B2, 0x66B0, 0xADC6, 0x3624, 0x1D15, 0xD35A, 0x3C42,
|
||||
0x540E, 0x63FF, 0x73C0, 0xCC55, 0xEF17, 0x65F9, 0x28F2, 0x55BC,
|
||||
0xC7F7, 0x80DC, 0xEDDC, 0xF46E, 0xEFCE, 0x5FDC, 0x53F7, 0x0005,
|
||||
};
|
||||
|
||||
|
||||
static const int pow10Index[] =
|
||||
{
|
||||
0, 1, 2, 3, 4, 6, 10, 17, 31, 58,
|
||||
};
|
||||
|
||||
|
||||
static const int pow10Size[] =
|
||||
{
|
||||
1, 1, 1, 1, 2, 4, 7, 14, 27, 54,
|
||||
};
|
||||
|
||||
|
||||
static void pow10Set(int index,
|
||||
BH_Int1120 *out)
|
||||
{
|
||||
out->size = pow10Size[index];
|
||||
memcpy(out->digits, pow10Data + pow10Index[index], out->size * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
|
||||
int BH_Int1120Clz(const uint16_t value)
|
||||
{
|
||||
|
||||
|
||||
if (value & 0xFF00)
|
||||
return clzLookup[(value >> 8) & 0xFF];
|
||||
else
|
||||
return 8 + clzLookup[value & 0xFF];
|
||||
}
|
||||
|
||||
|
||||
int BH_Int1120Compare(const BH_Int1120 *a,
|
||||
const BH_Int1120 *b)
|
||||
{
|
||||
int i, result;
|
||||
|
||||
/* Compare by lengths */
|
||||
result = a->size - b->size;
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/* Compare by blocks */
|
||||
for (i = a->size; i; i--)
|
||||
{
|
||||
if (a->digits[i - 1] < b->digits[i - 1])
|
||||
return -1;
|
||||
else if (a->digits[i - 1] > b->digits[i - 1])
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void BH_Int1120Add(const BH_Int1120 *a,
|
||||
const BH_Int1120 *b,
|
||||
BH_Int1120 *out)
|
||||
{
|
||||
const BH_Int1120 *small, *big;
|
||||
uint32_t carry, tmp;
|
||||
int i;
|
||||
|
||||
small = b;
|
||||
big = a;
|
||||
|
||||
assert(a->size + 1 <= BH_INT1120_DIGITS);
|
||||
assert(b->size + 1 <= BH_INT1120_DIGITS);
|
||||
|
||||
/* Find smaller interger */
|
||||
if (a->size < b->size)
|
||||
{
|
||||
small = a;
|
||||
big = b;
|
||||
}
|
||||
|
||||
/* Main addition loop */
|
||||
carry = 0;
|
||||
for (i = 0; i < small->size; i++)
|
||||
{
|
||||
tmp = (uint32_t)small->digits[i] + (uint32_t)big->digits[i] + carry;
|
||||
carry = (tmp >> 16) & 0xFFFF;
|
||||
out->digits[i] = tmp & 0xFFFF;
|
||||
}
|
||||
|
||||
/* Carry propogation */
|
||||
for (; i < big->size; i++)
|
||||
{
|
||||
tmp = (uint32_t)big->digits[i] + carry;
|
||||
carry = (tmp >> 16) & 0xFFFF;
|
||||
out->digits[i] = tmp & 0xFFFF;
|
||||
}
|
||||
|
||||
/* Handle carry */
|
||||
if (carry)
|
||||
out->digits[i++] = carry;
|
||||
|
||||
out->size = i;
|
||||
}
|
||||
|
||||
|
||||
void BH_Int1120Sub(const BH_Int1120 *a,
|
||||
const BH_Int1120 *b,
|
||||
BH_Int1120 *out)
|
||||
{
|
||||
uint32_t carry, tmp;
|
||||
int i;
|
||||
|
||||
/* Main subtraction loop */
|
||||
carry = 0;
|
||||
for (i = 0; i < b->size; i++)
|
||||
{
|
||||
tmp = (uint32_t)a->digits[i] - (uint32_t)b->digits[i] - carry;
|
||||
carry = (tmp >> 31) & 0x1;
|
||||
out->digits[i] = tmp & 0xFFFF;
|
||||
}
|
||||
|
||||
/* Carry propogation */
|
||||
for (; i < a->size; i++)
|
||||
{
|
||||
tmp = (uint32_t)a->digits[i] - carry;
|
||||
carry = (tmp >> 31) & 0x1;
|
||||
out->digits[i] = tmp & 0xFFFF;
|
||||
}
|
||||
|
||||
/* Truncate length on empty blocks */
|
||||
out->size = a->size;
|
||||
while(out->size && !out->digits[out->size - 1])
|
||||
out->size--;
|
||||
}
|
||||
|
||||
|
||||
void BH_Int1120Mul(const BH_Int1120 *a,
|
||||
const BH_Int1120 *b,
|
||||
BH_Int1120 *out)
|
||||
{
|
||||
int i, j;
|
||||
uint32_t tmp, carry;
|
||||
|
||||
assert(a->size + b->size <= BH_INT1120_DIGITS);
|
||||
|
||||
for (i = 0; i < BH_INT1120_DIGITS; i++)
|
||||
out->digits[i] = 0;
|
||||
|
||||
for (i = 0; i < a->size; i++)
|
||||
{
|
||||
carry = 0;
|
||||
|
||||
/* Multiplication loop */
|
||||
for (j = 0; j < b->size; j++)
|
||||
{
|
||||
carry += (uint32_t)out->digits[i + j];
|
||||
tmp = (uint32_t)a->digits[i] * (uint32_t)b->digits[j] + carry;
|
||||
carry = (tmp >> 16) & 0xFFFF;
|
||||
out->digits[i + j] = tmp & 0xFFFF;
|
||||
}
|
||||
|
||||
/* Carry propagation */
|
||||
if (carry)
|
||||
{
|
||||
tmp = (uint32_t)out->digits[i + j] + carry;
|
||||
out->digits[i + j] = tmp & 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
out->size = a->size + b->size;
|
||||
if (!out->digits[out->size - 1])
|
||||
out->size--;
|
||||
}
|
||||
|
||||
|
||||
void BH_Int1120MulDigit(const BH_Int1120 *in,
|
||||
uint16_t digit,
|
||||
BH_Int1120 *out)
|
||||
{
|
||||
int i;
|
||||
uint32_t tmp, carry;
|
||||
|
||||
assert(in->size + 1 <= BH_INT1120_DIGITS);
|
||||
|
||||
for (i = 0; i < BH_INT1120_DIGITS; i++)
|
||||
out->digits[i] = 0;
|
||||
|
||||
/* Multiplication loop */
|
||||
carry = 0;
|
||||
for (i = 0; i < in->size; i++)
|
||||
{
|
||||
carry += (uint32_t)out->digits[i];
|
||||
tmp = (uint32_t)in->digits[i] * digit + carry;
|
||||
carry = (tmp >> 16) & 0xFFFF;
|
||||
out->digits[i] = tmp & 0xFFFF;
|
||||
}
|
||||
|
||||
/* Carry propagation */
|
||||
if (carry)
|
||||
{
|
||||
tmp = (uint32_t)out->digits[i] + carry;
|
||||
out->digits[i] = tmp & 0xFFFF;
|
||||
}
|
||||
|
||||
out->size = in->size + 1;
|
||||
if (!out->digits[out->size - 1])
|
||||
out->size--;
|
||||
}
|
||||
|
||||
|
||||
static uint16_t BH_Int1120DivGuess(const BH_Int1120 *a,
|
||||
const BH_Int1120 *b)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
/* Compare two values */
|
||||
if (BH_Int1120Compare(a, b) < 0)
|
||||
return 0;
|
||||
|
||||
/* Make a guess */
|
||||
tmp = a->digits[a->size - 1];
|
||||
if (a->size != b->size)
|
||||
tmp = tmp << 16 | a->digits[a->size - 2];
|
||||
|
||||
return tmp / b->digits[b->size - 1];
|
||||
}
|
||||
|
||||
|
||||
void BH_Int1120Div(const BH_Int1120 *a,
|
||||
const BH_Int1120 *b,
|
||||
BH_Int1120 *q,
|
||||
BH_Int1120 *r)
|
||||
{
|
||||
BH_Int1120 left, right, tmp;
|
||||
uint16_t guess;
|
||||
int shift;
|
||||
|
||||
assert(a->size >= b->size);
|
||||
assert(b->size > 0);
|
||||
|
||||
/* Normilize input to reduce tries */
|
||||
shift = BH_Int1120Clz(b->digits[b->size - 1]);
|
||||
BH_Int1120Lsh(a, shift, &left);
|
||||
BH_Int1120Lsh(b, shift, &right);
|
||||
|
||||
/* Prepare first step of the division */
|
||||
q->size = 0;
|
||||
r->size = 0;
|
||||
while (BH_Int1120Compare(r, &right) < 0)
|
||||
{
|
||||
BH_Int1120Lsh(r, 16, r);
|
||||
r->digits[0] = left.digits[--left.size];
|
||||
|
||||
if (!r->size)
|
||||
r->size = 1;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Make a guess and check */
|
||||
guess = BH_Int1120DivGuess(r, &right);
|
||||
BH_Int1120MulDigit(&right, guess, &tmp);
|
||||
|
||||
/* If the guess was wrong - decrement guess and try again */
|
||||
while (BH_Int1120Compare(r, &tmp) < 0)
|
||||
BH_Int1120MulDigit(&right, --guess, &tmp);
|
||||
|
||||
/* Store digit in quotient */
|
||||
BH_Int1120Lsh(q, 16, q);
|
||||
q->digits[0] = guess;
|
||||
if (!q->size)
|
||||
q->size = 1;
|
||||
|
||||
/* Adjust remainder */
|
||||
BH_Int1120Sub(r, &tmp, r);
|
||||
|
||||
/* Fetch next digit or exit */
|
||||
if (!left.size)
|
||||
break;
|
||||
|
||||
BH_Int1120Lsh(r, 16, r);
|
||||
r->digits[0] = left.digits[--left.size];
|
||||
if (!r->size)
|
||||
r->size = 1;
|
||||
}
|
||||
|
||||
/* Normilize remainder */
|
||||
BH_Int1120Rsh(r, shift, r);
|
||||
}
|
||||
|
||||
|
||||
void BH_Int1120Pow10(int exponent,
|
||||
BH_Int1120 *out)
|
||||
{
|
||||
BH_Int1120 one;
|
||||
|
||||
one.digits[0] = 1;
|
||||
one.size = 1;
|
||||
BH_Int1120MulPow10(&one, exponent, out);
|
||||
}
|
||||
|
||||
|
||||
void BH_Int1120MulPow10(const BH_Int1120 *in,
|
||||
int exponent,
|
||||
BH_Int1120 *out)
|
||||
{
|
||||
BH_Int1120 *current, *next, *swap;
|
||||
BH_Int1120 tmp[2], factor;
|
||||
int index;
|
||||
|
||||
/* Make sure exponent is low, otherwise we get an overflow */
|
||||
assert(exponent < 512);
|
||||
|
||||
/* Prepare variables and temporaries */
|
||||
current = tmp;
|
||||
next = tmp + 1;
|
||||
index = 0;
|
||||
*current = *in;
|
||||
|
||||
/* Main multiply loop */
|
||||
while (exponent)
|
||||
{
|
||||
if (exponent & 0x1)
|
||||
{
|
||||
pow10Set(index, &factor);
|
||||
BH_Int1120Mul(current, &factor, next);
|
||||
swap = current;
|
||||
current = next;
|
||||
next = swap;
|
||||
}
|
||||
index++;
|
||||
exponent >>= 1;
|
||||
}
|
||||
*out = *current;
|
||||
}
|
||||
|
||||
|
||||
void BH_Int1120Pow2(int exponent,
|
||||
BH_Int1120 *out)
|
||||
{
|
||||
int blocks, bits, i;
|
||||
|
||||
assert(exponent < 1120);
|
||||
blocks = exponent / 16;
|
||||
bits = exponent % 16;
|
||||
|
||||
/* Zero out blocks and set one bit */
|
||||
for (i = 0; i < blocks; i++)
|
||||
out->digits[i] = 0;
|
||||
|
||||
out->digits[blocks] = (1 << bits);
|
||||
out->size = blocks;
|
||||
}
|
||||
|
||||
|
||||
void BH_Int1120Lsh(const BH_Int1120 *in,
|
||||
int amount,
|
||||
BH_Int1120 *out)
|
||||
{
|
||||
int blocks, bits, i;
|
||||
uint16_t low, high;
|
||||
|
||||
/* No input - no output */
|
||||
if (in->size == 0)
|
||||
return;
|
||||
|
||||
blocks = amount / 16;
|
||||
bits = amount % 16;
|
||||
|
||||
assert(in->size + blocks + (bits > 0) <= BH_INT1120_DIGITS);
|
||||
|
||||
if (bits)
|
||||
{
|
||||
/* Shift and copy parts of two blocks */
|
||||
low = 0;
|
||||
high = in->digits[in->size - 1] >> (16 - bits);
|
||||
for (i = in->size; i > 1; i--)
|
||||
{
|
||||
out->digits[i + blocks] = high | low;
|
||||
low = in->digits[i - 1] << bits;
|
||||
high = in->digits[i - 2] >> (16 - bits);
|
||||
}
|
||||
out->digits[blocks + 1] = high | low;
|
||||
out->digits[blocks] = in->digits[0] << bits;
|
||||
out->size = in->size + blocks + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Copy whole blocks */
|
||||
for (i = in->size; i; i--)
|
||||
out->digits[i - 1 + blocks] = in->digits[i - 1];
|
||||
out->size = in->size + blocks;
|
||||
}
|
||||
|
||||
/* Check upper block */
|
||||
if (!out->digits[out->size - 1])
|
||||
out->size--;
|
||||
|
||||
/* Zero out lower blocks */
|
||||
for (i = blocks; i; i--)
|
||||
out->digits[i - 1] = 0;
|
||||
}
|
||||
|
||||
|
||||
void BH_Int1120Rsh(const BH_Int1120 *in,
|
||||
int amount,
|
||||
BH_Int1120 *out)
|
||||
{
|
||||
int blocks, bits, i;
|
||||
uint16_t low, high;
|
||||
|
||||
/* No input - no output */
|
||||
if (in->size == 0)
|
||||
return;
|
||||
|
||||
blocks = amount / 16;
|
||||
bits = amount % 16;
|
||||
|
||||
if (bits)
|
||||
{
|
||||
/* Shift and copy parts of two blocks */
|
||||
low = in->digits[blocks] >> bits;
|
||||
high = in->digits[blocks + 1] << (16 - bits);
|
||||
|
||||
for (i = 0; i < in->size - blocks - 2; i++)
|
||||
{
|
||||
out->digits[i] = low | high;
|
||||
low = in->digits[i + blocks + 1] >> bits;
|
||||
high = in->digits[i + blocks + 2] << (16 - bits);
|
||||
}
|
||||
|
||||
out->digits[in->size - blocks - 2] = low | high;
|
||||
out->digits[in->size - blocks - 1] = in->digits[in->size - 1] >> bits;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Copy whole blocks */
|
||||
for (i = 0; i < in->size - blocks; i++)
|
||||
out->digits[i] = in->digits[i + blocks];
|
||||
}
|
||||
|
||||
/* Check upper block */
|
||||
out->size = in->size - blocks;
|
||||
if (!out->digits[out->size - 1])
|
||||
out->size--;
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
#ifndef BH_STRING_STRING_H
|
||||
#define BH_STRING_STRING_H
|
||||
|
||||
|
||||
#include <BH/String.h>
|
||||
|
||||
|
||||
#define BH_INT1120_DIGITS 70
|
||||
|
||||
|
||||
typedef struct BH_Int1120
|
||||
{
|
||||
int size;
|
||||
uint16_t digits[BH_INT1120_DIGITS];
|
||||
} BH_Int1120;
|
||||
|
||||
|
||||
/**
|
||||
* Counts the number of leading zero bits.
|
||||
*
|
||||
* \param value Value
|
||||
*
|
||||
* \return Count of leading zeros.
|
||||
*/
|
||||
int BH_Int1120Clz(const uint16_t value);
|
||||
|
||||
|
||||
/**
|
||||
* Compares big integers \a a and \a b.
|
||||
*
|
||||
* \param a A integer
|
||||
* \param b B integer
|
||||
*
|
||||
* \return Negative if \a a is less than \a b
|
||||
* \return Positive if \a a is greater than \a b
|
||||
* \return Zero if \a a and \a b are equal.
|
||||
*/
|
||||
int BH_Int1120Compare(const BH_Int1120 *a,
|
||||
const BH_Int1120 *b);
|
||||
|
||||
|
||||
/**
|
||||
* Adds two big integers \a a and \a b and stores result into \a out.
|
||||
*
|
||||
* \param a A integer
|
||||
* \param b B integer
|
||||
* \param out Result integer
|
||||
*/
|
||||
void BH_Int1120Add(const BH_Int1120 *a,
|
||||
const BH_Int1120 *b,
|
||||
BH_Int1120 *out);
|
||||
|
||||
|
||||
/**
|
||||
* Subtracts two big integers \a a and \a b and stores result into \a out.
|
||||
*
|
||||
* \param a A integer
|
||||
* \param b B integer
|
||||
* \param out Result integer
|
||||
*/
|
||||
void BH_Int1120Sub(const BH_Int1120 *a,
|
||||
const BH_Int1120 *b,
|
||||
BH_Int1120 *out);
|
||||
|
||||
|
||||
/**
|
||||
* Multiplies two big integers \a a and \a b and stores result into \a out.
|
||||
*
|
||||
* \param a A integer
|
||||
* \param b B integer
|
||||
* \param out Result integer
|
||||
*/
|
||||
void BH_Int1120Mul(const BH_Int1120 *a,
|
||||
const BH_Int1120 *b,
|
||||
BH_Int1120 *out);
|
||||
|
||||
|
||||
/**
|
||||
* Multiplies big integer \a a by \a digit and stores result into \a out.
|
||||
*
|
||||
* \param in Input integer
|
||||
* \param digit Digit
|
||||
* \param out Result integer
|
||||
*/
|
||||
void BH_Int1120MulDigit(const BH_Int1120 *in,
|
||||
uint16_t digit,
|
||||
BH_Int1120 *out);
|
||||
|
||||
|
||||
/**
|
||||
* Divides two big integers \a a and \a b and stores quotient into \a q and
|
||||
* remainder into \a r.
|
||||
*
|
||||
* \param a A integer
|
||||
* \param b B integer
|
||||
* \param q Output quotient integer
|
||||
* \param r Output remainder integer
|
||||
*/
|
||||
void BH_Int1120Div(const BH_Int1120 *a,
|
||||
const BH_Int1120 *b,
|
||||
BH_Int1120 *q,
|
||||
BH_Int1120 *r);
|
||||
|
||||
|
||||
/**
|
||||
* Computes 10 to the power of \a exponent.
|
||||
*
|
||||
* \param exponent Exponent
|
||||
* \param out Result integer
|
||||
*/
|
||||
void BH_Int1120Pow10(int exponent,
|
||||
BH_Int1120 *out);
|
||||
|
||||
|
||||
/**
|
||||
* Multiplies a big integer \a in by 10 to the power of \a exponent.
|
||||
*
|
||||
* \param in Input integer
|
||||
* \param exponent Exponent
|
||||
* \param out Result integer
|
||||
*/
|
||||
void BH_Int1120MulPow10(const BH_Int1120 *in,
|
||||
int exponent,
|
||||
BH_Int1120 *out);
|
||||
|
||||
|
||||
/**
|
||||
* Computes 2 to the power of \a exponent.
|
||||
*
|
||||
* \param exponent Exponent
|
||||
* \param out Result integer
|
||||
*/
|
||||
void BH_Int1120Pow2(int exponent,
|
||||
BH_Int1120 *out);
|
||||
|
||||
|
||||
/**
|
||||
* Left shifts big integer \a in by \a amount places and stores result into
|
||||
* \a out.
|
||||
*
|
||||
* \param in Input integer
|
||||
* \param amount Shift amount
|
||||
* \param out Result integer
|
||||
*/
|
||||
void BH_Int1120Lsh(const BH_Int1120 *in,
|
||||
int amount,
|
||||
BH_Int1120 *out);
|
||||
|
||||
|
||||
/**
|
||||
* Right shifts big integer \a in by \a amount places and stores result into
|
||||
* \a out.
|
||||
*
|
||||
* \param in Input integer
|
||||
* \param amount Shift amount
|
||||
* \param out Result integer
|
||||
*/
|
||||
void BH_Int1120Rsh(const BH_Int1120 *in,
|
||||
int amount,
|
||||
BH_Int1120 *out);
|
||||
|
||||
|
||||
#endif /* BH_STRING_STRING_H */
|
||||
Reference in New Issue
Block a user