klisp

an open source interpreter for the Kernel Programming Language.
git clone http://git.hanabi.in/repos/klisp.git
Log | Files | Refs | README

kinteger.h (5274B)


      1 /*
      2 ** kinteger.h
      3 ** Kernel Integers (fixints and bigints)
      4 ** See Copyright Notice in klisp.h
      5 */
      6 
      7 #ifndef kinteger_h
      8 #define kinteger_h
      9 
     10 #include <stdbool.h>
     11 #include <stdint.h>
     12 #include <inttypes.h>
     13 
     14 #include "kobject.h"
     15 #include "kstate.h"
     16 #include "imath.h"
     17 
     18 /* Check to see if an int64_t fits in a int32_t */
     19 static inline bool kfit_int32_t(int64_t n) {
     20     return (n >= (int64_t) INT32_MIN && n <= (int64_t) INT32_MAX);
     21 }
     22 
     23 /* This tries to convert a bigint to a fixint */
     24 /* XXX this doesn't need K really */
     25 static inline TValue kbigint_try_fixint(klisp_State *K, TValue n)
     26 {
     27     UNUSED(K);
     28     Bigint *b = tv2bigint(n);
     29     if (MP_USED(b) != 1)
     30         return n;
     31 
     32     int64_t digit = (int64_t) *(MP_DIGITS(b));
     33     if (MP_SIGN(b) == MP_NEG) digit = -digit;
     34     if (kfit_int32_t(digit)) {
     35         /* n shouln't be reachable but the let the gc do its job */
     36         return i2tv((int32_t) digit); 
     37     } else {
     38         return n;
     39     }
     40 }
     41 
     42 /* NOTE: is uint and has flag to allow INT32_MIN as positive argument */
     43 TValue kbigint_new(klisp_State *K, bool sign, uint32_t digit);
     44 
     45 TValue kbigint_copy(klisp_State *K, TValue src);
     46 
     47 /* macro to create the simplest bigint */
     48 #define kbigint_make_simple(K_) kbigint_new(K_, false, 0)
     49 
     50 /* Create a stack allocated bigints from a fixint,
     51    useful for mixed operations, relatively light weight compared
     52    to creating it in the heap and burdening the gc */
     53 #define kbind_bigint(name, fixint)                                      \
     54     int32_t (KUNIQUE_NAME(i)) = ivalue(fixint);                         \
     55     Bigint KUNIQUE_NAME(bigint);                                        \
     56     (KUNIQUE_NAME(bigint)).single = ({                                  \
     57             int64_t temp = (KUNIQUE_NAME(i));                           \
     58             (uint32_t) ((temp < 0)? -temp : temp);                      \
     59         });                                                             \
     60     (KUNIQUE_NAME(bigint)).digits = &((KUNIQUE_NAME(bigint)).single);	\
     61     (KUNIQUE_NAME(bigint)).alloc = 1;                                   \
     62     (KUNIQUE_NAME(bigint)).used = 1;                                    \
     63     (KUNIQUE_NAME(bigint)).sign = (KUNIQUE_NAME(i)) < 0?                \
     64         MP_NEG : MP_ZPOS;                                               \
     65     Bigint *name = &(KUNIQUE_NAME(bigint))
     66     
     67 /* This can be used prior to calling a bigint functions
     68    to automatically convert fixints to bigints.
     69    NOTE: calls to this macro should go in different lines! */
     70 #define kensure_bigint(n)                                       \
     71     /* must use goto, no block should be entered before calling \
     72        kbind_bigint */                                          \
     73     if (!ttisfixint(n))                                         \
     74         goto KUNIQUE_NAME(exit_lbl);                            \
     75     kbind_bigint(KUNIQUE_NAME(bint), (n));                      \
     76     (n) = gc2bigint(KUNIQUE_NAME(bint));                        \
     77 KUNIQUE_NAME(exit_lbl):
     78 
     79 /* This is used by the reader to destructively add digits to a number 
     80    tv_bigint must be positive */
     81 void kbigint_add_digit(klisp_State *K, TValue tv_bigint, int32_t base, 
     82                        int32_t digit);
     83 
     84 /* This is used by the writer to get the digits of a number 
     85    tv_bigint must be positive */
     86 int32_t kbigint_remove_digit(klisp_State *K, TValue tv_bigint, int32_t base);
     87 
     88 /* This is used by write to test if there is any digit left to print */
     89 bool kbigint_has_digits(klisp_State *K, TValue tv_bigint);
     90 
     91 /* Mutate the bigint to have the opposite sign, used in read & write */
     92 void kbigint_invert_sign(klisp_State *K, TValue tv_bigint);
     93 
     94 /* read/write interface */
     95 
     96 /* this works for bigints & fixints, returns true if ok */
     97 /* only positive numbers? */
     98 bool kinteger_read(klisp_State *K, char *buf, int32_t base, TValue *out, 
     99                    char **end);
    100 
    101 /* this is used by write to estimate the number of chars necessary to
    102    print the number */
    103 int32_t kbigint_print_size(TValue tv_bigint, int32_t base);
    104 
    105 /* this is used by write */
    106 void  kbigint_print_string(klisp_State *K, TValue tv_bigint, int32_t base, 
    107                            char *buf, int32_t limit);
    108 
    109 /* Interface for kgnumbers */
    110 bool kbigint_eqp(TValue bigint1, TValue bigint2);
    111 
    112 bool kbigint_ltp(TValue bigint1, TValue bigint2);
    113 bool kbigint_lep(TValue bigint1, TValue bigint2);
    114 bool kbigint_gtp(TValue bigint1, TValue bigint2);
    115 bool kbigint_gep(TValue bigint1, TValue bigint2);
    116 
    117 TValue kbigint_plus(klisp_State *K, TValue n1, TValue n2);
    118 TValue kbigint_times(klisp_State *K, TValue n1, TValue n2);
    119 TValue kbigint_minus(klisp_State *K, TValue n1, TValue n2);
    120 
    121 TValue kbigint_div_mod(klisp_State *K, TValue n1, TValue n2, TValue *res_r);
    122 TValue kbigint_div0_mod0(klisp_State *K, TValue n1, TValue n2, TValue *res_r);
    123 
    124 bool kbigint_negativep(TValue tv_bigint);
    125 bool kbigint_positivep(TValue tv_bigint);
    126 
    127 bool kbigint_oddp(TValue tv_bigint);
    128 bool kbigint_evenp(TValue tv_bigint);
    129 
    130 /* needs the state to create a copy if negative */
    131 TValue kbigint_abs(klisp_State *K, TValue tv_bigint);
    132 
    133 TValue kbigint_gcd(klisp_State *K, TValue n1, TValue n2);
    134 TValue kbigint_lcm(klisp_State *K, TValue n1, TValue n2);
    135 
    136 /* conversion from uint64_t */
    137 TValue kinteger_new_uint64(klisp_State *K, uint64_t x);
    138 
    139 #endif