From 4c87da7db7881a629af1933f50c8382273b320f8 Mon Sep 17 00:00:00 2001 From: Jin Cai Date: Thu, 19 Dec 2024 15:09:52 +0800 Subject: [PATCH] [style] modify styles --- .gitignore | 1 + ulbn.c | 819 ++++++++++++++++++++++++++++++----------------------- ulbn.h | 1 - 3 files changed, 461 insertions(+), 360 deletions(-) diff --git a/.gitignore b/.gitignore index e8d0faa..e31d520 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ *.sw? dev/** +dev* # Build results build*/** diff --git a/ulbn.c b/ulbn.c index bd5eaf6..33159b9 100644 --- a/ulbn.c +++ b/ulbn.c @@ -31,7 +31,7 @@ ulbn - Big Number Library #ifndef ULBN_SOURCE #define ULBN_SOURCE -#if (ULBN_SOURCE + 0) +#if (ULBN_SOURCE + 0) /* avoid "-Wunused-macros" */ #endif #ifndef ULBN_HEADER @@ -46,6 +46,9 @@ ulbn - Big Number Library #include #include +/*********** + * Utility * + ***********/ #ifndef ulbn_assert #define ulbn_assert(expr) assert(expr) @@ -140,12 +143,37 @@ ulbn - Big Number Library #endif #endif #endif + + #ifdef UL_ENDIAN_BIG /* avoid "-Wunused-macros" */ + #if (UL_ENDIAN_BIG + 0) + #endif + #endif + #ifdef UL_ENDIAN_LITTLE /* avoid "-Wunused-macros" */ + #if (UL_ENDIAN_LITTLE + 0) + #endif + #endif #endif /* !UL_ENDIAN_BIG && !UL_ENDIAN_LITTLE */ -#ifdef UL_ENDIAN_BIG + +/* check if `x` is 64-bit integer */ +#if defined(ULONG_MAX) && (ULONG_MAX >> 63) == 1 + #define _ULBN_IS_64BIT(x) ((x) == 0xFFFFFFFFFFFFFFFFul) +#elif defined(ULLONG_MAX) && (ULLONG_MAX >> 63) == 1 + #define _ULBN_IS_64BIT(x) ((x) == 0xFFFFFFFFFFFFFFFFull) +#else + #define _ULBN_IS_64BIT(x) (0) +#endif /* _ULBN_IS_64BIT */ + +#ifdef __cplusplus + #define ulbn_may_static static +#else + #define ulbn_may_static #endif -#ifdef UL_ENDIAN_LITTLE +#ifdef ulbn_may_static /* avoid "-Wunused-macros" */ #endif +/************************ + * Macros about overlap * + ************************/ #define ulbn_safe_forward_overlap(d, dn, s, sn) ((d) <= (s) || (d) >= (s) + (sn)) #define ulbn_safe_backward_overlap(d, dn, s, sn) ((d) + (dn) <= (s) || ((d) >= (s) && (d) + (dn) >= (s) + (sn))) @@ -157,15 +185,9 @@ ulbn - Big Number Library #define ulbn_assert_same_or_not_overlap(d, dn, s, sn) \ ulbn_assert((d) == ul_nullptr || (s) == ul_nullptr || (s) == (d) || ulbn_safe_overlap(d, dn, s, sn)) - -/* check if `x` is 64-bit integer */ -#if defined(ULONG_MAX) && (ULONG_MAX >> 63) == 1 - #define _ULBN_IS_64BIT(x) ((x) == 0xFFFFFFFFFFFFFFFFul) -#elif defined(ULLONG_MAX) && (ULLONG_MAX >> 63) == 1 - #define _ULBN_IS_64BIT(x) ((x) == 0xFFFFFFFFFFFFFFFFull) -#else - #define _ULBN_IS_64BIT(x) (0) -#endif /* _ULBN_IS_64BIT */ +/*********************************** + * Definations about `ulbn_limb_t` * + ***********************************/ #if (CHAR_BIT & 1) != 0 #error "ulbn: CHAR_BIT must be even" @@ -189,35 +211,6 @@ static ul_constexpr const ulbn_limb_t ULBN_LOWMASK = _ULBN_LOWMASK; #define _ulbn_from_pos_slimb(v) _ulbn_cast_limb(v) #define _ulbn_from_neg_slimb(v) _ulbn_cast_limb(_ulbn_cast_limb(-((v) + 1)) + 1u) - -#define _ULBN_SIZET_MAX ul_static_cast(size_t, ~ul_static_cast(size_t, 0)) -#define _ULBN_ALLOC_LIMIT ul_static_cast(size_t, _ULBN_SIZET_MAX / sizeof(ulbn_limb_t)) -/* The limitation of ulbn_usize_t, mainly to avoid overflow caused by the multiplication of ulbn_usize_t */ -#define _ULBN_SSIZE_LIMIT ulbn_cast_usize(_ulbn_min_(_ULBN_USIZE_LIMIT / 2, ulbn_cast_usize(ULBN_SSIZE_MAX))) - -ul_static_assert(sizeof(size_t) >= sizeof(ulbn_usize_t), "usbn_usize_t cannot be larger than size_t"); -ul_static_assert( - _ULBN_SHORT_LIMB_SIZE >= (sizeof(ulbn_ulong_t) + sizeof(ulbn_limb_t) - 1) / sizeof(ulbn_limb_t), - "ULBN_SHORT_LIMB_SIZE is too small, it cannot hold `ulbn_ulong_t`" -); - -static ul_constexpr const size_t ULBN_ALLOC_LIMIT = _ULBN_ALLOC_LIMIT; -static ul_constexpr const size_t ULBN_USIZE_LIMIT = _ULBN_USIZE_LIMIT; -static ul_constexpr const ulbn_usize_t ULBN_SSIZE_LIMIT = _ULBN_SSIZE_LIMIT; -static ul_constexpr const ulbn_usize_t ULBN_SHORT_LIMB_SIZE = _ULBN_SHORT_LIMB_SIZE; - -#define _ulbn_abs_size(n) ulbn_cast_usize((n) < 0 ? -(n) : (n)) -#define _ulbn_make_ssize(pos, n) ((pos) ? ulbn_cast_ssize(n) : -ulbn_cast_ssize(n)) -/* #define _ulbn_from_pos_ssize(v) ul_static_cast(ulbn_usize_t, v) */ -/* #define _ulbn_from_neg_ssize(v) ul_static_cast(ulbn_usize_t, ul_static_cast(ulbn_usize_t, -((v) + 1)) + 1u) */ -#define _ulbn_from_pos_sbits(v) ul_static_cast(ulbn_bits_t, v) -#define _ulbn_from_neg_sbits(v) ul_static_cast(ulbn_bits_t, ul_static_cast(ulbn_bits_t, -((v) + 1)) + 1u) - - -#define _ulbn_from_pos_slong(v) ul_static_cast(ulbn_ulong_t, v) -#define _ulbn_from_neg_slong(v) ul_static_cast(ulbn_ulong_t, ul_static_cast(ulbn_ulong_t, -((v) + 1)) + 1u) - - #if ULBN_LIMB_MAX < UCHAR_MAX #define _ULBN_LIMB_1X_CHAR #endif @@ -240,15 +233,36 @@ static ul_constexpr const ulbn_usize_t ULBN_SHORT_LIMB_SIZE = _ULBN_SHORT_LIMB_S #undef _ULBN_DIV_4LIMB #undef _ULBN_MUL_4LIMB +/******************************************************* + * Definations about `ulbn_usize_t` and `ulbn_ubits_t` * + *******************************************************/ + +#define _ULBN_SIZET_MAX ul_static_cast(size_t, ~ul_static_cast(size_t, 0)) +#define _ULBN_ALLOC_LIMIT ul_static_cast(size_t, _ULBN_SIZET_MAX / sizeof(ulbn_limb_t)) +/* The limitation of `ulbn_usize_t`, mainly to avoid overflow caused by the multiplication of `ulbn_usize_t` */ +#define _ULBN_USIZE_LIMIT ulbn_cast_usize(_ulbn_min_(_ULBN_SIZET_MAX / _ULBN_LIMB_BITS, ULBN_USIZE_MAX)) +#define _ULBN_SSIZE_LIMIT ulbn_cast_usize(_ulbn_min_(_ULBN_USIZE_LIMIT / 2, ulbn_cast_usize(ULBN_SSIZE_MAX))) + +static ul_constexpr const size_t ULBN_ALLOC_LIMIT = _ULBN_ALLOC_LIMIT; +static ul_constexpr const ulbn_usize_t ULBN_USIZE_LIMIT = _ULBN_USIZE_LIMIT; +static ul_constexpr const ulbn_usize_t ULBN_SSIZE_LIMIT = _ULBN_SSIZE_LIMIT; +static ul_constexpr const ulbn_usize_t ULBN_SHORT_LIMB_SIZE = _ULBN_SHORT_LIMB_SIZE; + +#define _ulbn_abs_size(n) ulbn_cast_usize((n) < 0 ? -(n) : (n)) +#define _ulbn_make_ssize(pos, n) ((pos) ? ulbn_cast_ssize(n) : -ulbn_cast_ssize(n)) +#define _ulbn_from_pos_sbits(v) ul_static_cast(ulbn_bits_t, v) +#define _ulbn_from_neg_sbits(v) ul_static_cast(ulbn_bits_t, ul_static_cast(ulbn_bits_t, -((v) + 1)) + 1u) + #ifndef ULBN_CHECK_USIZE_OVERFLOW + /* If `ulbn_usize_t` is able to hold bits of `ulbi_t`, we don't need to check if `ulbn_usize_t` exceeds the limit */ #if defined(SIZE_MAX) - #if defined(_ULBN_LIMB_1X_CHAR) && ULBN_USIZE_MAX <= SIZE_MAX + #if defined(_ULBN_LIMB_1X_CHAR) && ULBN_USIZE_MAX <= SIZE_MAX / CHAR_BIT #define ULBN_CHECK_USIZE_OVERFLOW 0 - #elif defined(_ULBN_LIMB_2X_CHAR) && ULBN_USIZE_MAX <= SIZE_MAX / 2 + #elif defined(_ULBN_LIMB_2X_CHAR) && ULBN_USIZE_MAX <= SIZE_MAX / 2 / CHAR_BIT #define ULBN_CHECK_USIZE_OVERFLOW 0 - #elif defined(ULBN_LIMB_4X_CHAR) && ULBN_USIZE_MAX <= SIZE_MAX / 4 + #elif defined(ULBN_LIMB_4X_CHAR) && ULBN_USIZE_MAX <= SIZE_MAX / 4 / CHAR_BIT #define ULBN_CHECK_USIZE_OVERFLOW 0 - #elif defined(ULBN_LIMB_8X_CHAR) && ULBN_USIZE_MAX <= SIZE_MAX / 8 + #elif defined(ULBN_LIMB_8X_CHAR) && ULBN_USIZE_MAX <= SIZE_MAX / 8 / CHAR_BIT #define ULBN_CHECK_USIZE_OVERFLOW 0 #endif #endif @@ -272,6 +286,7 @@ static ul_constexpr const ulbn_usize_t ULBN_SHORT_LIMB_SIZE = _ULBN_SHORT_LIMB_S #define ULBN_DO_IF_USIZE_OVERFLOW(n, expr) ULBN_DO_IF_USIZE_COND((n) > ULBN_USIZE_LIMIT, expr) #define ULBN_RETURN_IF_USIZE_OVERFLOW(n, ret) ULBN_RETURN_IF_USIZE_COND((n) > ULBN_USIZE_LIMIT, ret) +/* However, we must check if `ulbn_ssize_t` exceeds the limit */ /* #define ULBN_DO_IF_SSIZE_COND(cond, expr) \ if(ul_unlikely(cond)) \ @@ -297,6 +312,18 @@ static ul_constexpr const ulbn_usize_t ULBN_SHORT_LIMB_SIZE = _ULBN_SHORT_LIMB_S #define ULBN_RETURN_IF_ALLOC_FAILED(ptr, ret) ULBN_RETURN_IF_ALLOC_COND((ptr) == ul_nullptr, ret) #define ULBN_DO_IF_ALLOC_FAILED(ptr, expr) ULBN_DO_IF_ALLOC_COND((ptr) == ul_nullptr, expr) +/************************************ + * Definations about `ulbn_ulong_t` * + ************************************/ + +ul_static_assert( + _ULBN_SHORT_LIMB_SIZE >= (sizeof(ulbn_ulong_t) + sizeof(ulbn_limb_t) - 1) / sizeof(ulbn_limb_t), + "ULBN_SHORT_LIMB_SIZE is too small, it cannot hold `ulbn_ulong_t`" +); + +#define _ulbn_from_pos_slong(v) ul_static_cast(ulbn_ulong_t, v) +#define _ulbn_from_neg_slong(v) ul_static_cast(ulbn_ulong_t, ul_static_cast(ulbn_ulong_t, -((v) + 1)) + 1u) + #define ULBN_DO_IF_PUBLIC_COND(cond, expr) \ if(ul_unlikely(cond)) \ expr((void)0) @@ -306,6 +333,9 @@ static ul_constexpr const ulbn_usize_t ULBN_SHORT_LIMB_SIZE = _ULBN_SHORT_LIMB_S extern "C" { #endif +/********************* + * Allocation * + *********************/ #define ulbn_doalloc(alloc, p, on, nn) (alloc)->alloc_func((alloc)->alloc_opaque, (p), (on), (nn)) @@ -345,6 +375,9 @@ ULBN_PUBLIC void ulbn_dealloc(const ulbn_alloc_t* alloc, void* ptr, size_t sz) { ulbn_doalloc(alloc, ptr, sz, 0); } +/********************************************* + * Operations for short `ulbn_limb_t` * + *********************************************/ ULBN_PRIVATE int _ulbn_clz_(ulbn_limb_t x) { #if ul_has_builtin(__builtin_clz) && ULBN_LIMB_MAX <= UINT_MAX @@ -592,7 +625,6 @@ ULBN_PRIVATE int _ulbn_clz_ulong(ulbn_ulong_t x) { } while(0) #endif /* _ulbn_udiv_ */ - /* Let B to be 2^{ULBN_LIMB_BITS}, di = (B^2-1)//d1 - B */ ULBN_INTERNAL ulbn_limb_t _ulbn_divinv1(ulbn_limb_t d1) { /* @@ -696,6 +728,9 @@ ULBN_INTERNAL ulbn_limb_t _ulbn_divinv2(ulbn_limb_t d1, ulbn_limb_t d0) { (q) = __q1; \ } while(0) +/********************************* + * Copy, Check, Normalize * + *********************************/ /* Normalize p[0:n] from high to low, return the length */ ULBN_INTERNAL ulbn_usize_t ulbn_rnorm(const ulbn_limb_t* p, ulbn_usize_t n) { @@ -711,8 +746,7 @@ ULBN_INTERNAL ulbn_usize_t ulbn_fnorm(const ulbn_limb_t* p, ulbn_usize_t n) { return i; } - -/* Clear p[0:n] */ +/* Fill p[0:n] with 0 */ ULBN_INTERNAL void ulbn_fill0(ulbn_limb_t* p, ulbn_usize_t n) { ulbn_assert(ul_static_cast(size_t, n) < _ULBN_SIZET_MAX / sizeof(ulbn_limb_t)); memset(p, 0, ul_static_cast(size_t, n) * sizeof(ulbn_limb_t)); @@ -748,6 +782,9 @@ ULBN_INTERNAL void ulbn_rcopy(ulbn_limb_t* dst, const ulbn_limb_t* src, ulbn_usi } #define ulbn_maycopy(dst, src, n) ((dst) != (src) ? ulbn_copy((dst), (src), (n)) : (void)0) +/************************* + * Bit operations * + *************************/ /* rp[0:n] = ap[0:n] << b, return overflow part (do not write to rp[n]), ensure 0 < b < {ULBN_LIMB_BITS} */ ULBN_INTERNAL ulbn_limb_t ulbn_shl(ulbn_limb_t* rp, const ulbn_limb_t* ap, ulbn_usize_t n, int b) { @@ -876,6 +913,9 @@ ul_unused ULBN_INTERNAL void ulbn_dprint(FILE* fp, const char* prefix, const ulb } #endif +/********************* + * Comparison * + *********************/ /* Compare ap[0:n] and bp[0:n], return direction (<0 means less than, =0 means equal, >0 means greater) */ ULBN_INTERNAL int ulbn_cmpn(const ulbn_limb_t* ap, const ulbn_limb_t* bp, ulbn_usize_t n) { @@ -894,7 +934,6 @@ ULBN_INTERNAL int ulbn_cmp(const ulbn_limb_t* ap, ulbn_usize_t an, const ulbn_li else return ulbn_cmpn(ap, bp, an); } - /* Compare ap[0:n] and (bp[0:bn] << b), return direction (<0 means less than, =0 means equal, >0 means greater) */ ULBN_INTERNAL int ulbn_cmpshl(const ulbn_limb_t* ap, ulbn_usize_t an, const ulbn_limb_t* bp, ulbn_usize_t bn, int b) { const int br = ul_static_cast(int, _ULBN_LIMB_BITS) - b; @@ -927,6 +966,14 @@ ULBN_INTERNAL int ulbn_cmpshl(const ulbn_limb_t* ap, ulbn_usize_t an, const ulbn return ap[0] < bh ? -1 : 1; } +/* return ap[0:an]*2 <=> mp[0:mn] */ +ULBN_INTERNAL int ulbn_check_round(const ulbn_limb_t* ap, ulbn_usize_t an, const ulbn_limb_t* mp, ulbn_usize_t mn) { + return -ulbn_cmpshl(mp, mn, ap, an, 1); +} + +/********************************* + * Addition, Substraction * + *********************************/ /* rp[0:an] = ap[0:an] + b, return carry (do not write to rp[an]) */ ULBN_INTERNAL ulbn_limb_t ulbn_add1(ulbn_limb_t* rp, const ulbn_limb_t* ap, ulbn_usize_t an, ulbn_limb_t b) { @@ -1102,6 +1149,9 @@ ULBN_INTERNAL ulbn_limb_t ulbn_subshl( return ulbn_sub1(rp + bn, ap + bn, an - bn, cy); } +/************************* + * Multiplication * + *************************/ /* rp[0:an] = ap[0:an] * b, return carry (do not write to rp[an]) */ ULBN_INTERNAL ulbn_limb_t ulbn_mul1(ulbn_limb_t* rp, const ulbn_limb_t* ap, ulbn_usize_t an, ulbn_limb_t b) { @@ -1222,13 +1272,6 @@ ULBN_INTERNAL void ulbn_mul( #elif _ULBN_IS_64BIT(ULBN_LIMB_MAX) #define _ULBN_DEF_SHORT_DIV(prefix, a, b, c) 0x##prefix##a##b##c##a##b##c##a##b##c##a##b##c##a##b##c##u #endif -#ifndef _ULBN_DEF_SHORT_DIV - #ifdef __cplusplus - #define ulbn_may_static static - #else - #define ulbn_may_static - #endif -#endif ULBN_PRIVATE void _ulbn_divby3(ulbn_limb_t* qp, const ulbn_limb_t* ap, ulbn_usize_t an, int dshift) { #ifdef _ULBN_DEF_SHORT_DIV @@ -2304,7 +2347,7 @@ ULBN_PRIVATE int _ulbn_mul_toom_44( } #endif /* _ULBN_USE_TOOM4 */ -/* Note: If allocation fails, it falls back to using a version with less cache, +/* Note: If allocation fails, it falls back to using a version demanding less cache, eventually falling back to the school method (time complexity O(n^2)) */ ULBN_INTERNAL void ulbn_mul( const ulbn_alloc_t* alloc, ulbn_limb_t* ul_restrict rp, /* */ @@ -2425,6 +2468,9 @@ ULBN_INTERNAL int ulbn_mul_guard( return err; } +/******************* + * Division * + *******************/ /* qp[0:an] = ap[0:an] // (d>>shift), rp[0] = ap[0:an] % (d>>shift), ensuring `d` is normalized and `di` is `ulbn_divinv1(d)` */ @@ -2815,6 +2861,9 @@ ULBN_INTERNAL int ulbn_divmod_guard( return _ulbn_divmod_large(alloc, qp, rp, ap, an, dp, dn, shift); } +/************************** + * Base conversion * + **************************/ ULBN_PRIVATE int _ulbn_write0(ulbn_printer_t* printer, void* opaque, size_t len) { static const char ONLY_ZERO[16 + 1] = "0000000000000000"; @@ -3117,6 +3166,9 @@ ULBN_PRIVATE int _ulbn_strprinter(void* opaque, const char* str, size_t len) { return 0; } +/**************************** + * Bitwise operation * + ****************************/ ULBN_INTERNAL void ulbn_and_nocy( ulbn_limb_t* rp, const ulbn_limb_t* ap, const ulbn_limb_t* bp, ulbn_limb_t b_rev_mask, ulbn_usize_t n @@ -3381,6 +3433,9 @@ ULBN_INTERNAL int ulbn_to_bit_info(const ulbn_limb_t* limb, ulbn_usize_t n, ulbn #endif } +/********************************** + * Random number generator * + **********************************/ #if ULBN_CONF_USE_RAND ULBN_INTERNAL unsigned ulbn_rand_gen(ulbn_rand_t* rng) { @@ -3456,6 +3511,9 @@ ULBN_PUBLIC void ulbn_rand_fill(ulbn_rand_t* rng, void* dst, size_t n) { } #endif /* ULBN_CONF_USE_RAND */ +/********************** + * Square root * + **********************/ #if ULBN_LIMB_MAX == 0xFFu || ULBN_LIMB_MAX == 0xFFFFu || ULBN_LIMB_MAX == 0xFFFFFFFFu || _ULBN_IS_64BIT(ULBN_LIMB_MAX) /* 8/16/32/64 bit platform, use faster version */ @@ -3759,6 +3817,9 @@ ULBN_INTERNAL int ulbn_sqrtrem_guard( return err; } +/************** + * GCD * + **************/ ULBN_PRIVATE ulbn_limb_t _ulbn_gcd_(ulbn_limb_t a, ulbn_limb_t b) { /** @@ -3873,17 +3934,9 @@ ULBN_INTERNAL ulbn_usize_t ulbn_gcd( return ulbn_rnorm(ap, shl_idx + an); } - -/* return ap[0:an]*2 <=> mp[0:mn] */ -ULBN_INTERNAL int ulbn_check_round(const ulbn_limb_t* ap, ulbn_usize_t an, const ulbn_limb_t* mp, ulbn_usize_t mn) { - return -ulbn_cmpshl(mp, mn, ap, an, 1); -} - - -/*************** - * Big Integer * - ***************/ - +/************************ + * Memory manage * + ************************/ ULBN_PUBLIC size_t ulbi_sizeof(void) { return sizeof(ulbi_t); @@ -4052,10 +4105,52 @@ ULBN_PUBLIC int ulbi_shrink(const ulbn_alloc_t* alloc, ulbi_t* o) { } -ul_static_assert( - (sizeof(ulbn_ulong_t) * CHAR_BIT + _ULBN_LIMB_BITS - 1) / _ULBN_LIMB_BITS <= _ULBN_SSIZE_LIMIT, - "ulbn_ulong_t is too large that `ulbi_t` cannot hold it" -); +ULBN_PUBLIC int ulbi_set_copy(const ulbn_alloc_t* alloc, ulbi_t* dst, const ulbi_t* src) { + if(dst != src) { + ulbn_limb_t* limb; + ulbn_usize_t n = _ulbn_abs_size(src->len); + if(n <= ULBN_SHORT_LIMB_SIZE) { + limb = _ulbi_limbs(dst); + ulbn_copy(limb, _ulbi_limbs(src), n); + } else { + limb = _ulbi_res(alloc, dst, n); + ULBN_RETURN_IF_ALLOC_FAILED(limb, ULBN_ERR_NOMEM); + ulbn_copy(limb, _ulbi_limbs(src), n); + } + dst->len = src->len; + } + return 0; +} +ULBN_PUBLIC void ulbi_set_move(const ulbn_alloc_t* alloc, ulbi_t* dst, ulbi_t* src) { + ulbi_deinit(alloc, dst); + *dst = *src; + ulbi_init(src); +} + + +#if 0 +ULBN_PRIVATE void ulbi_dprint(FILE* fp, const char* prefix, const ulbi_t* bi) { + if(prefix) + fputs(prefix, fp); + if(bi->len == 0) + fputc('0', fp); + else { + ulbn_baseconv_t conv; + if(bi->len < 0) + fputc('-', fp); + ulbn_prepare_baseconv(&conv, 10); + ulbn_conv2print_generic( + ulbn_default_alloc(), 0, _ulbn_fileprinter, fp, _ulbi_limbs(bi), _ulbn_abs_size(bi->len), &conv + ); + } + fputc('\n', fp); +} +#endif + +/******************************************** + * `ulbn_ulong_t` and `ulbn_slong_t` * + ********************************************/ + ULBN_PUBLIC void ulbi_set_ulong(ulbi_t* dst, ulbn_ulong_t l) { dst->len = ulbn_cast_ssize(ulbn_set_ulong(dst->u.shrt, l)); } @@ -4091,28 +4186,9 @@ ULBN_PUBLIC int ulbi_abs(const ulbn_alloc_t* alloc, ulbi_t* ro, const ulbi_t* ao return err; } - -ULBN_PUBLIC int ulbi_set_copy(const ulbn_alloc_t* alloc, ulbi_t* dst, const ulbi_t* src) { - if(dst != src) { - ulbn_limb_t* limb; - ulbn_usize_t n = _ulbn_abs_size(src->len); - if(n <= ULBN_SHORT_LIMB_SIZE) { - limb = _ulbi_limbs(dst); - ulbn_copy(limb, _ulbi_limbs(src), n); - } else { - limb = _ulbi_res(alloc, dst, n); - ULBN_RETURN_IF_ALLOC_FAILED(limb, ULBN_ERR_NOMEM); - ulbn_copy(limb, _ulbi_limbs(src), n); - } - dst->len = src->len; - } - return 0; -} -ULBN_PUBLIC void ulbi_set_move(const ulbn_alloc_t* alloc, ulbi_t* dst, ulbi_t* src) { - ulbi_deinit(alloc, dst); - *dst = *src; - ulbi_init(src); -} +/********************* + * Set string * + *********************/ ul_static_assert( sizeof(ulbn_usize_t) / sizeof(ulbn_limb_t) + 1 <= _ULBN_SSIZE_LIMIT, @@ -4514,6 +4590,9 @@ ULBN_PUBLIC int ulbi_set_string(const ulbn_alloc_t* alloc, ulbi_t* dst, const ch return *str == 0 ? 0 : ULBN_ERR_INVALID; } +/******************** + * Set bytes * + ********************/ #if ULBN_LIMB_MAX < UCHAR_MAX #error "ulbn: `ulbn_limb_t` cannot be smaller than `unsigned char`" @@ -4761,6 +4840,9 @@ ULBN_PUBLIC int ulbi_set_bytes_signed( } } +/************************* + * Initialization * + *************************/ ULBN_PUBLIC int ulbi_init_copy(const ulbn_alloc_t* alloc, ulbi_t* dst, const ulbi_t* src) { return ulbi_set_copy(alloc, ulbi_init(dst), src); @@ -4820,26 +4902,9 @@ ULBN_PUBLIC int ulbi_init_bytes_signed( return ulbi_set_bytes_signed(alloc, ulbi_init(dst), bytes, len, is_big_endian); } - -#if 0 -ULBN_PRIVATE void ulbi_dprint(FILE* fp, const char* prefix, const ulbi_t* bi) { - if(prefix) - fputs(prefix, fp); - if(bi->len == 0) - fputc('0', fp); - else { - ulbn_baseconv_t conv; - if(bi->len < 0) - fputc('-', fp); - ulbn_prepare_baseconv(&conv, 10); - ulbn_conv2print_generic( - ulbn_default_alloc(), 0, _ulbn_fileprinter, fp, _ulbi_limbs(bi), _ulbn_abs_size(bi->len), &conv - ); - } - fputc('\n', fp); -} -#endif - +/********************* + * Comparison * + *********************/ ULBN_PUBLIC int ulbi_comp(const ulbi_t* ao, const ulbi_t* bo) { int a_positive = (ao->len >= 0), cmp; @@ -4989,6 +5054,9 @@ ULBN_PUBLIC int ulbi_is_odd(const ulbi_t* o) { return o->len != 0 && (_ulbi_limbs(o)[0] & 1) != 0; } +/******************************** + * Addition, Subtraction * + ********************************/ /* ignore sign of `ao` and `bo` */ ULBN_PRIVATE int _ulbi_add_ignore_sign( @@ -5149,6 +5217,9 @@ ULBN_PUBLIC int ulbi_slimb_sub(const ulbn_alloc_t* alloc, ulbi_t* ro, ulbn_slimb return err; } +/************************* + * Multiplication * + *************************/ ULBN_PUBLIC int ulbi_mul_limb(const ulbn_alloc_t* alloc, ulbi_t* ro, const ulbi_t* ao, ulbn_limb_t b) { int positive = (ao->len >= 0); @@ -5201,6 +5272,9 @@ ULBN_PUBLIC int ulbi_mul(const ulbn_alloc_t* alloc, ulbi_t* ro, const ulbi_t* ao return 0; } +/******************* + * Division * + *******************/ ULBN_PRIVATE enum ULBN_ROUND_ENUM _ulbn_adjust_half_round(enum ULBN_ROUND_ENUM round_mode, const ulbi_t* qo) { if(round_mode == ULBN_ROUND_HALF_ODD) @@ -5755,6 +5829,9 @@ ULBN_PUBLIC int ulbi_divmod_2exp( } } +/********************** + * Power, Root * + **********************/ ULBN_PUBLIC int ulbi_pow_ulong(const ulbn_alloc_t* alloc, ulbi_t* ro, const ulbi_t* ao, ulbn_ulong_t b) { ulbi_t B = ULBI_INIT, ta = ULBI_INIT; @@ -5994,6 +6071,9 @@ ULBN_PUBLIC int ulbi_root(const ulbn_alloc_t* alloc, ulbi_t* so, const ulbi_t* a return ulbi_rootrem(alloc, so, ul_nullptr, ao, eo); } +/**************************** + * Bitwise Operation * + ****************************/ ULBN_PUBLIC int ulbi_and(const ulbn_alloc_t* alloc, ulbi_t* ro, const ulbi_t* ao, const ulbi_t* bo) { ulbn_usize_t an = _ulbn_abs_size(ao->len), bn = _ulbn_abs_size(bo->len); @@ -6269,6 +6349,9 @@ ULBN_PUBLIC int ulbi_sar(const ulbn_alloc_t* alloc, ulbi_t* ro, const ulbi_t* ao } } +/******************************* + * Single bit operation * + *******************************/ ULBN_PRIVATE int _ulbi_testbit(const ulbi_t* o, ulbn_usize_t idx, int shift) { ulbn_assert(0 <= shift && ul_static_cast(unsigned, shift) < ULBN_LIMB_BITS); @@ -6451,6 +6534,27 @@ ULBN_PUBLIC int ulbi_combit(const ulbn_alloc_t* alloc, ulbi_t* o, const ulbi_t* } +ULBN_PUBLIC int ulbi_is_2pow(const ulbi_t* o) { + return ulbn_is_2pow(_ulbi_limbs(o), _ulbn_abs_size(o->len)); +} +ULBN_PUBLIC ulbn_bits_t ulbi_ctz(const ulbi_t* ro) { + return ulbn_ctz(_ulbi_limbs(ro), _ulbn_abs_size(ro->len)); +} +ULBN_PUBLIC ulbn_bits_t ulbi_cto(const ulbi_t* ro) { + return ulbn_cto(_ulbi_limbs(ro), _ulbn_abs_size(ro->len)); +} +ULBN_PUBLIC ulbn_bits_t ulbi_abs_popcount(const ulbi_t* ro) { + return ulbn_popcount(_ulbi_limbs(ro), _ulbn_abs_size(ro->len)); +} +ULBN_PUBLIC ulbn_bits_t ulbi_abs_bit_width(const ulbi_t* ro) { + ulbn_usize_t n = _ulbn_abs_size(ro->len); + return n ? ulbn_bit_width(_ulbi_limbs(ro), n) : 0; +} + +/******************************************* + * Conversion to fixed-bits integer * + *******************************************/ + ULBN_PRIVATE int _ulbi_as_uint( const ulbn_alloc_t* alloc, ulbi_t* ro, /* */ const ulbi_t* ao, ulbn_usize_t idx, int shift, int need_com /* */ @@ -6621,24 +6725,9 @@ ULBN_PUBLIC int ulbi_as_int(const ulbn_alloc_t* alloc, ulbi_t* ro, const ulbi_t* return _ulbi_as_int(alloc, ro, ao, idx, shift); } - -ULBN_PUBLIC int ulbi_is_2pow(const ulbi_t* o) { - return ulbn_is_2pow(_ulbi_limbs(o), _ulbn_abs_size(o->len)); -} -ULBN_PUBLIC ulbn_bits_t ulbi_ctz(const ulbi_t* ro) { - return ulbn_ctz(_ulbi_limbs(ro), _ulbn_abs_size(ro->len)); -} -ULBN_PUBLIC ulbn_bits_t ulbi_cto(const ulbi_t* ro) { - return ulbn_cto(_ulbi_limbs(ro), _ulbn_abs_size(ro->len)); -} -ULBN_PUBLIC ulbn_bits_t ulbi_abs_popcount(const ulbi_t* ro) { - return ulbn_popcount(_ulbi_limbs(ro), _ulbn_abs_size(ro->len)); -} -ULBN_PUBLIC ulbn_bits_t ulbi_abs_bit_width(const ulbi_t* ro) { - ulbn_usize_t n = _ulbn_abs_size(ro->len); - return n ? ulbn_bit_width(_ulbi_limbs(ro), n) : 0; -} - +/************************************ + * Conversion to other types * + ************************************/ ULBN_PUBLIC ulbn_limb_t ulbi_to_limb(const ulbi_t* src) { if(src->len == 0) @@ -6717,39 +6806,238 @@ ULBN_PUBLIC int ulbi_fit_slong(const ulbi_t* src) { } -ULBN_PRIVATE void _ulbi_to_bytes_pos_le(unsigned char* dst, size_t size, const ulbn_limb_t* limb, ulbn_usize_t len) { -#if ULBN_LIMB_MAX == UCHAR_MAX || (defined(UL_ENDIAN_LITTLE) && !defined(UL_ENDIAN_BIG)) - ulbn_assert(ul_static_cast(size_t, len) <= _ULBN_SIZET_MAX / sizeof(ulbn_limb_t)); - if(size <= len * sizeof(ulbn_limb_t)) { - memcpy(dst, limb, size); - } else { - memcpy(dst, limb, len * sizeof(ulbn_limb_t)); - memset(dst + len * sizeof(ulbn_limb_t), 0, size - len * sizeof(ulbn_limb_t)); - } -#else - ulbn_limb_t l; - size_t t; - - ulbn_assert(ul_static_cast(size_t, len) <= _ULBN_SIZET_MAX / sizeof(ulbn_limb_t)); - while(len-- != 0) { - l = *limb++; - t = _ulbn_min_(sizeof(ulbn_limb_t), size); - size -= t; - while(t-- != 0) { - *dst++ = ul_static_cast(unsigned char, l); - l >>= CHAR_BIT; - } - if(size == 0) - return; - } - memset(dst, 0, size); -#endif +#if ULBN_CONF_HAS_FLOAT +ULBN_PRIVATE int _ulbn_feqf(float a, float b) { + return a >= b && a <= b; } -ULBN_PRIVATE void _ulbi_to_bytes_pos_be(unsigned char* dst, size_t size, const ulbn_limb_t* limb, ulbn_usize_t len) { - size_t t; - ulbn_limb_t l; +ULBN_PUBLIC int ulbi_set_float(const ulbn_alloc_t* alloc, ulbi_t* dst, float x) { + static ul_constexpr const float B = ul_static_cast(float, _ULBN_LIMB_SIGNBIT) * 2.0F; + static ul_constexpr const float Bi = 1.0F / (ul_static_cast(float, _ULBN_LIMB_SIGNBIT) * 2.0F); + ulbn_usize_t rn; + ulbn_limb_t* rp; + float xl; + int positive; - ulbn_assert(ul_static_cast(size_t, len) <= _ULBN_SIZET_MAX / sizeof(ulbn_limb_t)); + /* NaN, +Inf, -Inf or 0 */ + if(x != x || _ulbn_feqf(x, x * 0.5F)) { + _ulbi_set_zero(dst); + return _ulbn_feqf(x, 0.0F) ? 0 : ULBN_ERR_INVALID; + } + positive = x >= 0.0F; + if(!positive) + x = -x; + if(x < 1.0F) { + _ulbi_set_zero(dst); + return ULBN_ERR_INEXACT; + } + for(rn = 1; x >= B; ++rn) + x *= Bi; + ULBN_RETURN_IF_SSIZE_OVERFLOW(rn, ULBN_ERR_EXCEED_RANGE); + + rp = _ulbi_res(alloc, dst, rn); + ULBN_RETURN_IF_ALLOC_FAILED(rp, ULBN_ERR_NOMEM); + dst->len = _ulbn_make_ssize(positive, rn); + while(rn) { + #ifdef HUGE_VALF /* we guess that `floorf` exists when `HUGE_VALF` exists */ + xl = floorf(x); + #else + xl = ul_static_cast(float, floor(x)); + #endif + x -= xl; + rp[--rn] = _ulbn_cast_limb(xl); + x = B * x; + } + return x <= 0.0F ? 0 : ULBN_ERR_INEXACT; +} +ULBN_PUBLIC int ulbi_init_float(const ulbn_alloc_t* alloc, ulbi_t* dst, float x) { + return ulbi_set_float(alloc, ulbi_init(dst), x); +} +ULBN_PUBLIC float ulbi_to_float(const ulbi_t* src) { + static ul_constexpr const float B = ul_static_cast(float, _ULBN_LIMB_SIGNBIT) * 2.0F; + const ulbn_usize_t n = _ulbn_abs_size(src->len); + const ulbn_limb_t* p = _ulbi_limbs(src); + float r; + ulbn_usize_t i = n; + + if(n == 0) + return 0.0F; + r = ul_static_cast(float, p[--i]); + while(i > 0) + r = r * B + ul_static_cast(float, p[--i]); + return src->len >= 0 ? r : -r; +} +ULBN_PUBLIC int ulbi_fit_float(const ulbi_t* src) { + const ulbn_bits_t bits = ulbi_abs_bit_width(src); + const ulbn_bits_t ctz = ulbi_ctz(src); + return bits <= FLT_MAX_EXP && bits - ctz <= FLT_MANT_DIG; +} +#endif /* ULBN_CONF_HAS_FLOAT */ + + +#if ULBN_CONF_HAS_DOUBLE +ULBN_PRIVATE int _ulbn_feq(double a, double b) { + return a >= b && a <= b; +} +ULBN_PUBLIC int ulbi_set_double(const ulbn_alloc_t* alloc, ulbi_t* dst, double x) { + static ul_constexpr const double B = ul_static_cast(double, _ULBN_LIMB_SIGNBIT) * 2.0; + static ul_constexpr const double Bi = 1.0 / (ul_static_cast(double, _ULBN_LIMB_SIGNBIT) * 2.0); + ulbn_usize_t rn; + ulbn_limb_t* rp; + double xl; + int positive; + + /* NaN, +Inf, -Inf or 0 */ + if(x != x || _ulbn_feq(x, x * 0.5)) { + _ulbi_set_zero(dst); + return _ulbn_feq(x, 0.0) ? 0 : ULBN_ERR_INVALID; + } + positive = x >= 0.0; + if(!positive) + x = -x; + if(x < 1.0) { + _ulbi_set_zero(dst); + return ULBN_ERR_INEXACT; + } + for(rn = 1; x >= B; ++rn) + x *= Bi; + ULBN_RETURN_IF_SSIZE_OVERFLOW(rn, ULBN_ERR_EXCEED_RANGE); + + rp = _ulbi_res(alloc, dst, rn); + ULBN_RETURN_IF_ALLOC_FAILED(rp, ULBN_ERR_NOMEM); + dst->len = _ulbn_make_ssize(positive, rn); + while(rn) { + xl = floor(x); + x -= xl; + rp[--rn] = _ulbn_cast_limb(xl); + x = B * x; + } + return x <= 0 ? 0 : ULBN_ERR_INEXACT; +} +ULBN_PUBLIC int ulbi_init_double(const ulbn_alloc_t* alloc, ulbi_t* dst, double x) { + return ulbi_set_double(alloc, ulbi_init(dst), x); +} +ULBN_PUBLIC double ulbi_to_double(const ulbi_t* src) { + static ul_constexpr const double B = ul_static_cast(double, _ULBN_LIMB_SIGNBIT) * 2.0; + const ulbn_usize_t n = _ulbn_abs_size(src->len); + const ulbn_limb_t* p = _ulbi_limbs(src); + double r; + ulbn_usize_t i = n; + + if(n == 0) + return 0.0; + r = ul_static_cast(double, p[--i]); + while(i > 0) + r = r * B + ul_static_cast(double, p[--i]); + return src->len >= 0 ? r : -r; +} +ULBN_PUBLIC int ulbi_fit_double(const ulbi_t* src) { + const ulbn_bits_t bits = ulbi_abs_bit_width(src); + const ulbn_bits_t ctz = ulbi_ctz(src); + return bits <= DBL_MAX_EXP && bits - ctz <= DBL_MANT_DIG; +} +#endif /* ULBN_CONF_HAS_DOUBLE */ + + +#if ULBN_CONF_HAS_LONG_DOUBLE +ULBN_PRIVATE int _ulbn_feql(long double a, long double b) { + return a >= b && a <= b; +} +ULBN_PUBLIC int ulbi_set_long_double(const ulbn_alloc_t* alloc, ulbi_t* dst, long double x) { + static ul_constexpr const long double B = ul_static_cast(long double, _ULBN_LIMB_SIGNBIT) * 2.0L; + static ul_constexpr const long double Bi = 1.0L / (ul_static_cast(long double, _ULBN_LIMB_SIGNBIT) * 2.0L); + ulbn_usize_t rn; + ulbn_limb_t* rp; + long double xl; + int positive; + + /* NaN, +Inf, -Inf or 0 */ + if(x != x || _ulbn_feql(x, x * 0.5L)) { + _ulbi_set_zero(dst); + return _ulbn_feql(x, 0.0L) ? 0 : ULBN_ERR_INVALID; + } + positive = x >= 0.0L; + if(!positive) + x = -x; + if(x < 1.0L) { + _ulbi_set_zero(dst); + return ULBN_ERR_INEXACT; + } + for(rn = 1; x >= B; ++rn) + x *= Bi; + ULBN_RETURN_IF_SSIZE_OVERFLOW(rn, ULBN_ERR_EXCEED_RANGE); + + rp = _ulbi_res(alloc, dst, rn); + ULBN_RETURN_IF_ALLOC_FAILED(rp, ULBN_ERR_NOMEM); + dst->len = _ulbn_make_ssize(positive, rn); + while(rn) { + xl = floorl(x); + x -= xl; + rp[--rn] = _ulbn_cast_limb(xl); + x = B * x; + } + return x <= 0.0L ? 0 : ULBN_ERR_INEXACT; +} +ULBN_PUBLIC int ulbi_init_long_double(const ulbn_alloc_t* alloc, ulbi_t* dst, long double x) { + return ulbi_set_long_double(alloc, ulbi_init(dst), x); +} +ULBN_PUBLIC long double ulbi_to_long_double(const ulbi_t* src) { + static ul_constexpr const long double B = ul_static_cast(long double, _ULBN_LIMB_SIGNBIT) * 2.0L; + const ulbn_usize_t n = _ulbn_abs_size(src->len); + const ulbn_limb_t* p = _ulbi_limbs(src); + long double r; + ulbn_usize_t i = n; + + if(n == 0) + return 0.0L; + r = ul_static_cast(long double, p[--i]); + while(i > 0) + r = r * B + ul_static_cast(long double, p[--i]); + return src->len >= 0 ? r : -r; +} +ULBN_PUBLIC int ulbi_fit_long_double(const ulbi_t* src) { + const ulbn_bits_t bits = ulbi_abs_bit_width(src); + const ulbn_bits_t ctz = ulbi_ctz(src); + return bits <= LDBL_MAX_EXP && bits - ctz <= LDBL_MANT_DIG; +} +#endif /* ULBN_CONF_HAS_LONG_DOUBLE */ + +/****************************** + * Conversion to bytes * + ******************************/ + +ULBN_PRIVATE void _ulbi_to_bytes_pos_le(unsigned char* dst, size_t size, const ulbn_limb_t* limb, ulbn_usize_t len) { +#if ULBN_LIMB_MAX == UCHAR_MAX || (defined(UL_ENDIAN_LITTLE) && !defined(UL_ENDIAN_BIG)) + ulbn_assert(ul_static_cast(size_t, len) <= _ULBN_SIZET_MAX / sizeof(ulbn_limb_t)); + if(size <= len * sizeof(ulbn_limb_t)) { + memcpy(dst, limb, size); + } else { + memcpy(dst, limb, len * sizeof(ulbn_limb_t)); + memset(dst + len * sizeof(ulbn_limb_t), 0, size - len * sizeof(ulbn_limb_t)); + } +#else + ulbn_limb_t l; + size_t t; + + ulbn_assert(ul_static_cast(size_t, len) <= _ULBN_SIZET_MAX / sizeof(ulbn_limb_t)); + while(len-- != 0) { + l = *limb++; + t = _ulbn_min_(sizeof(ulbn_limb_t), size); + size -= t; + while(t-- != 0) { + *dst++ = ul_static_cast(unsigned char, l); + l >>= CHAR_BIT; + } + if(size == 0) + return; + } + memset(dst, 0, size); +#endif +} +ULBN_PRIVATE void _ulbi_to_bytes_pos_be(unsigned char* dst, size_t size, const ulbn_limb_t* limb, ulbn_usize_t len) { + size_t t; + ulbn_limb_t l; + + ulbn_assert(ul_static_cast(size_t, len) <= _ULBN_SIZET_MAX / sizeof(ulbn_limb_t)); dst += size; while(len-- != 0) { l = *limb++; @@ -6909,6 +7197,9 @@ ULBN_PUBLIC void ulbi_to_bytes_signed_be(const ulbi_t* ao, void* dst, size_t siz _ulbi_to_bytes_neg_be(ul_reinterpret_cast(unsigned char*, dst), size, ap, an); } +/**************************** + * Base conversation * + ****************************/ ULBN_PRIVATE int _ulbi_print_ex( const ulbn_alloc_t* alloc, /* */ @@ -7031,202 +7322,9 @@ ULBN_PUBLIC char* ulbi_to_string_alloc( return printer.data; } - -#if ULBN_CONF_HAS_FLOAT -ULBN_PRIVATE int _ulbn_feqf(float a, float b) { - return a >= b && a <= b; -} -ULBN_PUBLIC int ulbi_set_float(const ulbn_alloc_t* alloc, ulbi_t* dst, float x) { - static ul_constexpr const float B = ul_static_cast(float, _ULBN_LIMB_SIGNBIT) * 2.0F; - static ul_constexpr const float Bi = 1.0F / (ul_static_cast(float, _ULBN_LIMB_SIGNBIT) * 2.0F); - ulbn_usize_t rn; - ulbn_limb_t* rp; - float xl; - int positive; - - /* NaN, +Inf, -Inf or 0 */ - if(x != x || _ulbn_feqf(x, x * 0.5F)) { - _ulbi_set_zero(dst); - return _ulbn_feqf(x, 0.0F) ? 0 : ULBN_ERR_INVALID; - } - positive = x >= 0.0F; - if(!positive) - x = -x; - if(x < 1.0F) { - _ulbi_set_zero(dst); - return ULBN_ERR_INEXACT; - } - for(rn = 1; x >= B; ++rn) - x *= Bi; - ULBN_RETURN_IF_SSIZE_OVERFLOW(rn, ULBN_ERR_EXCEED_RANGE); - - rp = _ulbi_res(alloc, dst, rn); - ULBN_RETURN_IF_ALLOC_FAILED(rp, ULBN_ERR_NOMEM); - dst->len = _ulbn_make_ssize(positive, rn); - while(rn) { - #ifdef HUGE_VALF /* we guess that `floorf` exists when `HUGE_VALF` exists */ - xl = floorf(x); - #else - xl = ul_static_cast(float, floor(x)); - #endif - x -= xl; - rp[--rn] = _ulbn_cast_limb(xl); - x = B * x; - } - return x <= 0.0F ? 0 : ULBN_ERR_INEXACT; -} -ULBN_PUBLIC int ulbi_init_float(const ulbn_alloc_t* alloc, ulbi_t* dst, float x) { - return ulbi_set_float(alloc, ulbi_init(dst), x); -} -ULBN_PUBLIC float ulbi_to_float(const ulbi_t* src) { - static ul_constexpr const float B = ul_static_cast(float, _ULBN_LIMB_SIGNBIT) * 2.0F; - const ulbn_usize_t n = _ulbn_abs_size(src->len); - const ulbn_limb_t* p = _ulbi_limbs(src); - float r; - ulbn_usize_t i = n; - - if(n == 0) - return 0.0F; - r = ul_static_cast(float, p[--i]); - while(i > 0) - r = r * B + ul_static_cast(float, p[--i]); - return src->len >= 0 ? r : -r; -} -ULBN_PUBLIC int ulbi_fit_float(const ulbi_t* src) { - const ulbn_bits_t bits = ulbi_abs_bit_width(src); - const ulbn_bits_t ctz = ulbi_ctz(src); - return bits <= FLT_MAX_EXP && bits - ctz <= FLT_MANT_DIG; -} -#endif /* ULBN_CONF_HAS_FLOAT */ - - -#if ULBN_CONF_HAS_DOUBLE -ULBN_PRIVATE int _ulbn_feq(double a, double b) { - return a >= b && a <= b; -} -ULBN_PUBLIC int ulbi_set_double(const ulbn_alloc_t* alloc, ulbi_t* dst, double x) { - static ul_constexpr const double B = ul_static_cast(double, _ULBN_LIMB_SIGNBIT) * 2.0; - static ul_constexpr const double Bi = 1.0 / (ul_static_cast(double, _ULBN_LIMB_SIGNBIT) * 2.0); - ulbn_usize_t rn; - ulbn_limb_t* rp; - double xl; - int positive; - - /* NaN, +Inf, -Inf or 0 */ - if(x != x || _ulbn_feq(x, x * 0.5)) { - _ulbi_set_zero(dst); - return _ulbn_feq(x, 0.0) ? 0 : ULBN_ERR_INVALID; - } - positive = x >= 0.0; - if(!positive) - x = -x; - if(x < 1.0) { - _ulbi_set_zero(dst); - return ULBN_ERR_INEXACT; - } - for(rn = 1; x >= B; ++rn) - x *= Bi; - ULBN_RETURN_IF_SSIZE_OVERFLOW(rn, ULBN_ERR_EXCEED_RANGE); - - rp = _ulbi_res(alloc, dst, rn); - ULBN_RETURN_IF_ALLOC_FAILED(rp, ULBN_ERR_NOMEM); - dst->len = _ulbn_make_ssize(positive, rn); - while(rn) { - xl = floor(x); - x -= xl; - rp[--rn] = _ulbn_cast_limb(xl); - x = B * x; - } - return x <= 0 ? 0 : ULBN_ERR_INEXACT; -} -ULBN_PUBLIC int ulbi_init_double(const ulbn_alloc_t* alloc, ulbi_t* dst, double x) { - return ulbi_set_double(alloc, ulbi_init(dst), x); -} -ULBN_PUBLIC double ulbi_to_double(const ulbi_t* src) { - static ul_constexpr const double B = ul_static_cast(double, _ULBN_LIMB_SIGNBIT) * 2.0; - const ulbn_usize_t n = _ulbn_abs_size(src->len); - const ulbn_limb_t* p = _ulbi_limbs(src); - double r; - ulbn_usize_t i = n; - - if(n == 0) - return 0.0; - r = ul_static_cast(double, p[--i]); - while(i > 0) - r = r * B + ul_static_cast(double, p[--i]); - return src->len >= 0 ? r : -r; -} -ULBN_PUBLIC int ulbi_fit_double(const ulbi_t* src) { - const ulbn_bits_t bits = ulbi_abs_bit_width(src); - const ulbn_bits_t ctz = ulbi_ctz(src); - return bits <= DBL_MAX_EXP && bits - ctz <= DBL_MANT_DIG; -} -#endif /* ULBN_CONF_HAS_DOUBLE */ - - -#if ULBN_CONF_HAS_LONG_DOUBLE -ULBN_PRIVATE int _ulbn_feql(long double a, long double b) { - return a >= b && a <= b; -} -ULBN_PUBLIC int ulbi_set_long_double(const ulbn_alloc_t* alloc, ulbi_t* dst, long double x) { - static ul_constexpr const long double B = ul_static_cast(long double, _ULBN_LIMB_SIGNBIT) * 2.0L; - static ul_constexpr const long double Bi = 1.0L / (ul_static_cast(long double, _ULBN_LIMB_SIGNBIT) * 2.0L); - ulbn_usize_t rn; - ulbn_limb_t* rp; - long double xl; - int positive; - - /* NaN, +Inf, -Inf or 0 */ - if(x != x || _ulbn_feql(x, x * 0.5L)) { - _ulbi_set_zero(dst); - return _ulbn_feql(x, 0.0L) ? 0 : ULBN_ERR_INVALID; - } - positive = x >= 0.0L; - if(!positive) - x = -x; - if(x < 1.0L) { - _ulbi_set_zero(dst); - return ULBN_ERR_INEXACT; - } - for(rn = 1; x >= B; ++rn) - x *= Bi; - ULBN_RETURN_IF_SSIZE_OVERFLOW(rn, ULBN_ERR_EXCEED_RANGE); - - rp = _ulbi_res(alloc, dst, rn); - ULBN_RETURN_IF_ALLOC_FAILED(rp, ULBN_ERR_NOMEM); - dst->len = _ulbn_make_ssize(positive, rn); - while(rn) { - xl = floorl(x); - x -= xl; - rp[--rn] = _ulbn_cast_limb(xl); - x = B * x; - } - return x <= 0.0L ? 0 : ULBN_ERR_INEXACT; -} -ULBN_PUBLIC int ulbi_init_long_double(const ulbn_alloc_t* alloc, ulbi_t* dst, long double x) { - return ulbi_set_long_double(alloc, ulbi_init(dst), x); -} -ULBN_PUBLIC long double ulbi_to_long_double(const ulbi_t* src) { - static ul_constexpr const long double B = ul_static_cast(long double, _ULBN_LIMB_SIGNBIT) * 2.0L; - const ulbn_usize_t n = _ulbn_abs_size(src->len); - const ulbn_limb_t* p = _ulbi_limbs(src); - long double r; - ulbn_usize_t i = n; - - if(n == 0) - return 0.0L; - r = ul_static_cast(long double, p[--i]); - while(i > 0) - r = r * B + ul_static_cast(long double, p[--i]); - return src->len >= 0 ? r : -r; -} -ULBN_PUBLIC int ulbi_fit_long_double(const ulbi_t* src) { - const ulbn_bits_t bits = ulbi_abs_bit_width(src); - const ulbn_bits_t ctz = ulbi_ctz(src); - return bits <= LDBL_MAX_EXP && bits - ctz <= LDBL_MANT_DIG; -} -#endif /* ULBN_CONF_HAS_LONG_DOUBLE */ - +/*********************************** + * Random number generation * + ***********************************/ #if ULBN_CONF_USE_RAND ULBN_PRIVATE int _ulbi_set_rand( @@ -7369,6 +7467,9 @@ ULBN_PUBLIC int ulbi_init_rand_range2( } #endif /* ULBN_CONF_USE_RAND */ +/********************************* + * GCD, LCM, Extended GCD * + *********************************/ ULBN_PUBLIC int ulbi_gcd(const ulbn_alloc_t* alloc, ulbi_t* ro, const ulbi_t* ao, const ulbi_t* bo) { ulbn_limb_t *ap, *bp; diff --git a/ulbn.h b/ulbn.h index 9ea9fbb..c0696b2 100644 --- a/ulbn.h +++ b/ulbn.h @@ -459,7 +459,6 @@ typedef unsigned ulbn_usize_t; #define ulbn_cast_usize(n) ul_static_cast(ulbn_usize_t, (n)) #define ulbn_cast_ssize(n) ul_static_cast(ulbn_ssize_t, (n)) -#define _ULBN_USIZE_LIMIT ulbn_cast_usize(_ulbn_min_(_ULBN_SIZET_MAX / _ULBN_LIMB_BITS, ULBN_USIZE_MAX)) #if !defined(ULBN_BITS_MAX)