bignum module wrapper for kokke/tiny-bignum-c
parent
7a29d959ce
commit
a44ba0b8a2
|
@ -0,0 +1,2 @@
|
|||
This folder contains bn.h and bn.c files
|
||||
from https://github.com/kokke/tiny-bignum-c
|
|
@ -0,0 +1,664 @@
|
|||
/*
|
||||
|
||||
Big number library - arithmetic on multiple-precision unsigned integers.
|
||||
|
||||
This library is an implementation of arithmetic on arbitrarily large integers.
|
||||
|
||||
The difference between this and other implementations, is that the data structure
|
||||
has optimal memory utilization (i.e. a 1024 bit integer takes up 128 bytes RAM),
|
||||
and all memory is allocated statically: no dynamic allocation for better or worse.
|
||||
|
||||
Primary goals are correctness, clarity of code and clean, portable implementation.
|
||||
Secondary goal is a memory footprint small enough to make it suitable for use in
|
||||
embedded applications.
|
||||
|
||||
|
||||
The current state is correct functionality and adequate performance.
|
||||
There may well be room for performance-optimizations and improvements.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include "bn.h"
|
||||
|
||||
|
||||
|
||||
/* Functions for shifting number in-place. */
|
||||
static void _lshift_one_bit(struct bn* a);
|
||||
static void _rshift_one_bit(struct bn* a);
|
||||
static void _lshift_word(struct bn* a, int nwords);
|
||||
static void _rshift_word(struct bn* a, int nwords);
|
||||
|
||||
|
||||
|
||||
/* Public / Exported functions. */
|
||||
void bignum_init(struct bn* n)
|
||||
{
|
||||
require(n, "n is null");
|
||||
|
||||
int i;
|
||||
for (i = 0; i < BN_ARRAY_SIZE; ++i)
|
||||
{
|
||||
n->array[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bignum_from_int(struct bn* n, DTYPE_TMP i)
|
||||
{
|
||||
require(n, "n is null");
|
||||
|
||||
bignum_init(n);
|
||||
|
||||
/* Endianness issue if machine is not little-endian? */
|
||||
#ifdef WORD_SIZE
|
||||
#if (WORD_SIZE == 1)
|
||||
n->array[0] = (i & 0x000000ff);
|
||||
n->array[1] = (i & 0x0000ff00) >> 8;
|
||||
n->array[2] = (i & 0x00ff0000) >> 16;
|
||||
n->array[3] = (i & 0xff000000) >> 24;
|
||||
#elif (WORD_SIZE == 2)
|
||||
n->array[0] = (i & 0x0000ffff);
|
||||
n->array[1] = (i & 0xffff0000) >> 16;
|
||||
#elif (WORD_SIZE == 4)
|
||||
n->array[0] = i;
|
||||
DTYPE_TMP num_32 = 32;
|
||||
DTYPE_TMP tmp = i >> num_32; /* bit-shift with U64 operands to force 64-bit results */
|
||||
n->array[1] = tmp;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int bignum_to_int(struct bn* n)
|
||||
{
|
||||
require(n, "n is null");
|
||||
|
||||
int ret = 0;
|
||||
|
||||
/* Endianness issue if machine is not little-endian? */
|
||||
#if (WORD_SIZE == 1)
|
||||
ret += n->array[0];
|
||||
ret += n->array[1] << 8;
|
||||
ret += n->array[2] << 16;
|
||||
ret += n->array[3] << 24;
|
||||
#elif (WORD_SIZE == 2)
|
||||
ret += n->array[0];
|
||||
ret += n->array[1] << 16;
|
||||
#elif (WORD_SIZE == 4)
|
||||
ret += n->array[0];
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void bignum_from_string(struct bn* n, char* str, int nbytes)
|
||||
{
|
||||
require(n, "n is null");
|
||||
require(str, "str is null");
|
||||
require(nbytes > 0, "nbytes must be positive");
|
||||
require((nbytes & 1) == 0, "string format must be in hex -> equal number of bytes");
|
||||
|
||||
bignum_init(n);
|
||||
|
||||
DTYPE tmp; /* DTYPE is defined in bn.h - uint{8,16,32,64}_t */
|
||||
int i = nbytes - (2 * WORD_SIZE); /* index into string */
|
||||
int j = 0; /* index into array */
|
||||
|
||||
/* reading last hex-byte "MSB" from string first -> big endian */
|
||||
/* MSB ~= most significant byte / block ? :) */
|
||||
while (i >= 0)
|
||||
{
|
||||
tmp = 0;
|
||||
sscanf(&str[i], SSCANF_FORMAT_STR, &tmp);
|
||||
n->array[j] = tmp;
|
||||
i -= (2 * WORD_SIZE); /* step WORD_SIZE hex-byte(s) back in the string. */
|
||||
j += 1; /* step one element forward in the array. */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bignum_to_string(struct bn* n, char* str, int nbytes)
|
||||
{
|
||||
require(n, "n is null");
|
||||
require(str, "str is null");
|
||||
require(nbytes > 0, "nbytes must be positive");
|
||||
require((nbytes & 1) == 0, "string format must be in hex -> equal number of bytes");
|
||||
|
||||
int j = BN_ARRAY_SIZE - 1; /* index into array - reading "MSB" first -> big-endian */
|
||||
int i = 0; /* index into string representation. */
|
||||
|
||||
/* reading last array-element "MSB" first -> big endian */
|
||||
while ((j >= 0) && (nbytes > (i + 1)))
|
||||
{
|
||||
sprintf(&str[i], SPRINTF_FORMAT_STR, n->array[j]);
|
||||
i += (2 * WORD_SIZE); /* step WORD_SIZE hex-byte(s) forward in the string. */
|
||||
j -= 1; /* step one element back in the array. */
|
||||
}
|
||||
|
||||
/* Count leading zeros: */
|
||||
j = 0;
|
||||
while (str[j] == '0')
|
||||
{
|
||||
j += 1;
|
||||
}
|
||||
|
||||
/* Move string j places ahead, effectively skipping leading zeros */
|
||||
for (i = 0; i < (nbytes - j); ++i)
|
||||
{
|
||||
str[i] = str[i + j];
|
||||
}
|
||||
|
||||
/* Zero-terminate string */
|
||||
str[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
void bignum_dec(struct bn* n)
|
||||
{
|
||||
require(n, "n is null");
|
||||
|
||||
DTYPE tmp; /* copy of n */
|
||||
DTYPE res;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < BN_ARRAY_SIZE; ++i)
|
||||
{
|
||||
tmp = n->array[i];
|
||||
res = tmp - 1;
|
||||
n->array[i] = res;
|
||||
|
||||
if (!(res > tmp))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bignum_inc(struct bn* n)
|
||||
{
|
||||
require(n, "n is null");
|
||||
|
||||
DTYPE res;
|
||||
DTYPE_TMP tmp; /* copy of n */
|
||||
|
||||
int i;
|
||||
for (i = 0; i < BN_ARRAY_SIZE; ++i)
|
||||
{
|
||||
tmp = n->array[i];
|
||||
res = tmp + 1;
|
||||
n->array[i] = res;
|
||||
|
||||
if (res > tmp)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bignum_add(struct bn* a, struct bn* b, struct bn* c)
|
||||
{
|
||||
require(a, "a is null");
|
||||
require(b, "b is null");
|
||||
require(c, "c is null");
|
||||
|
||||
DTYPE_TMP tmp;
|
||||
int carry = 0;
|
||||
int i;
|
||||
for (i = 0; i < BN_ARRAY_SIZE; ++i)
|
||||
{
|
||||
tmp = (DTYPE_TMP)a->array[i] + b->array[i] + carry;
|
||||
carry = (tmp > MAX_VAL);
|
||||
c->array[i] = (tmp & MAX_VAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bignum_sub(struct bn* a, struct bn* b, struct bn* c)
|
||||
{
|
||||
require(a, "a is null");
|
||||
require(b, "b is null");
|
||||
require(c, "c is null");
|
||||
|
||||
DTYPE_TMP res;
|
||||
DTYPE_TMP tmp1;
|
||||
DTYPE_TMP tmp2;
|
||||
int borrow = 0;
|
||||
int i;
|
||||
for (i = 0; i < BN_ARRAY_SIZE; ++i)
|
||||
{
|
||||
tmp1 = (DTYPE_TMP)a->array[i] + (MAX_VAL + 1); /* + number_base */
|
||||
tmp2 = (DTYPE_TMP)b->array[i] + borrow;;
|
||||
res = (tmp1 - tmp2);
|
||||
c->array[i] = (DTYPE)(res & MAX_VAL); /* "modulo number_base" == "% (number_base - 1)" if number_base is 2^N */
|
||||
borrow = (res <= MAX_VAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bignum_mul(struct bn* a, struct bn* b, struct bn* c)
|
||||
{
|
||||
require(a, "a is null");
|
||||
require(b, "b is null");
|
||||
require(c, "c is null");
|
||||
|
||||
struct bn row;
|
||||
struct bn tmp;
|
||||
int i, j;
|
||||
|
||||
bignum_init(c);
|
||||
|
||||
for (i = 0; i < BN_ARRAY_SIZE; ++i)
|
||||
{
|
||||
bignum_init(&row);
|
||||
|
||||
for (j = 0; j < BN_ARRAY_SIZE; ++j)
|
||||
{
|
||||
if (i + j < BN_ARRAY_SIZE)
|
||||
{
|
||||
bignum_init(&tmp);
|
||||
DTYPE_TMP intermediate = ((DTYPE_TMP)a->array[i] * (DTYPE_TMP)b->array[j]);
|
||||
bignum_from_int(&tmp, intermediate);
|
||||
_lshift_word(&tmp, i + j);
|
||||
bignum_add(&tmp, &row, &row);
|
||||
}
|
||||
}
|
||||
bignum_add(c, &row, c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bignum_div(struct bn* a, struct bn* b, struct bn* c)
|
||||
{
|
||||
require(a, "a is null");
|
||||
require(b, "b is null");
|
||||
require(c, "c is null");
|
||||
|
||||
struct bn current;
|
||||
struct bn denom;
|
||||
struct bn tmp;
|
||||
|
||||
bignum_from_int(¤t, 1); // int current = 1;
|
||||
bignum_assign(&denom, b); // denom = b
|
||||
bignum_assign(&tmp, a); // tmp = a
|
||||
|
||||
const DTYPE_TMP half_max = 1 + (DTYPE_TMP)(MAX_VAL / 2);
|
||||
bool overflow = false;
|
||||
while (bignum_cmp(&denom, a) != LARGER) // while (denom <= a) {
|
||||
{
|
||||
if (denom.array[BN_ARRAY_SIZE - 1] >= half_max)
|
||||
{
|
||||
overflow = true;
|
||||
break;
|
||||
}
|
||||
_lshift_one_bit(¤t); // current <<= 1;
|
||||
_lshift_one_bit(&denom); // denom <<= 1;
|
||||
}
|
||||
if (!overflow)
|
||||
{
|
||||
_rshift_one_bit(&denom); // denom >>= 1;
|
||||
_rshift_one_bit(¤t); // current >>= 1;
|
||||
}
|
||||
bignum_init(c); // int answer = 0;
|
||||
|
||||
while (!bignum_is_zero(¤t)) // while (current != 0)
|
||||
{
|
||||
if (bignum_cmp(&tmp, &denom) != SMALLER) // if (dividend >= denom)
|
||||
{
|
||||
bignum_sub(&tmp, &denom, &tmp); // dividend -= denom;
|
||||
bignum_or(c, ¤t, c); // answer |= current;
|
||||
}
|
||||
_rshift_one_bit(¤t); // current >>= 1;
|
||||
_rshift_one_bit(&denom); // denom >>= 1;
|
||||
} // return answer;
|
||||
}
|
||||
|
||||
|
||||
void bignum_lshift(struct bn* a, struct bn* b, int nbits)
|
||||
{
|
||||
require(a, "a is null");
|
||||
require(b, "b is null");
|
||||
require(nbits >= 0, "no negative shifts");
|
||||
|
||||
bignum_assign(b, a);
|
||||
/* Handle shift in multiples of word-size */
|
||||
const int nbits_pr_word = (WORD_SIZE * 8);
|
||||
int nwords = nbits / nbits_pr_word;
|
||||
if (nwords != 0)
|
||||
{
|
||||
_lshift_word(b, nwords);
|
||||
nbits -= (nwords * nbits_pr_word);
|
||||
}
|
||||
|
||||
if (nbits != 0)
|
||||
{
|
||||
int i;
|
||||
for (i = (BN_ARRAY_SIZE - 1); i > 0; --i)
|
||||
{
|
||||
b->array[i] = (b->array[i] << nbits) | (b->array[i - 1] >> ((8 * WORD_SIZE) - nbits));
|
||||
}
|
||||
b->array[i] <<= nbits;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bignum_rshift(struct bn* a, struct bn* b, int nbits)
|
||||
{
|
||||
require(a, "a is null");
|
||||
require(b, "b is null");
|
||||
require(nbits >= 0, "no negative shifts");
|
||||
|
||||
bignum_assign(b, a);
|
||||
/* Handle shift in multiples of word-size */
|
||||
const int nbits_pr_word = (WORD_SIZE * 8);
|
||||
int nwords = nbits / nbits_pr_word;
|
||||
if (nwords != 0)
|
||||
{
|
||||
_rshift_word(b, nwords);
|
||||
nbits -= (nwords * nbits_pr_word);
|
||||
}
|
||||
|
||||
if (nbits != 0)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < (BN_ARRAY_SIZE - 1); ++i)
|
||||
{
|
||||
b->array[i] = (b->array[i] >> nbits) | (b->array[i + 1] << ((8 * WORD_SIZE) - nbits));
|
||||
}
|
||||
b->array[i] >>= nbits;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void bignum_mod(struct bn* a, struct bn* b, struct bn* c)
|
||||
{
|
||||
/*
|
||||
Take divmod and throw away div part
|
||||
*/
|
||||
require(a, "a is null");
|
||||
require(b, "b is null");
|
||||
require(c, "c is null");
|
||||
|
||||
struct bn tmp;
|
||||
|
||||
bignum_divmod(a,b,&tmp,c);
|
||||
}
|
||||
|
||||
void bignum_divmod(struct bn* a, struct bn* b, struct bn* c, struct bn* d)
|
||||
{
|
||||
/*
|
||||
Puts a%b in d
|
||||
and a/b in c
|
||||
|
||||
mod(a,b) = a - ((a / b) * b)
|
||||
|
||||
example:
|
||||
mod(8, 3) = 8 - ((8 / 3) * 3) = 2
|
||||
*/
|
||||
require(a, "a is null");
|
||||
require(b, "b is null");
|
||||
require(c, "c is null");
|
||||
|
||||
struct bn tmp;
|
||||
|
||||
/* c = (a / b) */
|
||||
bignum_div(a, b, c);
|
||||
|
||||
/* tmp = (c * b) */
|
||||
bignum_mul(c, b, &tmp);
|
||||
|
||||
/* c = a - tmp */
|
||||
bignum_sub(a, &tmp, d);
|
||||
}
|
||||
|
||||
|
||||
void bignum_and(struct bn* a, struct bn* b, struct bn* c)
|
||||
{
|
||||
require(a, "a is null");
|
||||
require(b, "b is null");
|
||||
require(c, "c is null");
|
||||
|
||||
int i;
|
||||
for (i = 0; i < BN_ARRAY_SIZE; ++i)
|
||||
{
|
||||
c->array[i] = (a->array[i] & b->array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bignum_or(struct bn* a, struct bn* b, struct bn* c)
|
||||
{
|
||||
require(a, "a is null");
|
||||
require(b, "b is null");
|
||||
require(c, "c is null");
|
||||
|
||||
int i;
|
||||
for (i = 0; i < BN_ARRAY_SIZE; ++i)
|
||||
{
|
||||
c->array[i] = (a->array[i] | b->array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bignum_xor(struct bn* a, struct bn* b, struct bn* c)
|
||||
{
|
||||
require(a, "a is null");
|
||||
require(b, "b is null");
|
||||
require(c, "c is null");
|
||||
|
||||
int i;
|
||||
for (i = 0; i < BN_ARRAY_SIZE; ++i)
|
||||
{
|
||||
c->array[i] = (a->array[i] ^ b->array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int bignum_cmp(struct bn* a, struct bn* b)
|
||||
{
|
||||
require(a, "a is null");
|
||||
require(b, "b is null");
|
||||
|
||||
int i = BN_ARRAY_SIZE;
|
||||
do
|
||||
{
|
||||
i -= 1; /* Decrement first, to start with last array element */
|
||||
if (a->array[i] > b->array[i])
|
||||
{
|
||||
return LARGER;
|
||||
}
|
||||
else if (a->array[i] < b->array[i])
|
||||
{
|
||||
return SMALLER;
|
||||
}
|
||||
}
|
||||
while (i != 0);
|
||||
|
||||
return EQUAL;
|
||||
}
|
||||
|
||||
|
||||
int bignum_is_zero(struct bn* n)
|
||||
{
|
||||
require(n, "n is null");
|
||||
|
||||
int i;
|
||||
for (i = 0; i < BN_ARRAY_SIZE; ++i)
|
||||
{
|
||||
if (n->array[i])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void bignum_pow(struct bn* a, struct bn* b, struct bn* c)
|
||||
{
|
||||
require(a, "a is null");
|
||||
require(b, "b is null");
|
||||
require(c, "c is null");
|
||||
|
||||
struct bn tmp;
|
||||
|
||||
bignum_init(c);
|
||||
|
||||
if (bignum_cmp(b, c) == EQUAL)
|
||||
{
|
||||
/* Return 1 when exponent is 0 -- n^0 = 1 */
|
||||
bignum_inc(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct bn bcopy;
|
||||
bignum_assign(&bcopy, b);
|
||||
|
||||
/* Copy a -> tmp */
|
||||
bignum_assign(&tmp, a);
|
||||
|
||||
bignum_dec(&bcopy);
|
||||
|
||||
/* Begin summing products: */
|
||||
while (!bignum_is_zero(&bcopy))
|
||||
{
|
||||
|
||||
/* c = tmp * tmp */
|
||||
bignum_mul(&tmp, a, c);
|
||||
/* Decrement b by one */
|
||||
bignum_dec(&bcopy);
|
||||
|
||||
bignum_assign(&tmp, c);
|
||||
}
|
||||
|
||||
/* c = tmp */
|
||||
bignum_assign(c, &tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void bignum_isqrt(struct bn *a, struct bn* b)
|
||||
{
|
||||
require(a, "a is null");
|
||||
require(b, "b is null");
|
||||
|
||||
struct bn low, high, mid, tmp;
|
||||
|
||||
bignum_init(&low);
|
||||
bignum_assign(&high, a);
|
||||
bignum_rshift(&high, &mid, 1);
|
||||
bignum_inc(&mid);
|
||||
|
||||
while (bignum_cmp(&high, &low) > 0)
|
||||
{
|
||||
bignum_mul(&mid, &mid, &tmp);
|
||||
if (bignum_cmp(&tmp, a) > 0)
|
||||
{
|
||||
bignum_assign(&high, &mid);
|
||||
bignum_dec(&high);
|
||||
}
|
||||
else
|
||||
{
|
||||
bignum_assign(&low, &mid);
|
||||
}
|
||||
bignum_sub(&high,&low,&mid);
|
||||
_rshift_one_bit(&mid);
|
||||
bignum_add(&low,&mid,&mid);
|
||||
bignum_inc(&mid);
|
||||
}
|
||||
bignum_assign(b,&low);
|
||||
}
|
||||
|
||||
|
||||
void bignum_assign(struct bn* dst, struct bn* src)
|
||||
{
|
||||
require(dst, "dst is null");
|
||||
require(src, "src is null");
|
||||
|
||||
int i;
|
||||
for (i = 0; i < BN_ARRAY_SIZE; ++i)
|
||||
{
|
||||
dst->array[i] = src->array[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Private / Static functions. */
|
||||
static void _rshift_word(struct bn* a, int nwords)
|
||||
{
|
||||
/* Naive method: */
|
||||
require(a, "a is null");
|
||||
require(nwords >= 0, "no negative shifts");
|
||||
|
||||
int i;
|
||||
if (nwords >= BN_ARRAY_SIZE)
|
||||
{
|
||||
for (i = 0; i < BN_ARRAY_SIZE; ++i)
|
||||
{
|
||||
a->array[i] = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < BN_ARRAY_SIZE - nwords; ++i)
|
||||
{
|
||||
a->array[i] = a->array[i + nwords];
|
||||
}
|
||||
for (; i < BN_ARRAY_SIZE; ++i)
|
||||
{
|
||||
a->array[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void _lshift_word(struct bn* a, int nwords)
|
||||
{
|
||||
require(a, "a is null");
|
||||
require(nwords >= 0, "no negative shifts");
|
||||
|
||||
int i;
|
||||
/* Shift whole words */
|
||||
for (i = (BN_ARRAY_SIZE - 1); i >= nwords; --i)
|
||||
{
|
||||
a->array[i] = a->array[i - nwords];
|
||||
}
|
||||
/* Zero pad shifted words. */
|
||||
for (; i >= 0; --i)
|
||||
{
|
||||
a->array[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void _lshift_one_bit(struct bn* a)
|
||||
{
|
||||
require(a, "a is null");
|
||||
|
||||
int i;
|
||||
for (i = (BN_ARRAY_SIZE - 1); i > 0; --i)
|
||||
{
|
||||
a->array[i] = (a->array[i] << 1) | (a->array[i - 1] >> ((8 * WORD_SIZE) - 1));
|
||||
}
|
||||
a->array[0] <<= 1;
|
||||
}
|
||||
|
||||
|
||||
static void _rshift_one_bit(struct bn* a)
|
||||
{
|
||||
require(a, "a is null");
|
||||
|
||||
int i;
|
||||
for (i = 0; i < (BN_ARRAY_SIZE - 1); ++i)
|
||||
{
|
||||
a->array[i] = (a->array[i] >> 1) | (a->array[i + 1] << ((8 * WORD_SIZE) - 1));
|
||||
}
|
||||
a->array[BN_ARRAY_SIZE - 1] >>= 1;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
#ifndef __BIGNUM_H__
|
||||
#define __BIGNUM_H__
|
||||
/*
|
||||
|
||||
Big number library - arithmetic on multiple-precision unsigned integers.
|
||||
|
||||
This library is an implementation of arithmetic on arbitrarily large integers.
|
||||
|
||||
The difference between this and other implementations, is that the data structure
|
||||
has optimal memory utilization (i.e. a 1024 bit integer takes up 128 bytes RAM),
|
||||
and all memory is allocated statically: no dynamic allocation for better or worse.
|
||||
|
||||
Primary goals are correctness, clarity of code and clean, portable implementation.
|
||||
Secondary goal is a memory footprint small enough to make it suitable for use in
|
||||
embedded applications.
|
||||
|
||||
|
||||
The current state is correct functionality and adequate performance.
|
||||
There may well be room for performance-optimizations and improvements.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
/* This macro defines the word size in bytes of the array that constitues the big-number data structure. */
|
||||
#ifndef WORD_SIZE
|
||||
#define WORD_SIZE 4
|
||||
#endif
|
||||
|
||||
/* Size of big-numbers in bytes */
|
||||
#define BN_ARRAY_SIZE (128 / WORD_SIZE)
|
||||
|
||||
|
||||
/* Here comes the compile-time specialization for how large the underlying array size should be. */
|
||||
/* The choices are 1, 2 and 4 bytes in size with uint32, uint64 for WORD_SIZE==4, as temporary. */
|
||||
#ifndef WORD_SIZE
|
||||
#error Must define WORD_SIZE to be 1, 2, 4
|
||||
#elif (WORD_SIZE == 1)
|
||||
/* Data type of array in structure */
|
||||
#define DTYPE uint8_t
|
||||
/* bitmask for getting MSB */
|
||||
#define DTYPE_MSB ((DTYPE_TMP)(0x80))
|
||||
/* Data-type larger than DTYPE, for holding intermediate results of calculations */
|
||||
#define DTYPE_TMP uint32_t
|
||||
/* sprintf format string */
|
||||
#define SPRINTF_FORMAT_STR "%.02x"
|
||||
#define SSCANF_FORMAT_STR "%2hhx"
|
||||
/* Max value of integer type */
|
||||
#define MAX_VAL ((DTYPE_TMP)0xFF)
|
||||
#elif (WORD_SIZE == 2)
|
||||
#define DTYPE uint16_t
|
||||
#define DTYPE_TMP uint32_t
|
||||
#define DTYPE_MSB ((DTYPE_TMP)(0x8000))
|
||||
#define SPRINTF_FORMAT_STR "%.04x"
|
||||
#define SSCANF_FORMAT_STR "%4hx"
|
||||
#define MAX_VAL ((DTYPE_TMP)0xFFFF)
|
||||
#elif (WORD_SIZE == 4)
|
||||
#define DTYPE uint32_t
|
||||
#define DTYPE_TMP uint64_t
|
||||
#define DTYPE_MSB ((DTYPE_TMP)(0x80000000))
|
||||
#define SPRINTF_FORMAT_STR "%.08x"
|
||||
#define SSCANF_FORMAT_STR "%8x"
|
||||
#define MAX_VAL ((DTYPE_TMP)0xFFFFFFFF)
|
||||
#endif
|
||||
#ifndef DTYPE
|
||||
#error DTYPE must be defined to uint8_t, uint16_t uint32_t or whatever
|
||||
#endif
|
||||
|
||||
|
||||
/* Custom assert macro - easy to disable */
|
||||
#define require(p, msg) assert(p && #msg)
|
||||
|
||||
|
||||
/* Data-holding structure: array of DTYPEs */
|
||||
struct bn
|
||||
{
|
||||
DTYPE array[BN_ARRAY_SIZE];
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Tokens returned by bignum_cmp() for value comparison */
|
||||
enum { SMALLER = -1, EQUAL = 0, LARGER = 1 };
|
||||
|
||||
|
||||
|
||||
/* Initialization functions: */
|
||||
void bignum_init(struct bn* n);
|
||||
void bignum_from_int(struct bn* n, DTYPE_TMP i);
|
||||
int bignum_to_int(struct bn* n);
|
||||
void bignum_from_string(struct bn* n, char* str, int nbytes);
|
||||
void bignum_to_string(struct bn* n, char* str, int maxsize);
|
||||
|
||||
/* Basic arithmetic operations: */
|
||||
void bignum_add(struct bn* a, struct bn* b, struct bn* c); /* c = a + b */
|
||||
void bignum_sub(struct bn* a, struct bn* b, struct bn* c); /* c = a - b */
|
||||
void bignum_mul(struct bn* a, struct bn* b, struct bn* c); /* c = a * b */
|
||||
void bignum_div(struct bn* a, struct bn* b, struct bn* c); /* c = a / b */
|
||||
void bignum_mod(struct bn* a, struct bn* b, struct bn* c); /* c = a % b */
|
||||
void bignum_divmod(struct bn* a, struct bn* b, struct bn* c, struct bn* d); /* c = a/b, d = a%b */
|
||||
|
||||
/* Bitwise operations: */
|
||||
void bignum_and(struct bn* a, struct bn* b, struct bn* c); /* c = a & b */
|
||||
void bignum_or(struct bn* a, struct bn* b, struct bn* c); /* c = a | b */
|
||||
void bignum_xor(struct bn* a, struct bn* b, struct bn* c); /* c = a ^ b */
|
||||
void bignum_lshift(struct bn* a, struct bn* b, int nbits); /* b = a << nbits */
|
||||
void bignum_rshift(struct bn* a, struct bn* b, int nbits); /* b = a >> nbits */
|
||||
|
||||
/* Special operators and comparison */
|
||||
int bignum_cmp(struct bn* a, struct bn* b); /* Compare: returns LARGER, EQUAL or SMALLER */
|
||||
int bignum_is_zero(struct bn* n); /* For comparison with zero */
|
||||
void bignum_inc(struct bn* n); /* Increment: add one to n */
|
||||
void bignum_dec(struct bn* n); /* Decrement: subtract one from n */
|
||||
void bignum_pow(struct bn* a, struct bn* b, struct bn* c); /* Calculate a^b -- e.g. 2^10 => 1024 */
|
||||
void bignum_isqrt(struct bn* a, struct bn* b); /* Integer square root -- e.g. isqrt(5) => 2*/
|
||||
void bignum_assign(struct bn* dst, struct bn* src); /* Copy src into dst -- dst := src */
|
||||
|
||||
|
||||
#endif /* #ifndef __BIGNUM_H__ */
|
||||
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
module bignum
|
||||
|
||||
// Wrapper for https://github.com/kokke/tiny-bignum-c
|
||||
|
||||
#flag -I @VROOT/thirdparty/bignum
|
||||
#flag @VROOT/thirdparty/bignum/bn.o
|
||||
#include "bn.h"
|
||||
|
||||
const (
|
||||
STRING_BUFFER_SIZE = 8192
|
||||
)
|
||||
|
||||
pub struct Number {
|
||||
array [32]u32
|
||||
}
|
||||
|
||||
fn C.bignum_init( n &Number )
|
||||
fn C.bignum_from_int( n &Number, i u64 )
|
||||
fn C.bignum_to_int( n &Number ) int
|
||||
fn C.bignum_from_string( n &Number, s byteptr, nbytes int)
|
||||
fn C.bignum_to_string( n &Number, s byteptr, maxsize int)
|
||||
|
||||
fn C.bignum_add( a &Number, b &Number, c &Number) // c = a + b
|
||||
fn C.bignum_sub( a &Number, b &Number, c &Number) // c = a - b
|
||||
fn C.bignum_mul( a &Number, b &Number, c &Number) // c = a * b
|
||||
fn C.bignum_div( a &Number, b &Number, c &Number) // c = a / b
|
||||
fn C.bignum_mod( a &Number, b &Number, c &Number) // c = a % b
|
||||
fn C.bignum_divmod( a &Number, b &Number, c &Number, d &Number) // c = a/b d=a%b
|
||||
|
||||
fn C.bignum_and( a &Number, b &Number, c &Number) // c = a & b
|
||||
fn C.bignum_or( a &Number, b &Number, c &Number) // c = a | b
|
||||
fn C.bignum_xor( a &Number, b &Number, c &Number) // c = a xor b
|
||||
fn C.bignum_lshift( a &Number, b &Number, nbits int) // b = a << nbits
|
||||
fn C.bignum_rshift( a &Number, b &Number, nbits int) // b = a >> nbits
|
||||
|
||||
fn C.bignum_cmp( a &Number, b &Number) int
|
||||
fn C.bignum_is_zero( a &Number) int
|
||||
fn C.bignum_inc(n &Number)
|
||||
fn C.bignum_dec(n &Number)
|
||||
fn C.bignum_pow( a &Number, b &Number, c &Number) // c = a ^ b
|
||||
fn C.bignum_isqrt( a &Number, b &Number) // b = integer_square_root_of(a)
|
||||
fn C.bignum_assign( dst &Number, src &Number) // copy src number to dst number
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// conversion actions to/from big numbers:
|
||||
pub fn new_bignum() Number {
|
||||
return Number{}
|
||||
}
|
||||
pub fn from_int(i int) Number {
|
||||
n := Number{}
|
||||
C.bignum_from_int( &n, i)
|
||||
return n
|
||||
}
|
||||
|
||||
pub fn from_u64(u u64) Number {
|
||||
n := Number{}
|
||||
C.bignum_from_int( &n, u)
|
||||
return n
|
||||
}
|
||||
pub fn from_string(s string) Number {
|
||||
n := Number{}
|
||||
C.bignum_from_string(&n, s.str, s.len)
|
||||
return n
|
||||
}
|
||||
|
||||
pub fn (n Number) int() int {
|
||||
r := C.bignum_to_int(&n)
|
||||
return r
|
||||
}
|
||||
|
||||
pub fn (n Number) str() string {
|
||||
// TODO: return a decimal representation of the bignumber n.
|
||||
// A decimal representation will be easier to use in the repl
|
||||
// but will be slower to calculate. Also, it is not implemented
|
||||
// in the bn library.
|
||||
return 'Number (in hex): ' + n.hexstr()
|
||||
}
|
||||
|
||||
pub fn (n Number) hexstr() string {
|
||||
mut buf := [STRING_BUFFER_SIZE]byte
|
||||
C.bignum_to_string( &n, buf, STRING_BUFFER_SIZE)
|
||||
// NB: bignum_to_string , returns the HEXADECIMAL representation of the bignum n
|
||||
s := tos_clone( buf )
|
||||
if s.len == 0 { return '0' }
|
||||
return s
|
||||
}
|
||||
////////////////////////////////////////////////////////////
|
||||
// overloaded ops for the numbers:
|
||||
pub fn (a Number) + (b Number) Number {
|
||||
c := Number{}
|
||||
C.bignum_add(&a, &b, &c)
|
||||
return c
|
||||
}
|
||||
|
||||
pub fn (a Number) - (b Number) Number {
|
||||
c := Number{}
|
||||
C.bignum_sub(&a, &b, &c)
|
||||
return c
|
||||
}
|
||||
|
||||
pub fn (a Number) * (b Number) Number {
|
||||
c := Number{}
|
||||
C.bignum_mul(&a, &b, &c)
|
||||
return c
|
||||
}
|
||||
|
||||
pub fn (a Number) / (b Number) Number {
|
||||
c := Number{}
|
||||
C.bignum_div(&a, &b, &c)
|
||||
return c
|
||||
}
|
||||
|
||||
pub fn (a Number) % (b Number) Number {
|
||||
c := Number{}
|
||||
C.bignum_mod(&a, &b, &c)
|
||||
return c
|
||||
}
|
||||
|
||||
pub fn divmod( a &Number, b &Number, c &Number) Number {
|
||||
d := Number{}
|
||||
C.bignum_divmod( a, b, c, &d)
|
||||
return d
|
||||
}
|
||||
////////////////////////////////////////////////////////////
|
||||
pub fn cmp(a Number, b Number) int {
|
||||
return C.bignum_cmp(&a,&b)
|
||||
}
|
||||
pub fn (a Number) is_zero() bool {
|
||||
return int(C.bignum_is_zero(&a)) != 0
|
||||
}
|
||||
pub fn (a mut Number) inc() {
|
||||
C.bignum_inc(a)
|
||||
}
|
||||
pub fn (a mut Number) dec() {
|
||||
C.bignum_dec(a)
|
||||
}
|
||||
pub fn pow(a Number, b Number) Number {
|
||||
c := Number{}
|
||||
C.bignum_pow(&a,&b,&c)
|
||||
return c
|
||||
}
|
||||
pub fn (a Number) isqrt() Number {
|
||||
b := Number{}
|
||||
C.bignum_isqrt(&a,&b)
|
||||
return b
|
||||
}
|
||||
////////////////////////////////////////////////////////////
|
||||
pub fn b_and(a Number, b Number) Number {
|
||||
c := Number{}
|
||||
C.bignum_and(&a,&b,&c)
|
||||
return c
|
||||
}
|
||||
pub fn b_or(a Number, b Number) Number {
|
||||
c := Number{}
|
||||
C.bignum_or(&a,&b,&c)
|
||||
return c
|
||||
}
|
||||
pub fn b_xor(a Number, b Number) Number {
|
||||
c := Number{}
|
||||
C.bignum_xor(&a,&b,&c)
|
||||
return c
|
||||
}
|
||||
pub fn (a Number) lshift(nbits int) Number {
|
||||
b := Number{}
|
||||
C.bignum_lshift(&a,&b,nbits)
|
||||
return b
|
||||
}
|
||||
pub fn (a Number) rshift(nbits int) Number {
|
||||
b := Number{}
|
||||
C.bignum_rshift(&a,&b,nbits)
|
||||
return b
|
||||
}
|
||||
pub fn (a Number) clone() Number {
|
||||
b := Number{}
|
||||
C.bignum_assign(&b,&a)
|
||||
return b
|
||||
}
|
||||
////////////////////////////////////////////////////////////
|
||||
pub fn factorial(nn bignum.Number) bignum.Number {
|
||||
mut n := nn.clone()
|
||||
mut a := nn.clone()
|
||||
n.dec()
|
||||
mut i:=1
|
||||
for !n.is_zero() {
|
||||
res := a * n
|
||||
n.dec()
|
||||
a = res
|
||||
i++
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
pub fn fact(n int) bignum.Number {
|
||||
return factorial( bignum.from_int(n) )
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
import bignum
|
||||
|
||||
fn test_new_bignum(){
|
||||
n := bignum.new_bignum()
|
||||
assert sizeof( bignum.Number ) == 128
|
||||
assert n.hexstr() == '0'
|
||||
}
|
||||
|
||||
fn test_from_int(){
|
||||
assert bignum.from_int(255).hexstr() == 'ff'
|
||||
assert bignum.from_int(127).hexstr() == '7f'
|
||||
assert bignum.from_int(1024).hexstr() == '400'
|
||||
assert bignum.from_int(2147483647).hexstr() == '7fffffff'
|
||||
assert bignum.from_int(-1).hexstr() == 'ffffffffffffffff'
|
||||
}
|
||||
|
||||
fn test_from_u64(){
|
||||
assert bignum.from_u64(255).hexstr() == 'ff'
|
||||
assert bignum.from_u64(127).hexstr() == '7f'
|
||||
assert bignum.from_u64(1024).hexstr() == '400'
|
||||
assert bignum.from_u64(4294967295).hexstr() == 'ffffffff'
|
||||
assert bignum.from_u64(4398046511104).hexstr() == '40000000000'
|
||||
assert bignum.from_u64(-1).hexstr() == 'ffffffffffffffff'
|
||||
}
|
||||
|
||||
fn test_plus(){
|
||||
a := bignum.from_u64(2)
|
||||
b := bignum.from_u64(3)
|
||||
c := a + b
|
||||
assert c.hexstr() == '5'
|
||||
assert (bignum.from_u64(1024) + bignum.from_u64(1024)).hexstr() == '800'
|
||||
}
|
||||
|
||||
fn test_minus(){
|
||||
a := bignum.from_u64(2)
|
||||
b := bignum.from_u64(3)
|
||||
c := b - a
|
||||
assert c.hexstr() == '1'
|
||||
e := bignum.from_u64(1024)
|
||||
ee := e - e
|
||||
assert ee.hexstr() == '0'
|
||||
}
|
||||
|
||||
fn test_divide(){
|
||||
a := bignum.from_u64(2)
|
||||
b := bignum.from_u64(3)
|
||||
c := b / a
|
||||
assert c.hexstr() == '1'
|
||||
assert (b % a ).hexstr() == '1'
|
||||
e := bignum.from_u64(1024) // dec(1024) == hex(0x400)
|
||||
ee := e / e
|
||||
assert ee.hexstr() == '1'
|
||||
assert (e / a).hexstr() == '200'
|
||||
assert (e / (a*a)).hexstr() == '100'
|
||||
}
|
||||
|
||||
fn test_multiply(){
|
||||
a := bignum.from_u64(2)
|
||||
b := bignum.from_u64(3)
|
||||
c := b * a
|
||||
assert c.hexstr() == '6'
|
||||
e := bignum.from_u64(1024)
|
||||
e2 := e * e
|
||||
e4 := e2 * e2
|
||||
e8 := e2 * e2 * e2 * e2
|
||||
e9 := e8 + bignum.from_u64(1)
|
||||
d := ((e9 * e9) + b) * c
|
||||
assert e4.hexstr() == '10000000000'
|
||||
assert e8.hexstr() == '100000000000000000000'
|
||||
assert e9.hexstr() == '100000000000000000001'
|
||||
assert d.hexstr() == '60000000000000000000c00000000000000000018'
|
||||
}
|
||||
|
||||
fn test_mod(){
|
||||
assert (bignum.from_u64(13) % bignum.from_u64(10) ).int() == 3
|
||||
assert (bignum.from_u64(13) % bignum.from_u64(9) ).int() == 4
|
||||
assert (bignum.from_u64(7) % bignum.from_u64(5) ).int() == 2
|
||||
}
|
||||
|
||||
|
||||
fn test_factorial(){
|
||||
f5 := bignum.factorial( bignum.from_u64(5) )
|
||||
assert f5.hexstr() == '78'
|
||||
f100 := bignum.factorial( bignum.from_u64(100) )
|
||||
assert f100.hexstr() == '1b30964ec395dc24069528d54bbda40d16e966ef9a70eb21b5b2943a321cdf10391745570cca9420c6ecb3b72ed2ee8b02ea2735c61a000000000000000000000000'
|
||||
}
|
|
@ -448,34 +448,29 @@ fn (p mut Parser) expression() string {
|
|||
// Make sure operators are used with correct types
|
||||
if !p.pref.translated && !is_str && !is_ustr && !is_num {
|
||||
T := p.table.find_type(typ)
|
||||
if tok_op == .plus {
|
||||
if T.has_method('+') {
|
||||
p.cgen.set_placeholder(ph, typ + '_plus(')
|
||||
p.gen(')')
|
||||
}
|
||||
else {
|
||||
p.error('operator + not defined on `$typ`')
|
||||
}
|
||||
}
|
||||
else if tok_op == .minus {
|
||||
if T.has_method('-') {
|
||||
p.cgen.set_placeholder(ph, '${typ}_minus(')
|
||||
p.gen(')')
|
||||
}
|
||||
else {
|
||||
p.error('operator - not defined on `$typ`')
|
||||
}
|
||||
}
|
||||
if tok_op == .plus { p.handle_operator('+', typ, 'op_plus', ph, T) }
|
||||
else if tok_op == .minus { p.handle_operator('-', typ, 'op_minus', ph, T) }
|
||||
}
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
fn (p mut Parser) handle_operator(op string, typ string, cpostfix string, ph int, T &Type) {
|
||||
if T.has_method( op ) {
|
||||
p.cgen.set_placeholder(ph, '${typ}_${cpostfix}(')
|
||||
p.gen(')')
|
||||
}
|
||||
else {
|
||||
p.error('operator $op not defined on `$typ`')
|
||||
}
|
||||
}
|
||||
|
||||
fn (p mut Parser) term() string {
|
||||
line_nr := p.scanner.line_nr
|
||||
//if p.fileis('fn_test') {
|
||||
//println('\nterm() $line_nr')
|
||||
//}
|
||||
ph := p.cgen.add_placeholder()
|
||||
typ := p.unary()
|
||||
//if p.fileis('fn_test') {
|
||||
//println('2: $line_nr')
|
||||
|
@ -491,11 +486,28 @@ fn (p mut Parser) term() string {
|
|||
// is_mul := tok == .mod
|
||||
p.next()
|
||||
p.gen(tok.str())// + ' /*op2*/ ')
|
||||
oph := p.cgen.add_placeholder()
|
||||
p.fgen(' ' + tok.str() + ' ')
|
||||
if (is_div || is_mod) && p.tok == .number && p.lit == '0' {
|
||||
p.error('division or modulo by zero')
|
||||
}
|
||||
expr_type := p.unary()
|
||||
|
||||
if !is_primitive_type(expr_type) && expr_type == typ {
|
||||
p.check_types(expr_type, typ)
|
||||
T := p.table.find_type(typ)
|
||||
// NB: oph is a char index just after the OP
|
||||
before_oph := p.cgen.cur_line[..oph-1]
|
||||
after_oph := p.cgen.cur_line[oph..]
|
||||
p.cgen.cur_line = before_oph + ',' + after_oph
|
||||
match tok {
|
||||
.mul { p.handle_operator('*', typ, 'op_mul', ph, T) }
|
||||
.div { p.handle_operator('/', typ, 'op_div', ph, T) }
|
||||
.mod { p.handle_operator('%', typ, 'op_mod', ph, T) }
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if is_mod {
|
||||
if !(is_integer_type(expr_type) && is_integer_type(typ)) {
|
||||
p.error('operator `mod` requires integer types')
|
||||
|
|
|
@ -265,7 +265,7 @@ fn (p mut Parser) fn_decl() {
|
|||
p.register_var(receiver)
|
||||
}
|
||||
// +-/* methods
|
||||
if p.tok in [.plus, .minus, .mul] {
|
||||
if p.tok in [.plus, .minus, .mul, .div, .mod] {
|
||||
f.name = p.tok.str()
|
||||
p.next()
|
||||
}
|
||||
|
|
|
@ -228,9 +228,15 @@ fn (table mut Table) fn_gen_name(f &Fn) string {
|
|||
if f.is_method {
|
||||
name = '${f.receiver_typ}_$f.name'
|
||||
name = name.replace(' ', '')
|
||||
name = name.replace('*', '')
|
||||
name = name.replace('+', 'plus')
|
||||
name = name.replace('-', 'minus')
|
||||
if f.name.len == 1 {
|
||||
match f.name[0] {
|
||||
`+` { name = name.replace('+', 'op_plus') }
|
||||
`-` { name = name.replace('-', 'op_minus') }
|
||||
`*` { name = name.replace('*', 'op_mul') }
|
||||
`/` { name = name.replace('/', 'op_div') }
|
||||
`%` { name = name.replace('%', 'op_mod') }
|
||||
}
|
||||
}
|
||||
}
|
||||
// Avoid name conflicts (with things like abs(), print() etc).
|
||||
// Generate v_abs(), v_print()
|
||||
|
|
|
@ -6,6 +6,35 @@ module math
|
|||
|
||||
#include <math.h>
|
||||
|
||||
fn C.acos(x f64) f64
|
||||
fn C.asin(x f64) f64
|
||||
fn C.atan(x f64) f64
|
||||
fn C.atan2(y f64, x f64) f64
|
||||
fn C.cbrt(x f64) f64
|
||||
fn C.ceil(x f64) f64
|
||||
fn C.cos(x f64) f64
|
||||
fn C.cosh(x f64) f64
|
||||
fn C.erf(x f64) f64
|
||||
fn C.erfc(x f64) f64
|
||||
fn C.exp(x f64) f64
|
||||
fn C.exp2(x f64) f64
|
||||
fn C.floor(x f64) f64
|
||||
fn C.fmod(x f64, y f64) f64
|
||||
fn C.hypot(x f64, y f64) f64
|
||||
fn C.log(x f64) f64
|
||||
fn C.log2(x f64) f64
|
||||
fn C.log10(x f64) f64
|
||||
fn C.lgamma(x f64) f64
|
||||
fn C.pow(x f64, y f64) f64
|
||||
fn C.round(x f64) f64
|
||||
fn C.sin(x f64) f64
|
||||
fn C.sqrt(x f64) f64
|
||||
fn C.tgamma(x f64) f64
|
||||
fn C.tan(x f64) f64
|
||||
fn C.tanh(x f64) f64
|
||||
fn C.trunc(x f64) f64
|
||||
|
||||
|
||||
// NOTE
|
||||
// When adding a new function, please make sure it's in the right place.
|
||||
// All functions are sorted alphabetically.
|
||||
|
@ -18,8 +47,6 @@ pub fn abs(a f64) f64 {
|
|||
return a
|
||||
}
|
||||
|
||||
fn C.acos(a f64) f64
|
||||
|
||||
// acos calculates inverse cosine (arccosine).
|
||||
pub fn acos(a f64) f64 {
|
||||
return C.acos(a)
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import os
|
||||
|
||||
fn test_aaa_setup(){
|
||||
cleanup_leftovers() assert true
|
||||
}
|
||||
|
||||
fn test_setenv() {
|
||||
os.setenv('foo', 'bar', true)
|
||||
assert os.getenv('foo') == 'bar'
|
||||
|
@ -114,12 +118,11 @@ fn test_walk() {
|
|||
}
|
||||
|
||||
fn test_cp() {
|
||||
$if windows {
|
||||
old_file_name := './example.txt'
|
||||
new_file_name := './new_example.txt'
|
||||
old_file_name := 'cp_example.txt'
|
||||
new_file_name := 'cp_new_example.txt'
|
||||
|
||||
os.write_file(old_file_name, 'Test data 1 2 3, V is awesome #$%^[]!~⭐')
|
||||
result := os.cp(old_file_name, new_file_name) or { panic('$err: errcode: $errcode') }
|
||||
os.cp(old_file_name, new_file_name) or { panic('$err: errcode: $errcode') }
|
||||
|
||||
old_file := os.read_file(old_file_name) or { panic(err) }
|
||||
new_file := os.read_file(new_file_name) or { panic(err) }
|
||||
|
@ -128,12 +131,10 @@ fn test_cp() {
|
|||
os.rm(old_file_name)
|
||||
os.rm(new_file_name)
|
||||
}
|
||||
}
|
||||
|
||||
fn test_cp_r() {
|
||||
//fileX -> dir/fileX
|
||||
// TODO clean up the files
|
||||
/*
|
||||
// NB: clean up of the files happens inside the cleanup_leftovers function
|
||||
os.write_file('ex1.txt', 'wow!')
|
||||
os.mkdir('ex')
|
||||
os.cp_r('ex1.txt', 'ex', false) or { panic(err) }
|
||||
|
@ -148,7 +149,6 @@ fn test_cp_r() {
|
|||
assert old2 == new2
|
||||
//recurring on dir -> local dir
|
||||
os.cp_r('ex', './', true) or { panic(err) }
|
||||
*/
|
||||
}
|
||||
|
||||
//fn test_fork() {
|
||||
|
@ -173,3 +173,25 @@ fn test_cp_r() {
|
|||
// println(cpid)
|
||||
// }
|
||||
//}
|
||||
|
||||
fn test_zzz_cleanup(){
|
||||
cleanup_leftovers() assert true
|
||||
}
|
||||
|
||||
|
||||
// this function is called by both test_aaa_setup & test_zzz_cleanup
|
||||
// it ensures that os tests do not polute the filesystem with leftover
|
||||
// files so that they can be run several times in a row.
|
||||
fn cleanup_leftovers(){
|
||||
// possible leftovers from test_cp
|
||||
os.rm('cp_example.txt')
|
||||
os.rm('cp_new_example.txt')
|
||||
|
||||
// possible leftovers from test_cp_r
|
||||
os.rm('ex/ex2/ex2.txt')
|
||||
os.rm('ex/ex2')
|
||||
os.rm('ex/ex1.txt')
|
||||
os.rm('ex')
|
||||
os.rm('ex2/ex2.txt')
|
||||
os.rm('ex2')
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue