libBF 0.6.5.1 → 0.6.6
raw patch · 11 files changed
+9952/−9282 lines, 11 files
Files
- CHANGELOG.md +7/−0
- libBF.cabal +7/−7
- libbf-2020-01-19/cutils.c +0/−178
- libbf-2020-01-19/cutils.h +0/−157
- libbf-2020-01-19/libbf.c +0/−8404
- libbf-2020-01-19/libbf.h +0/−534
- libbf-quickjs-2021-03-27/cutils.c +631/−0
- libbf-quickjs-2021-03-27/cutils.h +297/−0
- libbf-quickjs-2021-03-27/libbf.c +8466/−0
- libbf-quickjs-2021-03-27/libbf.h +535/−0
- tests/RunUnitTests.hs +9/−2
CHANGELOG.md view
@@ -1,5 +1,12 @@ # Revision history for libBF-hs +## 0.6.6 -- 2023.07.17++* Update the vendored version of `libbf` to include the changes from the+ `2021-03-27` version of `libbf` included in `quickjs`. This includes a bugfix+ that prevents the `bfIsSubnormal` function from infinitely looping on AArch64+ (and other non-x86 64-bit architectures) on certain inputs.+ ## 0.6.5.1 -- 2022.08.29 * Fix a build error on non-Windows OSes accidentally introduced in version
libBF.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.2 name: libBF-version: 0.6.5.1+version: 0.6.6 synopsis: A binding to the libBF library. description: LibBF is a C library for working with arbitray precision IEEE 754 floating point numbers.@@ -61,18 +61,18 @@ cbits/libbf-hs.c else include-dirs:- libbf-2020-01-19+ libbf-quickjs-2021-03-27 includes:- libbf-2020-01-19/libbf.h+ libbf-quickjs-2021-03-27/libbf.h install-includes:- libbf-2020-01-19/libbf.h- libbf-2020-01-19/cutils.h+ libbf-quickjs-2021-03-27/libbf.h+ libbf-quickjs-2021-03-27/cutils.h c-sources:- libbf-2020-01-19/cutils.c- libbf-2020-01-19/libbf.c+ libbf-quickjs-2021-03-27/cutils.c+ libbf-quickjs-2021-03-27/libbf.c cbits/libbf-hs.c ghc-options: -Wall
− libbf-2020-01-19/cutils.c
@@ -1,178 +0,0 @@-/*- * C utilities- * - * Copyright (c) 2017 Fabrice Bellard- *- * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- *- * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- *- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN- * THE SOFTWARE.- */-#include <stdlib.h>-#include <stdio.h>-#include <stdarg.h>-#include <string.h>-#include "cutils.h"--void pstrcpy(char *buf, int buf_size, const char *str)-{- int c;- char *q = buf;-- if (buf_size <= 0)- return;-- for(;;) {- c = *str++;- if (c == 0 || q >= buf + buf_size - 1)- break;- *q++ = c;- }- *q = '\0';-}--/* strcat and truncate. */-char *pstrcat(char *buf, int buf_size, const char *s)-{- int len;- len = strlen(buf);- if (len < buf_size)- pstrcpy(buf + len, buf_size - len, s);- return buf;-}--int strstart(const char *str, const char *val, const char **ptr)-{- const char *p, *q;- p = str;- q = val;- while (*q != '\0') {- if (*p != *q)- return 0;- p++;- q++;- }- if (ptr)- *ptr = p;- return 1;-}--void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func)-{- memset(s, 0, sizeof(*s));- s->opaque = opaque;- s->realloc_func = realloc_func;-}--static void *dbuf_default_realloc(void *opaque, void *ptr, size_t size)-{- return realloc(ptr, size);-}--void dbuf_init(DynBuf *s)-{- dbuf_init2(s, NULL, dbuf_default_realloc);-}--/* return < 0 if error */-int dbuf_realloc(DynBuf *s, size_t new_size)-{- size_t size;- uint8_t *new_buf;- if (new_size > s->allocated_size) {- if (s->error)- return -1;- size = s->allocated_size * 3 / 2;- if (size > new_size)- new_size = size;- new_buf = s->realloc_func(s->opaque, s->buf, new_size);- if (!new_buf) {- s->error = TRUE;- return -1;- }- s->buf = new_buf;- s->allocated_size = new_size;- }- return 0;-}--int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len)-{- size_t end;- end = offset + len;- if (dbuf_realloc(s, end))- return -1;- memcpy(s->buf + offset, data, len);- if (end > s->size)- s->size = end;- return 0;-}--int dbuf_put(DynBuf *s, const uint8_t *data, size_t len)-{- if (unlikely((s->size + len) > s->allocated_size)) {- if (dbuf_realloc(s, s->size + len))- return -1;- }- memcpy(s->buf + s->size, data, len);- s->size += len;- return 0;-}--int dbuf_putc(DynBuf *s, uint8_t c)-{- return dbuf_put(s, &c, 1);-}--int dbuf_putstr(DynBuf *s, const char *str)-{- return dbuf_put(s, (const uint8_t *)str, strlen(str));-}--int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,- const char *fmt, ...)-{- va_list ap;- char buf[128];- int len;- - va_start(ap, fmt);- len = vsnprintf(buf, sizeof(buf), fmt, ap);- va_end(ap);- if (len < sizeof(buf)) {- /* fast case */- return dbuf_put(s, (uint8_t *)buf, len);- } else {- if (dbuf_realloc(s, s->size + len + 1))- return -1;- va_start(ap, fmt);- vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size,- fmt, ap);- va_end(ap);- s->size += len;- }- return 0;-}--void dbuf_free(DynBuf *s)-{- /* we test s->buf as a fail safe to avoid crashing if dbuf_free()- is called twice */- if (s->buf) {- s->realloc_func(s->opaque, s->buf, 0);- }- memset(s, 0, sizeof(*s));-}
− libbf-2020-01-19/cutils.h
@@ -1,157 +0,0 @@-/*- * C utilities- * - * Copyright (c) 2017 Fabrice Bellard- *- * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- *- * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- *- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN- * THE SOFTWARE.- */-#ifndef _CUTILS_H-#define _CUTILS_H--#include <inttypes.h>--#define likely(x) __builtin_expect(!!(x), 1)-#define unlikely(x) __builtin_expect(!!(x), 0)-#define force_inline inline __attribute__((always_inline))-#define no_inline __attribute__((noinline))-#define __maybe_unused __attribute__((unused))--#define xglue(x, y) x ## y-#define glue(x, y) xglue(x, y)-#define stringify(s) tostring(s)-#define tostring(s) #s--#ifndef offsetof-#define offsetof(type, field) ((size_t) &((type *)0)->field)-#endif-#define countof(x) (sizeof(x) / sizeof(x[0]))--typedef int BOOL;--enum {- FALSE = 0,- TRUE = 1,-};--void pstrcpy(char *buf, int buf_size, const char *str);-char *pstrcat(char *buf, int buf_size, const char *s);-int strstart(const char *str, const char *val, const char **ptr);--static inline int max_int(int a, int b)-{- if (a > b)- return a;- else- return b;-}--static inline int min_int(int a, int b)-{- if (a < b)- return a;- else- return b;-}--/* WARNING: undefined if a = 0 */-static inline int clz32(unsigned int a)-{- return __builtin_clz(a);-}--/* WARNING: undefined if a = 0 */-static inline int clz64(uint64_t a)-{- return __builtin_clzll(a);-}--/* WARNING: undefined if a = 0 */-static inline int ctz32(unsigned int a)-{- return __builtin_ctz(a);-}--/* WARNING: undefined if a = 0 */-static inline int ctz64(uint64_t a)-{- return __builtin_ctzll(a);-}--struct __attribute__((packed)) packed_u32 {- uint32_t v;-};--struct __attribute__((packed)) packed_u16 {- uint16_t v;-};--static inline uint32_t get_u32(const uint8_t *tab)-{- return ((struct packed_u32 *)tab)->v;-}--static inline void put_u32(uint8_t *tab, uint32_t val)-{- ((struct packed_u32 *)tab)->v = val;-}--static inline uint32_t get_u16(const uint8_t *tab)-{- return ((struct packed_u16 *)tab)->v;-}--static inline void put_u16(uint8_t *tab, uint16_t val)-{- ((struct packed_u16 *)tab)->v = val;-}--typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size);--typedef struct {- uint8_t *buf;- size_t size;- size_t allocated_size;- BOOL error; /* true if a memory allocation error occurred */- DynBufReallocFunc *realloc_func;- void *opaque; /* for realloc_func */-} DynBuf;--void dbuf_init(DynBuf *s);-void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func);-int dbuf_realloc(DynBuf *s, size_t new_size);-int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len);-int dbuf_put(DynBuf *s, const uint8_t *data, size_t len);-int dbuf_putc(DynBuf *s, uint8_t c);-int dbuf_putstr(DynBuf *s, const char *str);-static inline int dbuf_put_u32(DynBuf *s, uint32_t val)-{- return dbuf_put(s, (uint8_t *)&val, 4);-}-static inline int dbuf_put_u16(DynBuf *s, uint16_t val)-{- return dbuf_put(s, (uint8_t *)&val, 2);-}-int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,- const char *fmt, ...);-void dbuf_free(DynBuf *s);-static inline BOOL dbuf_error(DynBuf *s) {- return s->error;-}--#endif
− libbf-2020-01-19/libbf.c
@@ -1,8404 +0,0 @@-/*- * Tiny arbitrary precision floating point library- * - * Copyright (c) 2017-2020 Fabrice Bellard- *- * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- *- * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- *- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN- * THE SOFTWARE.- */-#include <stdlib.h>-#include <stdio.h>-#include <inttypes.h>-#include <math.h>-#include <string.h>-#include <assert.h>--#ifdef __AVX2__-#include <immintrin.h>-#endif--#include "cutils.h"-#include "libbf.h"--/* enable it to check the multiplication result */-//#define USE_MUL_CHECK-/* enable it to use FFT/NTT multiplication */-#define USE_FFT_MUL-/* enable decimal floating point support */-#define USE_BF_DEC--//#define inline __attribute__((always_inline))--#ifdef __AVX2__-#define FFT_MUL_THRESHOLD 100 /* in limbs of the smallest factor */-#else-#define FFT_MUL_THRESHOLD 100 /* in limbs of the smallest factor */-#endif--/* XXX: adjust */-#define DIVNORM_LARGE_THRESHOLD 50-#define UDIV1NORM_THRESHOLD 3--#if LIMB_BITS == 64-#define FMT_LIMB1 "%" PRIx64 -#define FMT_LIMB "%016" PRIx64 -#define PRId_LIMB PRId64-#define PRIu_LIMB PRIu64--#else--#define FMT_LIMB1 "%x"-#define FMT_LIMB "%08x"-#define PRId_LIMB "d"-#define PRIu_LIMB "u"--#endif--typedef intptr_t mp_size_t;--typedef int bf_op2_func_t(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,- bf_flags_t flags);--#ifdef USE_FFT_MUL--#define FFT_MUL_R_OVERLAP_A (1 << 0)-#define FFT_MUL_R_OVERLAP_B (1 << 1)-#define FFT_MUL_R_NORESIZE (1 << 2)--static no_inline int fft_mul(bf_context_t *s,- bf_t *res, limb_t *a_tab, limb_t a_len,- limb_t *b_tab, limb_t b_len, int mul_flags);-static void fft_clear_cache(bf_context_t *s);-#endif-#ifdef USE_BF_DEC-static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos);-#endif---/* could leading zeros */-static inline int clz(limb_t a)-{- if (a == 0) {- return LIMB_BITS;- } else {-#if LIMB_BITS == 64- return clz64(a);-#else- return clz32(a);-#endif- }-}--static inline int ctz(limb_t a)-{- if (a == 0) {- return LIMB_BITS;- } else {-#if LIMB_BITS == 64- return ctz64(a);-#else- return ctz32(a);-#endif- }-}--static inline int ceil_log2(limb_t a)-{- if (a <= 1)- return 0;- else- return LIMB_BITS - clz(a - 1);-}--/* b must be >= 1 */-static inline slimb_t ceil_div(slimb_t a, slimb_t b)-{- if (a >= 0)- return (a + b - 1) / b;- else- return a / b;-}--/* b must be >= 1 */-static inline slimb_t floor_div(slimb_t a, slimb_t b)-{- if (a >= 0) {- return a / b;- } else {- return (a - b + 1) / b;- }-}--/* return r = a modulo b (0 <= r <= b - 1. b must be >= 1 */-static inline limb_t smod(slimb_t a, slimb_t b)-{- a = a % (slimb_t)b;- if (a < 0)- a += b;- return a;-}--/* signed addition with saturation */-static inline slimb_t sat_add(slimb_t a, slimb_t b)-{- slimb_t r;- r = a + b;- /* overflow ? */- if (((a ^ r) & (b ^ r)) < 0)- r = (a >> (LIMB_BITS - 1)) ^ (((limb_t)1 << (LIMB_BITS - 1)) - 1);- return r;-}--#define malloc(s) malloc_is_forbidden(s)-#define free(p) free_is_forbidden(p)-#define realloc(p, s) realloc_is_forbidden(p, s)--void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func,- void *realloc_opaque)-{- memset(s, 0, sizeof(*s));- s->realloc_func = realloc_func;- s->realloc_opaque = realloc_opaque;-}--void bf_context_end(bf_context_t *s)-{- bf_clear_cache(s);-}--void bf_init(bf_context_t *s, bf_t *r)-{- r->ctx = s;- r->sign = 0;- r->expn = BF_EXP_ZERO;- r->len = 0;- r->tab = NULL;-}--/* return 0 if OK, -1 if alloc error */-int bf_resize(bf_t *r, limb_t len)-{- limb_t *tab;- - if (len != r->len) {- tab = bf_realloc(r->ctx, r->tab, len * sizeof(limb_t));- if (!tab && len != 0)- return -1;- r->tab = tab;- r->len = len;- }- return 0;-}--/* return 0 or BF_ST_MEM_ERROR */-int bf_set_ui(bf_t *r, uint64_t a)-{- r->sign = 0;- if (a == 0) {- r->expn = BF_EXP_ZERO;- bf_resize(r, 0); /* cannot fail */- } -#if LIMB_BITS == 32- else if (a <= 0xffffffff)-#else- else-#endif- {- int shift;- if (bf_resize(r, 1))- goto fail;- shift = clz(a);- r->tab[0] = a << shift;- r->expn = LIMB_BITS - shift;- }-#if LIMB_BITS == 32- else {- uint32_t a1, a0;- int shift;- if (bf_resize(r, 2))- goto fail;- a0 = a;- a1 = a >> 32;- shift = clz(a1);- r->tab[0] = a0 << shift;- r->tab[1] = (a1 << shift) | (a0 >> (LIMB_BITS - shift));- r->expn = 2 * LIMB_BITS - shift;- }-#endif- return 0;- fail:- bf_set_nan(r);- return BF_ST_MEM_ERROR;-}--/* return 0 or BF_ST_MEM_ERROR */-int bf_set_si(bf_t *r, int64_t a)-{- int ret;-- if (a < 0) {- ret = bf_set_ui(r, -a);- r->sign = 1;- } else {- ret = bf_set_ui(r, a);- }- return ret;-}--void bf_set_nan(bf_t *r)-{- bf_resize(r, 0); /* cannot fail */- r->expn = BF_EXP_NAN;- r->sign = 0;-}--void bf_set_zero(bf_t *r, int is_neg)-{- bf_resize(r, 0); /* cannot fail */- r->expn = BF_EXP_ZERO;- r->sign = is_neg;-}--void bf_set_inf(bf_t *r, int is_neg)-{- bf_resize(r, 0); /* cannot fail */- r->expn = BF_EXP_INF;- r->sign = is_neg;-}--/* return 0 or BF_ST_MEM_ERROR */-int bf_set(bf_t *r, const bf_t *a)-{- if (r == a)- return 0;- if (bf_resize(r, a->len)) {- bf_set_nan(r);- return BF_ST_MEM_ERROR;- }- r->sign = a->sign;- r->expn = a->expn;- memcpy(r->tab, a->tab, a->len * sizeof(limb_t));- return 0;-}--/* equivalent to bf_set(r, a); bf_delete(a) */-void bf_move(bf_t *r, bf_t *a)-{- bf_context_t *s = r->ctx;- if (r == a)- return;- bf_free(s, r->tab);- *r = *a;-}--static limb_t get_limbz(const bf_t *a, limb_t idx)-{- if (idx >= a->len)- return 0;- else- return a->tab[idx];-}--/* get LIMB_BITS at bit position 'pos' in tab */-static inline limb_t get_bits(const limb_t *tab, limb_t len, slimb_t pos)-{- limb_t i, a0, a1;- int p;-- i = pos >> LIMB_LOG2_BITS;- p = pos & (LIMB_BITS - 1);- if (i < len)- a0 = tab[i];- else- a0 = 0;- if (p == 0) {- return a0;- } else {- i++;- if (i < len)- a1 = tab[i];- else- a1 = 0;- return (a0 >> p) | (a1 << (LIMB_BITS - p));- }-}--static inline limb_t get_bit(const limb_t *tab, limb_t len, slimb_t pos)-{- slimb_t i;- i = pos >> LIMB_LOG2_BITS;- if (i < 0 || i >= len)- return 0;- return (tab[i] >> (pos & (LIMB_BITS - 1))) & 1;-}--static inline limb_t limb_mask(int start, int last)-{- limb_t v;- int n;- n = last - start + 1;- if (n == LIMB_BITS)- v = -1;- else- v = (((limb_t)1 << n) - 1) << start;- return v;-}--static limb_t mp_scan_nz(const limb_t *tab, mp_size_t n)-{- mp_size_t i;- for(i = 0; i < n; i++) {- if (tab[i] != 0)- return 1;- }- return 0;-}--/* return != 0 if one bit between 0 and bit_pos inclusive is not zero. */-static inline limb_t scan_bit_nz(const bf_t *r, slimb_t bit_pos)-{- slimb_t pos;- limb_t v;- - pos = bit_pos >> LIMB_LOG2_BITS;- if (pos < 0)- return 0;- v = r->tab[pos] & limb_mask(0, bit_pos & (LIMB_BITS - 1));- if (v != 0)- return 1;- pos--;- while (pos >= 0) {- if (r->tab[pos] != 0)- return 1;- pos--;- }- return 0;-}--/* return the addend for rounding. Note that prec can be <= 0 (for- BF_FLAG_RADPNT_PREC) */-static int bf_get_rnd_add(int *pret, const bf_t *r, limb_t l,- slimb_t prec, int rnd_mode)-{- int add_one, inexact;- limb_t bit1, bit0;- - if (rnd_mode == BF_RNDF) {- bit0 = 1; /* faithful rounding does not honor the INEXACT flag */- } else {- /* starting limb for bit 'prec + 1' */- bit0 = scan_bit_nz(r, l * LIMB_BITS - 1 - bf_max(0, prec + 1));- }-- /* get the bit at 'prec' */- bit1 = get_bit(r->tab, l, l * LIMB_BITS - 1 - prec);- inexact = (bit1 | bit0) != 0;- - add_one = 0;- switch(rnd_mode) {- case BF_RNDZ:- break;- case BF_RNDN:- if (bit1) {- if (bit0) {- add_one = 1;- } else {- /* round to even */- add_one =- get_bit(r->tab, l, l * LIMB_BITS - 1 - (prec - 1));- }- }- break;- case BF_RNDD:- case BF_RNDU:- if (r->sign == (rnd_mode == BF_RNDD))- add_one = inexact;- break;- case BF_RNDA:- add_one = inexact;- break;- case BF_RNDNA:- case BF_RNDF:- add_one = bit1;- break;- default:- abort();- }- - if (inexact)- *pret |= BF_ST_INEXACT;- return add_one;-}--static int bf_set_overflow(bf_t *r, int sign, limb_t prec, bf_flags_t flags)-{- slimb_t i, l, e_max;- int rnd_mode;- - rnd_mode = flags & BF_RND_MASK;- if (prec == BF_PREC_INF ||- rnd_mode == BF_RNDN ||- rnd_mode == BF_RNDNA ||- rnd_mode == BF_RNDA ||- (rnd_mode == BF_RNDD && sign == 1) ||- (rnd_mode == BF_RNDU && sign == 0)) {- bf_set_inf(r, sign);- } else {- /* set to maximum finite number */- l = (prec + LIMB_BITS - 1) / LIMB_BITS;- if (bf_resize(r, l)) {- bf_set_nan(r);- return BF_ST_MEM_ERROR;- }- r->tab[0] = limb_mask((-prec) & (LIMB_BITS - 1),- LIMB_BITS - 1);- for(i = 1; i < l; i++)- r->tab[i] = (limb_t)-1;- e_max = (limb_t)1 << (bf_get_exp_bits(flags) - 1);- r->expn = e_max;- r->sign = sign;- }- return BF_ST_OVERFLOW | BF_ST_INEXACT;-}--/* round to prec1 bits assuming 'r' is non zero and finite. 'r' is- assumed to have length 'l' (1 <= l <= r->len). Note: 'prec1' can be- infinite (BF_PREC_INF). 'ret' is 0 or BF_ST_INEXACT if the result- is known to be inexact. Can fail with BF_ST_MEM_ERROR in case of- overflow not returning infinity. */-static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l,- int ret)-{- limb_t v, a;- int shift, add_one, rnd_mode;- slimb_t i, bit_pos, pos, e_min, e_max, e_range, prec;-- /* e_min and e_max are computed to match the IEEE 754 conventions */- e_range = (limb_t)1 << (bf_get_exp_bits(flags) - 1);- e_min = -e_range + 3;- e_max = e_range;- - if (flags & BF_FLAG_RADPNT_PREC) {- /* 'prec' is the precision after the radix point */- if (prec1 != BF_PREC_INF)- prec = r->expn + prec1;- else- prec = prec1;- } else if (unlikely(r->expn < e_min) && (flags & BF_FLAG_SUBNORMAL)) {- /* restrict the precision in case of potentially subnormal- result */- assert(prec1 != BF_PREC_INF);- prec = prec1 - (e_min - r->expn);- } else {- prec = prec1;- }-- /* round to prec bits */- rnd_mode = flags & BF_RND_MASK;- add_one = bf_get_rnd_add(&ret, r, l, prec, rnd_mode);- - if (prec <= 0) {- if (add_one) {- bf_resize(r, 1); /* cannot fail */- r->tab[0] = (limb_t)1 << (LIMB_BITS - 1);- r->expn += 1 - prec;- ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;- return ret;- } else {- goto underflow;- }- } else if (add_one) {- limb_t carry;- - /* add one starting at digit 'prec - 1' */- bit_pos = l * LIMB_BITS - 1 - (prec - 1);- pos = bit_pos >> LIMB_LOG2_BITS;- carry = (limb_t)1 << (bit_pos & (LIMB_BITS - 1));- - for(i = pos; i < l; i++) {- v = r->tab[i] + carry;- carry = (v < carry);- r->tab[i] = v;- if (carry == 0)- break;- }- if (carry) {- /* shift right by one digit */- v = 1;- for(i = l - 1; i >= pos; i--) {- a = r->tab[i];- r->tab[i] = (a >> 1) | (v << (LIMB_BITS - 1));- v = a;- }- r->expn++;- }- }- - /* check underflow */- if (unlikely(r->expn < e_min)) {- if (flags & BF_FLAG_SUBNORMAL) {- /* if inexact, also set the underflow flag */- if (ret & BF_ST_INEXACT)- ret |= BF_ST_UNDERFLOW;- } else {- underflow:- ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;- bf_set_zero(r, r->sign);- return ret;- }- }- - /* check overflow */- if (unlikely(r->expn > e_max))- return bf_set_overflow(r, r->sign, prec1, flags);- - /* keep the bits starting at 'prec - 1' */- bit_pos = l * LIMB_BITS - 1 - (prec - 1);- i = bit_pos >> LIMB_LOG2_BITS;- if (i >= 0) {- shift = bit_pos & (LIMB_BITS - 1);- if (shift != 0)- r->tab[i] &= limb_mask(shift, LIMB_BITS - 1);- } else {- i = 0;- }- /* remove trailing zeros */- while (r->tab[i] == 0)- i++;- if (i > 0) {- l -= i;- memmove(r->tab, r->tab + i, l * sizeof(limb_t));- }- bf_resize(r, l); /* cannot fail */- return ret;-}--/* 'r' must be a finite number. */-int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags)-{- limb_t l, v, a;- int shift, ret;- slimb_t i;- - // bf_print_str("bf_renorm", r);- l = r->len;- while (l > 0 && r->tab[l - 1] == 0)- l--;- if (l == 0) {- /* zero */- r->expn = BF_EXP_ZERO;- bf_resize(r, 0); /* cannot fail */- ret = 0;- } else {- r->expn -= (r->len - l) * LIMB_BITS;- /* shift to have the MSB set to '1' */- v = r->tab[l - 1];- shift = clz(v);- if (shift != 0) {- v = 0;- for(i = 0; i < l; i++) {- a = r->tab[i];- r->tab[i] = (a << shift) | (v >> (LIMB_BITS - shift));- v = a;- }- r->expn -= shift;- }- ret = __bf_round(r, prec1, flags, l, 0);- }- // bf_print_str("r_final", r);- return ret;-}--/* return true if rounding can be done at precision 'prec' assuming- the exact result r is such that |r-a| <= 2^(EXP(a)-k). */-/* XXX: check the case where the exponent would be incremented by the- rounding */-int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k)-{- BOOL is_rndn;- slimb_t bit_pos, n;- limb_t bit;- - if (a->expn == BF_EXP_INF || a->expn == BF_EXP_NAN)- return FALSE;- if (rnd_mode == BF_RNDF) {- return (k >= (prec + 1));- }- if (a->expn == BF_EXP_ZERO)- return FALSE;- is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);- if (k < (prec + 2))- return FALSE;- bit_pos = a->len * LIMB_BITS - 1 - prec;- n = k - prec;- /* bit pattern for RNDN or RNDNA: 0111.. or 1000...- for other rounding modes: 000... or 111... - */- bit = get_bit(a->tab, a->len, bit_pos);- bit_pos--;- n--;- bit ^= is_rndn;- /* XXX: slow, but a few iterations on average */- while (n != 0) {- if (get_bit(a->tab, a->len, bit_pos) != bit)- return TRUE;- bit_pos--;- n--;- }- return FALSE;-}--/* Cannot fail with BF_ST_MEM_ERROR. */-int bf_round(bf_t *r, limb_t prec, bf_flags_t flags)-{- if (r->len == 0)- return 0;- return __bf_round(r, prec, flags, r->len, 0);-}--/* for debugging */-static __maybe_unused void dump_limbs(const char *str, const limb_t *tab, limb_t n)-{- limb_t i;- printf("%s: len=%" PRId_LIMB "\n", str, n);- for(i = 0; i < n; i++) {- printf("%" PRId_LIMB ": " FMT_LIMB "\n",- i, tab[i]);- }-}--void mp_print_str(const char *str, const limb_t *tab, limb_t n)-{- slimb_t i;- printf("%s= 0x", str);- for(i = n - 1; i >= 0; i--) {- if (i != (n - 1))- printf("_");- printf(FMT_LIMB, tab[i]);- }- printf("\n");-}--static __maybe_unused void mp_print_str_h(const char *str,- const limb_t *tab, limb_t n,- limb_t high)-{- slimb_t i;- printf("%s= 0x", str);- printf(FMT_LIMB, high);- for(i = n - 1; i >= 0; i--) {- printf("_");- printf(FMT_LIMB, tab[i]);- }- printf("\n");-}--/* for debugging */-void bf_print_str(const char *str, const bf_t *a)-{- slimb_t i;- printf("%s=", str);-- if (a->expn == BF_EXP_NAN) {- printf("NaN");- } else {- if (a->sign)- putchar('-');- if (a->expn == BF_EXP_ZERO) {- putchar('0');- } else if (a->expn == BF_EXP_INF) {- printf("Inf");- } else {- printf("0x0.");- for(i = a->len - 1; i >= 0; i--)- printf(FMT_LIMB, a->tab[i]);- printf("p%" PRId_LIMB, a->expn);- }- }- printf("\n");-}--/* compare the absolute value of 'a' and 'b'. Return < 0 if a < b, 0- if a = b and > 0 otherwise. */-int bf_cmpu(const bf_t *a, const bf_t *b)-{- slimb_t i;- limb_t len, v1, v2;- - if (a->expn != b->expn) {- if (a->expn < b->expn)- return -1;- else- return 1;- }- len = bf_max(a->len, b->len);- for(i = len - 1; i >= 0; i--) {- v1 = get_limbz(a, a->len - len + i);- v2 = get_limbz(b, b->len - len + i);- if (v1 != v2) {- if (v1 < v2)- return -1;- else- return 1;- }- }- return 0;-}--/* Full order: -0 < 0, NaN == NaN and NaN is larger than all other numbers */-int bf_cmp_full(const bf_t *a, const bf_t *b)-{- int res;- - if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {- if (a->expn == b->expn)- res = 0;- else if (a->expn == BF_EXP_NAN)- res = 1;- else- res = -1;- } else if (a->sign != b->sign) {- res = 1 - 2 * a->sign;- } else {- res = bf_cmpu(a, b);- if (a->sign)- res = -res;- }- return res;-}--/* Standard floating point comparison: return 2 if one of the operands- is NaN (unordered) or -1, 0, 1 depending on the ordering assuming- -0 == +0 */-int bf_cmp(const bf_t *a, const bf_t *b)-{- int res;- - if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {- res = 2;- } else if (a->sign != b->sign) {- if (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO)- res = 0;- else- res = 1 - 2 * a->sign;- } else {- res = bf_cmpu(a, b);- if (a->sign)- res = -res;- }- return res;-}--/* Compute the number of bits 'n' matching the pattern:- a= X1000..0- b= X0111..1- - When computing a-b, the result will have at least n leading zero- bits.-- Precondition: a > b and a.expn - b.expn = 0 or 1-*/-static limb_t count_cancelled_bits(const bf_t *a, const bf_t *b)-{- slimb_t bit_offset, b_offset, n;- int p, p1;- limb_t v1, v2, mask;-- bit_offset = a->len * LIMB_BITS - 1;- b_offset = (b->len - a->len) * LIMB_BITS - (LIMB_BITS - 1) +- a->expn - b->expn;- n = 0;-- /* first search the equals bits */- for(;;) {- v1 = get_limbz(a, bit_offset >> LIMB_LOG2_BITS);- v2 = get_bits(b->tab, b->len, bit_offset + b_offset);- // printf("v1=" FMT_LIMB " v2=" FMT_LIMB "\n", v1, v2);- if (v1 != v2)- break;- n += LIMB_BITS;- bit_offset -= LIMB_BITS;- }- /* find the position of the first different bit */- p = clz(v1 ^ v2) + 1;- n += p;- /* then search for '0' in a and '1' in b */- p = LIMB_BITS - p;- if (p > 0) {- /* search in the trailing p bits of v1 and v2 */- mask = limb_mask(0, p - 1);- p1 = bf_min(clz(v1 & mask), clz((~v2) & mask)) - (LIMB_BITS - p);- n += p1;- if (p1 != p)- goto done;- }- bit_offset -= LIMB_BITS;- for(;;) {- v1 = get_limbz(a, bit_offset >> LIMB_LOG2_BITS);- v2 = get_bits(b->tab, b->len, bit_offset + b_offset);- // printf("v1=" FMT_LIMB " v2=" FMT_LIMB "\n", v1, v2);- if (v1 != 0 || v2 != -1) {- /* different: count the matching bits */- p1 = bf_min(clz(v1), clz(~v2));- n += p1;- break;- }- n += LIMB_BITS;- bit_offset -= LIMB_BITS;- }- done:- return n;-}--static int bf_add_internal(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,- bf_flags_t flags, int b_neg)-{- const bf_t *tmp;- int is_sub, ret, cmp_res, a_sign, b_sign;-- a_sign = a->sign;- b_sign = b->sign ^ b_neg;- is_sub = a_sign ^ b_sign;- cmp_res = bf_cmpu(a, b);- if (cmp_res < 0) {- tmp = a;- a = b;- b = tmp;- a_sign = b_sign; /* b_sign is never used later */- }- /* abs(a) >= abs(b) */- if (cmp_res == 0 && is_sub && a->expn < BF_EXP_INF) {- /* zero result */- bf_set_zero(r, (flags & BF_RND_MASK) == BF_RNDD);- ret = 0;- } else if (a->len == 0 || b->len == 0) {- ret = 0;- if (a->expn >= BF_EXP_INF) {- if (a->expn == BF_EXP_NAN) {- /* at least one operand is NaN */- bf_set_nan(r);- } else if (b->expn == BF_EXP_INF && is_sub) {- /* infinities with different signs */- bf_set_nan(r);- ret = BF_ST_INVALID_OP;- } else {- bf_set_inf(r, a_sign);- }- } else {- /* at least one zero and not subtract */- bf_set(r, a);- r->sign = a_sign;- goto renorm;- }- } else {- slimb_t d, a_offset, b_bit_offset, i, cancelled_bits;- limb_t carry, v1, v2, u, r_len, carry1, precl, tot_len, z, sub_mask;-- r->sign = a_sign;- r->expn = a->expn;- d = a->expn - b->expn;- /* must add more precision for the leading cancelled bits in- subtraction */- if (is_sub) {- if (d <= 1)- cancelled_bits = count_cancelled_bits(a, b);- else- cancelled_bits = 1;- } else {- cancelled_bits = 0;- }- - /* add two extra bits for rounding */- precl = (cancelled_bits + prec + 2 + LIMB_BITS - 1) / LIMB_BITS;- tot_len = bf_max(a->len, b->len + (d + LIMB_BITS - 1) / LIMB_BITS);- r_len = bf_min(precl, tot_len);- if (bf_resize(r, r_len))- goto fail;- a_offset = a->len - r_len;- b_bit_offset = (b->len - r_len) * LIMB_BITS + d;-- /* compute the bits before for the rounding */- carry = is_sub;- z = 0;- sub_mask = -is_sub;- i = r_len - tot_len;- while (i < 0) {- slimb_t ap, bp;- BOOL inflag;- - ap = a_offset + i;- bp = b_bit_offset + i * LIMB_BITS;- inflag = FALSE;- if (ap >= 0 && ap < a->len) {- v1 = a->tab[ap];- inflag = TRUE;- } else {- v1 = 0;- }- if (bp + LIMB_BITS > 0 && bp < (slimb_t)(b->len * LIMB_BITS)) {- v2 = get_bits(b->tab, b->len, bp);- inflag = TRUE;- } else {- v2 = 0;- }- if (!inflag) {- /* outside 'a' and 'b': go directly to the next value- inside a or b so that the running time does not- depend on the exponent difference */- i = 0;- if (ap < 0)- i = bf_min(i, -a_offset);- /* b_bit_offset + i * LIMB_BITS + LIMB_BITS >= 1- equivalent to - i >= ceil(-b_bit_offset + 1 - LIMB_BITS) / LIMB_BITS)- */- if (bp + LIMB_BITS <= 0)- i = bf_min(i, (-b_bit_offset) >> LIMB_LOG2_BITS);- } else {- i++;- }- v2 ^= sub_mask;- u = v1 + v2;- carry1 = u < v1;- u += carry;- carry = (u < carry) | carry1;- z |= u;- }- /* and the result */- for(i = 0; i < r_len; i++) {- v1 = get_limbz(a, a_offset + i);- v2 = get_bits(b->tab, b->len, b_bit_offset + i * LIMB_BITS);- v2 ^= sub_mask;- u = v1 + v2;- carry1 = u < v1;- u += carry;- carry = (u < carry) | carry1;- r->tab[i] = u;- }- /* set the extra bits for the rounding */- r->tab[0] |= (z != 0);-- /* carry is only possible in add case */- if (!is_sub && carry) {- if (bf_resize(r, r_len + 1))- goto fail;- r->tab[r_len] = 1;- r->expn += LIMB_BITS;- }- renorm:- ret = bf_normalize_and_round(r, prec, flags);- }- return ret;- fail:- bf_set_nan(r);- return BF_ST_MEM_ERROR;-}--static int __bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,- bf_flags_t flags)-{- return bf_add_internal(r, a, b, prec, flags, 0);-}--static int __bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,- bf_flags_t flags)-{- return bf_add_internal(r, a, b, prec, flags, 1);-}--limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2, - limb_t n, limb_t carry)-{- slimb_t i;- limb_t k, a, v, k1;- - k = carry;- for(i=0;i<n;i++) {- v = op1[i];- a = v + op2[i];- k1 = a < v;- a = a + k;- k = (a < k) | k1;- res[i] = a;- }- return k;-}--limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n)-{- size_t i;- limb_t k, a;-- k=b;- for(i=0;i<n;i++) {- if (k == 0)- break;- a = tab[i] + k;- k = (a < k);- tab[i] = a;- }- return k;-}--limb_t mp_sub(limb_t *res, const limb_t *op1, const limb_t *op2, - mp_size_t n, limb_t carry)-{- int i;- limb_t k, a, v, k1;- - k = carry;- for(i=0;i<n;i++) {- v = op1[i];- a = v - op2[i];- k1 = a > v;- v = a - k;- k = (v > a) | k1;- res[i] = v;- }- return k;-}--/* compute 0 - op2 */-static limb_t mp_neg(limb_t *res, const limb_t *op2, mp_size_t n, limb_t carry)-{- int i;- limb_t k, a, v, k1;- - k = carry;- for(i=0;i<n;i++) {- v = 0;- a = v - op2[i];- k1 = a > v;- v = a - k;- k = (v > a) | k1;- res[i] = v;- }- return k;-}--limb_t mp_sub_ui(limb_t *tab, limb_t b, mp_size_t n)-{- mp_size_t i;- limb_t k, a, v;- - k=b;- for(i=0;i<n;i++) {- v = tab[i];- a = v - k;- k = a > v;- tab[i] = a;- if (k == 0)- break;- }- return k;-}--/* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift). - 1 <= shift <= LIMB_BITS - 1 */-static limb_t mp_shr(limb_t *tab_r, const limb_t *tab, mp_size_t n, - int shift, limb_t high)-{- mp_size_t i;- limb_t l, a;-- assert(shift >= 1 && shift < LIMB_BITS);- l = high;- for(i = n - 1; i >= 0; i--) {- a = tab[i];- tab_r[i] = (a >> shift) | (l << (LIMB_BITS - shift));- l = a;- }- return l & (((limb_t)1 << shift) - 1);-}--/* tabr[] = taba[] * b + l. Return the high carry */-static limb_t mp_mul1(limb_t *tabr, const limb_t *taba, limb_t n, - limb_t b, limb_t l)-{- limb_t i;- dlimb_t t;-- for(i = 0; i < n; i++) {- t = (dlimb_t)taba[i] * (dlimb_t)b + l;- tabr[i] = t;- l = t >> LIMB_BITS;- }- return l;-}--/* tabr[] += taba[] * b, return the high word. */-static limb_t mp_add_mul1(limb_t *tabr, const limb_t *taba, limb_t n,- limb_t b)-{- limb_t i, l;- dlimb_t t;- - l = 0;- for(i = 0; i < n; i++) {- t = (dlimb_t)taba[i] * (dlimb_t)b + l + tabr[i];- tabr[i] = t;- l = t >> LIMB_BITS;- }- return l;-}--/* size of the result : op1_size + op2_size. */-static void mp_mul_basecase(limb_t *result, - const limb_t *op1, limb_t op1_size, - const limb_t *op2, limb_t op2_size) -{- limb_t i, r;- - result[op1_size] = mp_mul1(result, op1, op1_size, op2[0], 0);- for(i=1;i<op2_size;i++) {- r = mp_add_mul1(result + i, op1, op1_size, op2[i]);- result[i + op1_size] = r;- }-}--/* return 0 if OK, -1 if memory error */-/* XXX: change API so that result can be allocated */-int mp_mul(bf_context_t *s, limb_t *result, - const limb_t *op1, limb_t op1_size, - const limb_t *op2, limb_t op2_size) -{-#ifdef USE_FFT_MUL- if (unlikely(bf_min(op1_size, op2_size) >= FFT_MUL_THRESHOLD)) {- bf_t r_s, *r = &r_s;- r->tab = result;- /* XXX: optimize memory usage in API */- if (fft_mul(s, r, (limb_t *)op1, op1_size,- (limb_t *)op2, op2_size, FFT_MUL_R_NORESIZE))- return -1;- } else-#endif- {- mp_mul_basecase(result, op1, op1_size, op2, op2_size);- }- return 0;-}--/* tabr[] -= taba[] * b. Return the value to substract to the high- word. */-static limb_t mp_sub_mul1(limb_t *tabr, const limb_t *taba, limb_t n,- limb_t b)-{- limb_t i, l;- dlimb_t t;- - l = 0;- for(i = 0; i < n; i++) {- t = tabr[i] - (dlimb_t)taba[i] * (dlimb_t)b - l;- tabr[i] = t;- l = -(t >> LIMB_BITS);- }- return l;-}--/* WARNING: d must be >= 2^(LIMB_BITS-1) */-static inline limb_t udiv1norm_init(limb_t d)-{- limb_t a0, a1;- a1 = -d - 1;- a0 = -1;- return (((dlimb_t)a1 << LIMB_BITS) | a0) / d;-}--/* return the quotient and the remainder in '*pr'of 'a1*2^LIMB_BITS+a0- / d' with 0 <= a1 < d. */-static inline limb_t udiv1norm(limb_t *pr, limb_t a1, limb_t a0,- limb_t d, limb_t d_inv)-{- limb_t n1m, n_adj, q, r, ah;- dlimb_t a;- n1m = ((slimb_t)a0 >> (LIMB_BITS - 1));- n_adj = a0 + (n1m & d);- a = (dlimb_t)d_inv * (a1 - n1m) + n_adj;- q = (a >> LIMB_BITS) + a1;- /* compute a - q * r and update q so that the remainder is\- between 0 and d - 1 */- a = ((dlimb_t)a1 << LIMB_BITS) | a0;- a = a - (dlimb_t)q * d - d;- ah = a >> LIMB_BITS;- q += 1 + ah;- r = (limb_t)a + (ah & d);- *pr = r;- return q;-}--/* b must be >= 1 << (LIMB_BITS - 1) */-static limb_t mp_div1norm(limb_t *tabr, const limb_t *taba, limb_t n,- limb_t b, limb_t r)-{- slimb_t i;-- if (n >= UDIV1NORM_THRESHOLD) {- limb_t b_inv;- b_inv = udiv1norm_init(b);- for(i = n - 1; i >= 0; i--) {- tabr[i] = udiv1norm(&r, r, taba[i], b, b_inv);- }- } else {- dlimb_t a1;- for(i = n - 1; i >= 0; i--) {- a1 = ((dlimb_t)r << LIMB_BITS) | taba[i];- tabr[i] = a1 / b;- r = a1 % b;- }- }- return r;-}--static int mp_divnorm_large(bf_context_t *s, - limb_t *tabq, limb_t *taba, limb_t na, - const limb_t *tabb, limb_t nb);--/* base case division: divides taba[0..na-1] by tabb[0..nb-1]. tabb[nb- - 1] must be >= 1 << (LIMB_BITS - 1). na - nb must be >= 0. 'taba'- is modified and contains the remainder (nb limbs). tabq[0..na-nb]- contains the quotient with tabq[na - nb] <= 1. */-static int mp_divnorm(bf_context_t *s, limb_t *tabq, limb_t *taba, limb_t na, - const limb_t *tabb, limb_t nb)-{- limb_t r, a, c, q, v, b1, b1_inv, n, dummy_r;- slimb_t i, j;-- b1 = tabb[nb - 1];- if (nb == 1) {- taba[0] = mp_div1norm(tabq, taba, na, b1, 0);- return 0;- }- n = na - nb;- if (bf_min(n, nb) >= DIVNORM_LARGE_THRESHOLD) {- return mp_divnorm_large(s, tabq, taba, na, tabb, nb);- }- - if (n >= UDIV1NORM_THRESHOLD)- b1_inv = udiv1norm_init(b1);- else- b1_inv = 0;-- /* first iteration: the quotient is only 0 or 1 */- q = 1;- for(j = nb - 1; j >= 0; j--) {- if (taba[n + j] != tabb[j]) {- if (taba[n + j] < tabb[j])- q = 0;- break;- }- }- tabq[n] = q;- if (q) {- mp_sub(taba + n, taba + n, tabb, nb, 0);- }- - for(i = n - 1; i >= 0; i--) {- if (unlikely(taba[i + nb] >= b1)) {- q = -1;- } else if (b1_inv) {- q = udiv1norm(&dummy_r, taba[i + nb], taba[i + nb - 1], b1, b1_inv);- } else {- dlimb_t al;- al = ((dlimb_t)taba[i + nb] << LIMB_BITS) | taba[i + nb - 1];- q = al / b1;- r = al % b1;- }- r = mp_sub_mul1(taba + i, tabb, nb, q);-- v = taba[i + nb];- a = v - r;- c = (a > v);- taba[i + nb] = a;-- if (c != 0) {- /* negative result */- for(;;) {- q--;- c = mp_add(taba + i, taba + i, tabb, nb, 0);- /* propagate carry and test if positive result */- if (c != 0) {- if (++taba[i + nb] == 0) {- break;- }- }- }- }- tabq[i] = q;- }- return 0;-}--/* compute r=B^(2*n)/a such as a*r < B^(2*n) < a*r + 2 with n >= 1. 'a'- has n limbs with a[n-1] >= B/2 and 'r' has n+1 limbs with r[n] = 1.- - See Modern Computer Arithmetic by Richard P. Brent and Paul- Zimmermann, algorithm 3.5 */-int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n)-{- mp_size_t l, h, k, i;- limb_t *tabxh, *tabt, c, *tabu;- - if (n <= 2) {- /* return ceil(B^(2*n)/a) - 1 */- /* XXX: could avoid allocation */- tabu = bf_malloc(s, sizeof(limb_t) * (2 * n + 1));- tabt = bf_malloc(s, sizeof(limb_t) * (n + 2));- if (!tabt || !tabu)- goto fail;- for(i = 0; i < 2 * n; i++)- tabu[i] = 0;- tabu[2 * n] = 1;- if (mp_divnorm(s, tabt, tabu, 2 * n + 1, taba, n))- goto fail;- for(i = 0; i < n + 1; i++)- tabr[i] = tabt[i];- if (mp_scan_nz(tabu, n) == 0) {- /* only happens for a=B^n/2 */- mp_sub_ui(tabr, 1, n + 1);- }- } else {- l = (n - 1) / 2;- h = n - l;- /* n=2p -> l=p-1, h = p + 1, k = p + 3- n=2p+1-> l=p, h = p + 1; k = p + 2- */- tabt = bf_malloc(s, sizeof(limb_t) * (n + h + 1));- tabu = bf_malloc(s, sizeof(limb_t) * (n + 2 * h - l + 2));- if (!tabt || !tabu)- goto fail;- tabxh = tabr + l;- if (mp_recip(s, tabxh, taba + l, h))- goto fail;- if (mp_mul(s, tabt, taba, n, tabxh, h + 1)) /* n + h + 1 limbs */- goto fail;- while (tabt[n + h] != 0) {- mp_sub_ui(tabxh, 1, h + 1);- c = mp_sub(tabt, tabt, taba, n, 0);- mp_sub_ui(tabt + n, c, h + 1);- }- /* T = B^(n+h) - T */- mp_neg(tabt, tabt, n + h + 1, 0);- tabt[n + h]++;- if (mp_mul(s, tabu, tabt + l, n + h + 1 - l, tabxh, h + 1))- goto fail;- /* n + 2*h - l + 2 limbs */- k = 2 * h - l;- for(i = 0; i < l; i++)- tabr[i] = tabu[i + k];- mp_add(tabr + l, tabr + l, tabu + 2 * h, h, 0);- }- bf_free(s, tabt);- bf_free(s, tabu);- return 0;- fail:- bf_free(s, tabt);- bf_free(s, tabu);- return -1;-}--/* return -1, 0 or 1 */-static int mp_cmp(const limb_t *taba, const limb_t *tabb, mp_size_t n)-{- mp_size_t i;- for(i = n - 1; i >= 0; i--) {- if (taba[i] != tabb[i]) {- if (taba[i] < tabb[i])- return -1;- else- return 1;- }- }- return 0;-}--//#define DEBUG_DIVNORM_LARGE-//#define DEBUG_DIVNORM_LARGE2--/* subquadratic divnorm */-static int mp_divnorm_large(bf_context_t *s, - limb_t *tabq, limb_t *taba, limb_t na, - const limb_t *tabb, limb_t nb)-{- limb_t *tabb_inv, nq, *tabt, i, n;- nq = na - nb;-#ifdef DEBUG_DIVNORM_LARGE- printf("na=%d nb=%d nq=%d\n", (int)na, (int)nb, (int)nq);- mp_print_str("a", taba, na);- mp_print_str("b", tabb, nb);-#endif- assert(nq >= 1);- n = nq;- if (nq < nb)- n++; - tabb_inv = bf_malloc(s, sizeof(limb_t) * (n + 1));- tabt = bf_malloc(s, sizeof(limb_t) * 2 * (n + 1));- if (!tabb_inv || !tabt)- goto fail;-- if (n >= nb) {- for(i = 0; i < n - nb; i++)- tabt[i] = 0;- for(i = 0; i < nb; i++)- tabt[i + n - nb] = tabb[i];- } else {- /* truncate B: need to increment it so that the approximate- inverse is smaller that the exact inverse */- for(i = 0; i < n; i++)- tabt[i] = tabb[i + nb - n];- if (mp_add_ui(tabt, 1, n)) {- /* tabt = B^n : tabb_inv = B^n */- memset(tabb_inv, 0, n * sizeof(limb_t));- tabb_inv[n] = 1;- goto recip_done;- }- }- if (mp_recip(s, tabb_inv, tabt, n))- goto fail;- recip_done:- /* Q=A*B^-1 */- if (mp_mul(s, tabt, tabb_inv, n + 1, taba + na - (n + 1), n + 1))- goto fail;- - for(i = 0; i < nq + 1; i++)- tabq[i] = tabt[i + 2 * (n + 1) - (nq + 1)];-#ifdef DEBUG_DIVNORM_LARGE- mp_print_str("q", tabq, nq + 1);-#endif-- bf_free(s, tabt);- bf_free(s, tabb_inv);- tabb_inv = NULL;- - /* R=A-B*Q */- tabt = bf_malloc(s, sizeof(limb_t) * (na + 1));- if (!tabt)- goto fail;- if (mp_mul(s, tabt, tabq, nq + 1, tabb, nb))- goto fail;- /* we add one more limb for the result */- mp_sub(taba, taba, tabt, nb + 1, 0);- bf_free(s, tabt);- /* the approximated quotient is smaller than than the exact one,- hence we may have to increment it */-#ifdef DEBUG_DIVNORM_LARGE2- int cnt = 0;- static int cnt_max;-#endif- for(;;) {- if (taba[nb] == 0 && mp_cmp(taba, tabb, nb) < 0)- break;- taba[nb] -= mp_sub(taba, taba, tabb, nb, 0);- mp_add_ui(tabq, 1, nq + 1);-#ifdef DEBUG_DIVNORM_LARGE2- cnt++;-#endif- }-#ifdef DEBUG_DIVNORM_LARGE2- if (cnt > cnt_max) {- cnt_max = cnt;- printf("\ncnt=%d nq=%d nb=%d\n", cnt_max, (int)nq, (int)nb);- }-#endif- return 0;- fail:- bf_free(s, tabb_inv);- bf_free(s, tabt);- return -1;-}--int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,- bf_flags_t flags)-{- int ret, r_sign;-- if (a->len < b->len) {- const bf_t *tmp = a;- a = b;- b = tmp;- }- r_sign = a->sign ^ b->sign;- /* here b->len <= a->len */- if (b->len == 0) {- if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {- bf_set_nan(r);- ret = 0;- } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_INF) {- if ((a->expn == BF_EXP_INF && b->expn == BF_EXP_ZERO) ||- (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_INF)) {- bf_set_nan(r);- ret = BF_ST_INVALID_OP;- } else {- bf_set_inf(r, r_sign);- ret = 0;- }- } else {- bf_set_zero(r, r_sign);- ret = 0;- }- } else {- bf_t tmp, *r1 = NULL;- limb_t a_len, b_len, precl;- limb_t *a_tab, *b_tab;- - a_len = a->len;- b_len = b->len;- - if ((flags & BF_RND_MASK) == BF_RNDF) {- /* faithful rounding does not require using the full inputs */- precl = (prec + 2 + LIMB_BITS - 1) / LIMB_BITS;- a_len = bf_min(a_len, precl);- b_len = bf_min(b_len, precl);- }- a_tab = a->tab + a->len - a_len;- b_tab = b->tab + b->len - b_len;- -#ifdef USE_FFT_MUL- if (b_len >= FFT_MUL_THRESHOLD) {- int mul_flags = 0;- if (r == a)- mul_flags |= FFT_MUL_R_OVERLAP_A;- if (r == b)- mul_flags |= FFT_MUL_R_OVERLAP_B;- if (fft_mul(r->ctx, r, a_tab, a_len, b_tab, b_len, mul_flags))- goto fail;- } else-#endif- {- if (r == a || r == b) {- bf_init(r->ctx, &tmp);- r1 = r;- r = &tmp;- }- if (bf_resize(r, a_len + b_len)) {- fail:- bf_set_nan(r);- ret = BF_ST_MEM_ERROR;- goto done;- }- mp_mul_basecase(r->tab, a_tab, a_len, b_tab, b_len);- }- r->sign = r_sign;- r->expn = a->expn + b->expn;- ret = bf_normalize_and_round(r, prec, flags);- done:- if (r == &tmp)- bf_move(r1, &tmp);- }- return ret;-}--/* multiply 'r' by 2^e */-int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags)-{- slimb_t e_max;- if (r->len == 0)- return 0;- e_max = ((limb_t)1 << BF_EXT_EXP_BITS_MAX) - 1;- e = bf_max(e, -e_max);- e = bf_min(e, e_max);- r->expn += e;- return __bf_round(r, prec, flags, r->len, 0);-}--/* Return e such as a=m*2^e with m odd integer. return 0 if a is zero,- Infinite or Nan. */-slimb_t bf_get_exp_min(const bf_t *a)-{- slimb_t i;- limb_t v;- int k;- - for(i = 0; i < a->len; i++) {- v = a->tab[i];- if (v != 0) {- k = ctz(v);- return a->expn - (a->len - i) * LIMB_BITS + k;- }- }- return 0;-}--/* a and b must be finite numbers with a >= 0 and b > 0. 'q' is the- integer defined as floor(a/b) and r = a - q * b. */-static void bf_tdivremu(bf_t *q, bf_t *r,- const bf_t *a, const bf_t *b)-{- if (bf_cmpu(a, b) < 0) {- bf_set_ui(q, 0);- bf_set(r, a);- } else {- bf_div(q, a, b, bf_max(a->expn - b->expn + 1, 2), BF_RNDZ);- bf_rint(q, BF_RNDZ);- bf_mul(r, q, b, BF_PREC_INF, BF_RNDZ);- bf_sub(r, a, r, BF_PREC_INF, BF_RNDZ);- }-}--static int __bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,- bf_flags_t flags)-{- bf_context_t *s = r->ctx;- int ret, r_sign;- limb_t n, nb, precl;- - r_sign = a->sign ^ b->sign;- if (a->expn >= BF_EXP_INF || b->expn >= BF_EXP_INF) {- if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {- bf_set_nan(r);- return 0;- } else if (a->expn == BF_EXP_INF && b->expn == BF_EXP_INF) {- bf_set_nan(r);- return BF_ST_INVALID_OP;- } else if (a->expn == BF_EXP_INF) {- bf_set_inf(r, r_sign);- return 0;- } else {- bf_set_zero(r, r_sign);- return 0;- }- } else if (a->expn == BF_EXP_ZERO) {- if (b->expn == BF_EXP_ZERO) {- bf_set_nan(r);- return BF_ST_INVALID_OP;- } else {- bf_set_zero(r, r_sign);- return 0;- }- } else if (b->expn == BF_EXP_ZERO) {- bf_set_inf(r, r_sign);- return BF_ST_DIVIDE_ZERO;- }-- /* number of limbs of the quotient (2 extra bits for rounding) */- precl = (prec + 2 + LIMB_BITS - 1) / LIMB_BITS;- nb = b->len;- n = bf_max(a->len, precl);- - {- limb_t *taba, na;- slimb_t d;- - na = n + nb;- taba = bf_malloc(s, (na + 1) * sizeof(limb_t));- if (!taba)- goto fail;- d = na - a->len;- memset(taba, 0, d * sizeof(limb_t));- memcpy(taba + d, a->tab, a->len * sizeof(limb_t));- if (bf_resize(r, n + 1))- goto fail;- if (mp_divnorm(s, r->tab, taba, na, b->tab, nb))- goto fail;- - /* see if non zero remainder */- if (mp_scan_nz(taba, nb))- r->tab[0] |= 1;- bf_free(r->ctx, taba);- r->expn = a->expn - b->expn + LIMB_BITS;- r->sign = r_sign;- ret = bf_normalize_and_round(r, prec, flags);- }- return ret;- fail:- bf_set_nan(r);- return BF_ST_MEM_ERROR;-}--/* division and remainder. - - rnd_mode is the rounding mode for the quotient. The additional- rounding mode BF_RND_EUCLIDIAN is supported.-- 'q' is an integer. 'r' is rounded with prec and flags (prec can be- BF_PREC_INF).-*/-int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,- limb_t prec, bf_flags_t flags, int rnd_mode)-{- bf_t a1_s, *a1 = &a1_s;- bf_t b1_s, *b1 = &b1_s;- int q_sign, ret;- BOOL is_ceil, is_rndn;- - assert(q != a && q != b);- assert(r != a && r != b);- assert(q != r);- - if (a->len == 0 || b->len == 0) {- bf_set_zero(q, 0);- if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {- bf_set_nan(r);- return 0;- } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_ZERO) {- bf_set_nan(r);- return BF_ST_INVALID_OP;- } else {- bf_set(r, a);- return bf_round(r, prec, flags);- }- }-- q_sign = a->sign ^ b->sign;- is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);- switch(rnd_mode) {- default:- case BF_RNDZ:- case BF_RNDN:- case BF_RNDNA:- is_ceil = FALSE;- break;- case BF_RNDD:- is_ceil = q_sign;- break;- case BF_RNDU:- is_ceil = q_sign ^ 1;- break;- case BF_RNDA:- is_ceil = TRUE;- break;- case BF_DIVREM_EUCLIDIAN:- is_ceil = a->sign;- break;- }-- a1->expn = a->expn;- a1->tab = a->tab;- a1->len = a->len;- a1->sign = 0;- - b1->expn = b->expn;- b1->tab = b->tab;- b1->len = b->len;- b1->sign = 0;-- /* XXX: could improve to avoid having a large 'q' */- bf_tdivremu(q, r, a1, b1);- if (bf_is_nan(q) || bf_is_nan(r))- goto fail;-- if (r->len != 0) {- if (is_rndn) {- int res;- b1->expn--;- res = bf_cmpu(r, b1);- b1->expn++;- if (res > 0 ||- (res == 0 &&- (rnd_mode == BF_RNDNA ||- get_bit(q->tab, q->len, q->len * LIMB_BITS - q->expn)))) {- goto do_sub_r;- }- } else if (is_ceil) {- do_sub_r:- ret = bf_add_si(q, q, 1, BF_PREC_INF, BF_RNDZ);- ret |= bf_sub(r, r, b1, BF_PREC_INF, BF_RNDZ);- if (ret & BF_ST_MEM_ERROR)- goto fail;- }- }-- r->sign ^= a->sign;- q->sign = q_sign;- return bf_round(r, prec, flags);- fail:- bf_set_nan(q);- bf_set_nan(r);- return BF_ST_MEM_ERROR;-}--int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,- bf_flags_t flags, int rnd_mode)-{- bf_t q_s, *q = &q_s;- int ret;- - bf_init(r->ctx, q);- ret = bf_divrem(q, r, a, b, prec, flags, rnd_mode);- bf_delete(q);- return ret;-}--static inline int bf_get_limb(slimb_t *pres, const bf_t *a, int flags)-{-#if LIMB_BITS == 32- return bf_get_int32(pres, a, flags);-#else- return bf_get_int64(pres, a, flags);-#endif-}--int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,- bf_flags_t flags, int rnd_mode)-{- bf_t q_s, *q = &q_s;- int ret;- - bf_init(r->ctx, q);- ret = bf_divrem(q, r, a, b, prec, flags, rnd_mode);- bf_get_limb(pq, q, BF_GET_INT_MOD);- bf_delete(q);- return ret;-}--static __maybe_unused inline limb_t mul_mod(limb_t a, limb_t b, limb_t m)-{- dlimb_t t;- t = (dlimb_t)a * (dlimb_t)b;- return t % m;-}--#if defined(USE_MUL_CHECK)-static limb_t mp_mod1(const limb_t *tab, limb_t n, limb_t m, limb_t r)-{- slimb_t i;- dlimb_t t;-- for(i = n - 1; i >= 0; i--) {- t = ((dlimb_t)r << LIMB_BITS) | tab[i];- r = t % m;- }- return r;-}-#endif--static const uint16_t sqrt_table[192] = {-128,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,144,145,146,147,148,149,150,150,151,152,153,154,155,155,156,157,158,159,160,160,161,162,163,163,164,165,166,167,167,168,169,170,170,171,172,173,173,174,175,176,176,177,178,178,179,180,181,181,182,183,183,184,185,185,186,187,187,188,189,189,190,191,192,192,193,193,194,195,195,196,197,197,198,199,199,200,201,201,202,203,203,204,204,205,206,206,207,208,208,209,209,210,211,211,212,212,213,214,214,215,215,216,217,217,218,218,219,219,220,221,221,222,222,223,224,224,225,225,226,226,227,227,228,229,229,230,230,231,231,232,232,233,234,234,235,235,236,236,237,237,238,238,239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252,252,253,253,254,254,255,-};--/* a >= 2^(LIMB_BITS - 2). Return (s, r) with s=floor(sqrt(a)) and- r=a-s^2. 0 <= r <= 2 * s */-static limb_t mp_sqrtrem1(limb_t *pr, limb_t a)-{- limb_t s1, r1, s, r, q, u, num;- - /* use a table for the 16 -> 8 bit sqrt */- s1 = sqrt_table[(a >> (LIMB_BITS - 8)) - 64];- r1 = (a >> (LIMB_BITS - 16)) - s1 * s1;- if (r1 > 2 * s1) {- r1 -= 2 * s1 + 1;- s1++;- }- - /* one iteration to get a 32 -> 16 bit sqrt */- num = (r1 << 8) | ((a >> (LIMB_BITS - 32 + 8)) & 0xff);- q = num / (2 * s1); /* q <= 2^8 */- u = num % (2 * s1);- s = (s1 << 8) + q;- r = (u << 8) | ((a >> (LIMB_BITS - 32)) & 0xff);- r -= q * q;- if ((slimb_t)r < 0) {- s--;- r += 2 * s + 1;- }--#if LIMB_BITS == 64- s1 = s;- r1 = r;- /* one more iteration for 64 -> 32 bit sqrt */- num = (r1 << 16) | ((a >> (LIMB_BITS - 64 + 16)) & 0xffff);- q = num / (2 * s1); /* q <= 2^16 */- u = num % (2 * s1);- s = (s1 << 16) + q;- r = (u << 16) | ((a >> (LIMB_BITS - 64)) & 0xffff);- r -= q * q;- if ((slimb_t)r < 0) {- s--;- r += 2 * s + 1;- }-#endif- *pr = r;- return s;-}--/* return floor(sqrt(a)) */-limb_t bf_isqrt(limb_t a)-{- limb_t s, r;- int k;-- if (a == 0)- return 0;- k = clz(a) & ~1;- s = mp_sqrtrem1(&r, a << k);- s >>= (k >> 1);- return s;-}--static limb_t mp_sqrtrem2(limb_t *tabs, limb_t *taba)-{- limb_t s1, r1, s, q, u, a0, a1;- dlimb_t r, num;- int l;-- a0 = taba[0];- a1 = taba[1];- s1 = mp_sqrtrem1(&r1, a1);- l = LIMB_BITS / 2;- num = ((dlimb_t)r1 << l) | (a0 >> l);- q = num / (2 * s1);- u = num % (2 * s1);- s = (s1 << l) + q;- r = ((dlimb_t)u << l) | (a0 & (((limb_t)1 << l) - 1));- if (unlikely((q >> l) != 0))- r -= (dlimb_t)1 << LIMB_BITS; /* special case when q=2^l */- else- r -= q * q;- if ((slimb_t)(r >> LIMB_BITS) < 0) {- s--;- r += 2 * (dlimb_t)s + 1;- }- tabs[0] = s;- taba[0] = r;- return r >> LIMB_BITS;-}--//#define DEBUG_SQRTREM--/* tmp_buf must contain (n / 2 + 1 limbs). *prh contains the highest- limb of the remainder. */-static int mp_sqrtrem_rec(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n,- limb_t *tmp_buf, limb_t *prh)-{- limb_t l, h, rh, ql, qh, c, i;- - if (n == 1) {- *prh = mp_sqrtrem2(tabs, taba);- return 0;- }-#ifdef DEBUG_SQRTREM- mp_print_str("a", taba, 2 * n);-#endif- l = n / 2;- h = n - l;- if (mp_sqrtrem_rec(s, tabs + l, taba + 2 * l, h, tmp_buf, &qh))- return -1;-#ifdef DEBUG_SQRTREM- mp_print_str("s1", tabs + l, h);- mp_print_str_h("r1", taba + 2 * l, h, qh);- mp_print_str_h("r2", taba + l, n, qh);-#endif- - /* the remainder is in taba + 2 * l. Its high bit is in qh */- if (qh) {- mp_sub(taba + 2 * l, taba + 2 * l, tabs + l, h, 0);- }- /* instead of dividing by 2*s, divide by s (which is normalized)- and update q and r */- if (mp_divnorm(s, tmp_buf, taba + l, n, tabs + l, h))- return -1;- qh += tmp_buf[l];- for(i = 0; i < l; i++)- tabs[i] = tmp_buf[i];- ql = mp_shr(tabs, tabs, l, 1, qh & 1);- qh = qh >> 1; /* 0 or 1 */- if (ql)- rh = mp_add(taba + l, taba + l, tabs + l, h, 0);- else- rh = 0;-#ifdef DEBUG_SQRTREM- mp_print_str_h("q", tabs, l, qh);- mp_print_str_h("u", taba + l, h, rh);-#endif- - mp_add_ui(tabs + l, qh, h);-#ifdef DEBUG_SQRTREM- mp_print_str_h("s2", tabs, n, sh);-#endif- - /* q = qh, tabs[l - 1 ... 0], r = taba[n - 1 ... l] */- /* subtract q^2. if qh = 1 then q = B^l, so we can take shortcuts */- if (qh) {- c = qh;- } else {- if (mp_mul(s, taba + n, tabs, l, tabs, l))- return -1;- c = mp_sub(taba, taba, taba + n, 2 * l, 0);- }- rh -= mp_sub_ui(taba + 2 * l, c, n - 2 * l);- if ((slimb_t)rh < 0) {- mp_sub_ui(tabs, 1, n);- rh += mp_add_mul1(taba, tabs, n, 2);- rh += mp_add_ui(taba, 1, n);- }- *prh = rh;- return 0;-}--/* 'taba' has 2*n limbs with n >= 1 and taba[2*n-1] >= 2 ^ (LIMB_BITS- - 2). Return (s, r) with s=floor(sqrt(a)) and r=a-s^2. 0 <= r <= 2- * s. tabs has n limbs. r is returned in the lower n limbs of- taba. Its r[n] is the returned value of the function. */-/* Algorithm from the article "Karatsuba Square Root" by Paul Zimmermann and- inspirated from its GMP implementation */-int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n)-{- limb_t tmp_buf1[8];- limb_t *tmp_buf;- mp_size_t n2;- int ret;- n2 = n / 2 + 1;- if (n2 <= countof(tmp_buf1)) {- tmp_buf = tmp_buf1;- } else {- tmp_buf = bf_malloc(s, sizeof(limb_t) * n2);- if (!tmp_buf)- return -1;- }- ret = mp_sqrtrem_rec(s, tabs, taba, n, tmp_buf, taba + n);- if (tmp_buf != tmp_buf1)- bf_free(s, tmp_buf);- return ret;-}--/* Integer square root with remainder. 'a' must be an integer. r =- floor(sqrt(a)) and rem = a - r^2. BF_ST_INEXACT is set if the result- is inexact. 'rem' can be NULL if the remainder is not needed. */-int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a)-{- int ret;- - if (a->len == 0) {- if (a->expn == BF_EXP_NAN) {- bf_set_nan(r);- } else if (a->expn == BF_EXP_INF && a->sign) {- goto invalid_op;- } else {- bf_set(r, a);- }- if (rem1)- bf_set_ui(rem1, 0);- ret = 0;- } else if (a->sign) {- invalid_op:- bf_set_nan(r);- if (rem1)- bf_set_ui(rem1, 0);- ret = BF_ST_INVALID_OP;- } else {- bf_t rem_s, *rem;- - bf_sqrt(r, a, (a->expn + 1) / 2, BF_RNDZ);- bf_rint(r, BF_RNDZ);- /* see if the result is exact by computing the remainder */- if (rem1) {- rem = rem1;- } else {- rem = &rem_s;- bf_init(r->ctx, rem);- }- /* XXX: could avoid recomputing the remainder */- bf_mul(rem, r, r, BF_PREC_INF, BF_RNDZ);- bf_neg(rem);- bf_add(rem, rem, a, BF_PREC_INF, BF_RNDZ);- if (bf_is_nan(rem)) {- ret = BF_ST_MEM_ERROR;- goto done;- }- if (rem->len != 0) {- ret = BF_ST_INEXACT;- } else {- ret = 0;- }- done:- if (!rem1)- bf_delete(rem);- }- return ret;-}--int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)-{- bf_context_t *s = a->ctx;- int ret;-- assert(r != a);-- if (a->len == 0) {- if (a->expn == BF_EXP_NAN) {- bf_set_nan(r);- } else if (a->expn == BF_EXP_INF && a->sign) {- goto invalid_op;- } else {- bf_set(r, a);- }- ret = 0;- } else if (a->sign) {- invalid_op:- bf_set_nan(r);- ret = BF_ST_INVALID_OP;- } else {- limb_t *a1;- slimb_t n, n1;- limb_t res;- - /* convert the mantissa to an integer with at least 2 *- prec + 4 bits */- n = (2 * (prec + 2) + 2 * LIMB_BITS - 1) / (2 * LIMB_BITS);- if (bf_resize(r, n))- goto fail;- a1 = bf_malloc(s, sizeof(limb_t) * 2 * n);- if (!a1)- goto fail;- n1 = bf_min(2 * n, a->len);- memset(a1, 0, (2 * n - n1) * sizeof(limb_t));- memcpy(a1 + 2 * n - n1, a->tab + a->len - n1, n1 * sizeof(limb_t));- if (a->expn & 1) {- res = mp_shr(a1, a1, 2 * n, 1, 0);- } else {- res = 0;- }- if (mp_sqrtrem(s, r->tab, a1, n)) {- bf_free(s, a1);- goto fail;- }- if (!res) {- res = mp_scan_nz(a1, n + 1);- }- bf_free(s, a1);- if (!res) {- res = mp_scan_nz(a->tab, a->len - n1);- }- if (res != 0)- r->tab[0] |= 1;- r->sign = 0;- r->expn = (a->expn + 1) >> 1;- ret = bf_round(r, prec, flags);- }- return ret;- fail:- bf_set_nan(r);- return BF_ST_MEM_ERROR;-}--static no_inline int bf_op2(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,- bf_flags_t flags, bf_op2_func_t *func)-{- bf_t tmp;- int ret;- - if (r == a || r == b) {- bf_init(r->ctx, &tmp);- ret = func(&tmp, a, b, prec, flags);- bf_move(r, &tmp);- } else {- ret = func(r, a, b, prec, flags);- }- return ret;-}--int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,- bf_flags_t flags)-{- return bf_op2(r, a, b, prec, flags, __bf_add);-}--int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,- bf_flags_t flags)-{- return bf_op2(r, a, b, prec, flags, __bf_sub);-}--int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,- bf_flags_t flags)-{- return bf_op2(r, a, b, prec, flags, __bf_div);-}--int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec,- bf_flags_t flags)-{- bf_t b;- int ret;- bf_init(r->ctx, &b);- ret = bf_set_ui(&b, b1);- ret |= bf_mul(r, a, &b, prec, flags);- bf_delete(&b);- return ret;-}--int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec,- bf_flags_t flags)-{- bf_t b;- int ret;- bf_init(r->ctx, &b);- ret = bf_set_si(&b, b1);- ret |= bf_mul(r, a, &b, prec, flags);- bf_delete(&b);- return ret;-}--int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec,- bf_flags_t flags)-{- bf_t b;- int ret;- - bf_init(r->ctx, &b);- ret = bf_set_si(&b, b1);- ret |= bf_add(r, a, &b, prec, flags);- bf_delete(&b);- return ret;-}--static int bf_pow_ui(bf_t *r, const bf_t *a, limb_t b, limb_t prec,- bf_flags_t flags)-{- int ret, n_bits, i;- - assert(r != a);- if (b == 0)- return bf_set_ui(r, 1);- ret = bf_set(r, a);- n_bits = LIMB_BITS - clz(b);- for(i = n_bits - 2; i >= 0; i--) {- ret |= bf_mul(r, r, r, prec, flags);- if ((b >> i) & 1)- ret |= bf_mul(r, r, a, prec, flags);- }- return ret;-}--static int bf_pow_ui_ui(bf_t *r, limb_t a1, limb_t b,- limb_t prec, bf_flags_t flags)-{- bf_t a;- int ret;- - if (a1 == 10 && b <= LIMB_DIGITS) {- /* use precomputed powers. We do not round at this point- because we expect the caller to do it */- ret = bf_set_ui(r, mp_pow_dec[b]);- } else {- bf_init(r->ctx, &a);- ret = bf_set_ui(&a, a1);- ret |= bf_pow_ui(r, &a, b, prec, flags);- bf_delete(&a);- }- return ret;-}--/* convert to integer (infinite precision) */-int bf_rint(bf_t *r, int rnd_mode)-{- return bf_round(r, 0, rnd_mode | BF_FLAG_RADPNT_PREC);-}--/* logical operations */-#define BF_LOGIC_OR 0-#define BF_LOGIC_XOR 1-#define BF_LOGIC_AND 2--static inline limb_t bf_logic_op1(limb_t a, limb_t b, int op)-{- switch(op) {- case BF_LOGIC_OR:- return a | b;- case BF_LOGIC_XOR:- return a ^ b;- default:- case BF_LOGIC_AND:- return a & b;- }-}--static int bf_logic_op(bf_t *r, const bf_t *a1, const bf_t *b1, int op)-{- bf_t b1_s, a1_s, *a, *b;- limb_t a_sign, b_sign, r_sign;- slimb_t l, i, a_bit_offset, b_bit_offset;- limb_t v1, v2, v1_mask, v2_mask, r_mask;- int ret;- - assert(r != a1 && r != b1);-- if (a1->expn <= 0)- a_sign = 0; /* minus zero is considered as positive */- else- a_sign = a1->sign;-- if (b1->expn <= 0)- b_sign = 0; /* minus zero is considered as positive */- else- b_sign = b1->sign;- - if (a_sign) {- a = &a1_s;- bf_init(r->ctx, a);- if (bf_add_si(a, a1, 1, BF_PREC_INF, BF_RNDZ)) {- b = NULL;- goto fail;- }- } else {- a = (bf_t *)a1;- }-- if (b_sign) {- b = &b1_s;- bf_init(r->ctx, b);- if (bf_add_si(b, b1, 1, BF_PREC_INF, BF_RNDZ))- goto fail;- } else {- b = (bf_t *)b1;- }- - r_sign = bf_logic_op1(a_sign, b_sign, op);- if (op == BF_LOGIC_AND && r_sign == 0) {- /* no need to compute extra zeros for and */- if (a_sign == 0 && b_sign == 0)- l = bf_min(a->expn, b->expn);- else if (a_sign == 0)- l = a->expn;- else- l = b->expn;- } else {- l = bf_max(a->expn, b->expn);- }- /* Note: a or b can be zero */- l = (bf_max(l, 1) + LIMB_BITS - 1) / LIMB_BITS;- if (bf_resize(r, l))- goto fail;- a_bit_offset = a->len * LIMB_BITS - a->expn;- b_bit_offset = b->len * LIMB_BITS - b->expn;- v1_mask = -a_sign;- v2_mask = -b_sign;- r_mask = -r_sign;- for(i = 0; i < l; i++) {- v1 = get_bits(a->tab, a->len, a_bit_offset + i * LIMB_BITS) ^ v1_mask;- v2 = get_bits(b->tab, b->len, b_bit_offset + i * LIMB_BITS) ^ v2_mask;- r->tab[i] = bf_logic_op1(v1, v2, op) ^ r_mask;- }- r->expn = l * LIMB_BITS;- r->sign = r_sign;- bf_normalize_and_round(r, BF_PREC_INF, BF_RNDZ); /* cannot fail */- if (r_sign) {- if (bf_add_si(r, r, -1, BF_PREC_INF, BF_RNDZ))- goto fail;- }- ret = 0;- done:- if (a == &a1_s)- bf_delete(a);- if (b == &b1_s)- bf_delete(b);- return ret;- fail:- bf_set_nan(r);- ret = BF_ST_MEM_ERROR;- goto done;-}--/* 'a' and 'b' must be integers. Return 0 or BF_ST_MEM_ERROR. */-int bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b)-{- return bf_logic_op(r, a, b, BF_LOGIC_OR);-}--/* 'a' and 'b' must be integers. Return 0 or BF_ST_MEM_ERROR. */-int bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b)-{- return bf_logic_op(r, a, b, BF_LOGIC_XOR);-}--/* 'a' and 'b' must be integers. Return 0 or BF_ST_MEM_ERROR. */-int bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b)-{- return bf_logic_op(r, a, b, BF_LOGIC_AND);-}--/* conversion between fixed size types */--typedef union {- double d;- uint64_t u;-} Float64Union;--int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode)-{- Float64Union u;- int e, ret;- uint64_t m;- - ret = 0;- if (a->expn == BF_EXP_NAN) {- u.u = 0x7ff8000000000000; /* quiet nan */- } else {- bf_t b_s, *b = &b_s;- - bf_init(a->ctx, b);- bf_set(b, a);- if (bf_is_finite(b)) {- ret = bf_round(b, 53, rnd_mode | BF_FLAG_SUBNORMAL | bf_set_exp_bits(11));- }- if (b->expn == BF_EXP_INF) {- e = (1 << 11) - 1;- m = 0;- } else if (b->expn == BF_EXP_ZERO) {- e = 0;- m = 0;- } else {- e = b->expn + 1023 - 1;-#if LIMB_BITS == 32- if (b->len == 2) {- m = ((uint64_t)b->tab[1] << 32) | b->tab[0];- } else {- m = ((uint64_t)b->tab[0] << 32);- }-#else- m = b->tab[0];-#endif- if (e <= 0) {- /* subnormal */- m = m >> (12 - e);- e = 0;- } else {- m = (m << 1) >> 12;- }- }- u.u = m | ((uint64_t)e << 52) | ((uint64_t)b->sign << 63);- bf_delete(b);- }- *pres = u.d;- return ret;-}--int bf_set_float64(bf_t *a, double d)-{- Float64Union u;- uint64_t m;- int shift, e, sgn;- - u.d = d;- sgn = u.u >> 63;- e = (u.u >> 52) & ((1 << 11) - 1);- m = u.u & (((uint64_t)1 << 52) - 1);- if (e == ((1 << 11) - 1)) {- if (m != 0) {- bf_set_nan(a);- } else {- bf_set_inf(a, sgn);- }- } else if (e == 0) {- if (m == 0) {- bf_set_zero(a, sgn);- } else {- /* subnormal number */- m <<= 12;- shift = clz64(m);- m <<= shift;- e = -shift;- goto norm;- }- } else {- m = (m << 11) | ((uint64_t)1 << 63);- norm:- a->expn = e - 1023 + 1;-#if LIMB_BITS == 32- if (bf_resize(a, 2))- goto fail;- a->tab[0] = m;- a->tab[1] = m >> 32;-#else- if (bf_resize(a, 1))- goto fail;- a->tab[0] = m;-#endif- a->sign = sgn;- }- return 0;-fail:- bf_set_nan(a);- return BF_ST_MEM_ERROR;-}--/* The rounding mode is always BF_RNDZ. Return BF_ST_OVERFLOW if there- is an overflow and 0 otherwise. */-int bf_get_int32(int *pres, const bf_t *a, int flags)-{- uint32_t v;- int ret;- if (a->expn >= BF_EXP_INF) {- ret = 0;- if (flags & BF_GET_INT_MOD) {- v = 0;- } else if (a->expn == BF_EXP_INF) {- v = (uint32_t)INT32_MAX + a->sign;- /* XXX: return overflow ? */- } else {- v = INT32_MAX;- }- } else if (a->expn <= 0) {- v = 0;- ret = 0;- } else if (a->expn <= 31) {- v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);- if (a->sign)- v = -v;- ret = 0;- } else if (!(flags & BF_GET_INT_MOD)) {- ret = BF_ST_OVERFLOW;- if (a->sign) {- v = (uint32_t)INT32_MAX + 1;- if (a->expn == 32 && - (a->tab[a->len - 1] >> (LIMB_BITS - 32)) == v) {- ret = 0;- }- } else {- v = INT32_MAX;- }- } else {- v = get_bits(a->tab, a->len, a->len * LIMB_BITS - a->expn); - if (a->sign)- v = -v;- ret = 0;- }- *pres = v;- return ret;-}--/* The rounding mode is always BF_RNDZ. Return BF_ST_OVERFLOW if there- is an overflow and 0 otherwise. */-int bf_get_int64(int64_t *pres, const bf_t *a, int flags)-{- uint64_t v;- int ret;- if (a->expn >= BF_EXP_INF) {- ret = 0;- if (flags & BF_GET_INT_MOD) {- v = 0;- } else if (a->expn == BF_EXP_INF) {- v = (uint64_t)INT64_MAX + a->sign;- } else {- v = INT64_MAX;- }- } else if (a->expn <= 0) {- v = 0;- ret = 0;- } else if (a->expn <= 63) {-#if LIMB_BITS == 32- if (a->expn <= 32)- v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);- else- v = (((uint64_t)a->tab[a->len - 1] << 32) |- get_limbz(a, a->len - 2)) >> (64 - a->expn);-#else- v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);-#endif- if (a->sign)- v = -v;- ret = 0;- } else if (!(flags & BF_GET_INT_MOD)) {- ret = BF_ST_OVERFLOW;- if (a->sign) {- uint64_t v1;- v = (uint64_t)INT64_MAX + 1;- if (a->expn == 64) {- v1 = a->tab[a->len - 1];-#if LIMB_BITS == 32- v1 = (v1 << 32) | get_limbz(a, a->len - 2);-#endif- if (v1 == v)- ret = 0;- }- } else {- v = INT64_MAX;- }- } else {- slimb_t bit_pos = a->len * LIMB_BITS - a->expn;- v = get_bits(a->tab, a->len, bit_pos); -#if LIMB_BITS == 32- v |= (uint64_t)get_bits(a->tab, a->len, bit_pos + 32) << 32;-#endif- if (a->sign)- v = -v;- ret = 0;- }- *pres = v;- return ret;-}--/* base conversion from radix */--static const uint8_t digits_per_limb_table[BF_RADIX_MAX - 1] = {-#if LIMB_BITS == 32-32,20,16,13,12,11,10,10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,-#else-64,40,32,27,24,22,21,20,19,18,17,17,16,16,16,15,15,15,14,14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12,-#endif-};--static limb_t get_limb_radix(int radix)-{- int i, k;- limb_t radixl;- - k = digits_per_limb_table[radix - 2];- radixl = radix;- for(i = 1; i < k; i++)- radixl *= radix;- return radixl;-}--/* return != 0 if error */-static int bf_integer_from_radix_rec(bf_t *r, const limb_t *tab,- limb_t n, int level, limb_t n0,- limb_t radix, bf_t *pow_tab)-{- int ret;- if (n == 1) {- ret = bf_set_ui(r, tab[0]);- } else {- bf_t T_s, *T = &T_s, *B;- limb_t n1, n2;- - n2 = (((n0 * 2) >> (level + 1)) + 1) / 2;- n1 = n - n2;- // printf("level=%d n0=%ld n1=%ld n2=%ld\n", level, n0, n1, n2);- B = &pow_tab[level];- if (B->len == 0) {- ret = bf_pow_ui_ui(B, radix, n2, BF_PREC_INF, BF_RNDZ);- if (ret)- return ret;- }- ret = bf_integer_from_radix_rec(r, tab + n2, n1, level + 1, n0,- radix, pow_tab);- if (ret)- return ret;- ret = bf_mul(r, r, B, BF_PREC_INF, BF_RNDZ);- if (ret)- return ret;- bf_init(r->ctx, T);- ret = bf_integer_from_radix_rec(T, tab, n2, level + 1, n0,- radix, pow_tab);- if (!ret)- ret = bf_add(r, r, T, BF_PREC_INF, BF_RNDZ);- bf_delete(T);- }- return ret;- // bf_print_str(" r=", r);-}--/* return 0 if OK != 0 if memory error */-static int bf_integer_from_radix(bf_t *r, const limb_t *tab,- limb_t n, limb_t radix)-{- bf_context_t *s = r->ctx;- int pow_tab_len, i, ret;- limb_t radixl;- bf_t *pow_tab;- - radixl = get_limb_radix(radix);- pow_tab_len = ceil_log2(n) + 2; /* XXX: check */- pow_tab = bf_malloc(s, sizeof(pow_tab[0]) * pow_tab_len);- if (!pow_tab)- return -1;- for(i = 0; i < pow_tab_len; i++)- bf_init(r->ctx, &pow_tab[i]);- ret = bf_integer_from_radix_rec(r, tab, n, 0, n, radixl, pow_tab);- for(i = 0; i < pow_tab_len; i++) {- bf_delete(&pow_tab[i]);- }- bf_free(s, pow_tab);- return ret;-}--/* compute and round T * radix^expn. */-int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,- slimb_t expn, limb_t prec, bf_flags_t flags)-{- int ret, expn_sign, overflow;- slimb_t e, extra_bits, prec1, ziv_extra_bits;- bf_t B_s, *B = &B_s;-- if (T->len == 0) {- return bf_set(r, T);- } else if (expn == 0) {- ret = bf_set(r, T);- ret |= bf_round(r, prec, flags);- return ret;- }-- e = expn;- expn_sign = 0;- if (e < 0) {- e = -e;- expn_sign = 1;- }- bf_init(r->ctx, B);- if (prec == BF_PREC_INF) {- /* infinite precision: only used if the result is known to be exact */- ret = bf_pow_ui_ui(B, radix, e, BF_PREC_INF, BF_RNDN);- if (expn_sign) {- ret |= bf_div(r, T, B, T->len * LIMB_BITS, BF_RNDN);- } else {- ret |= bf_mul(r, T, B, BF_PREC_INF, BF_RNDN);- }- } else {- ziv_extra_bits = 16;- for(;;) {- prec1 = prec + ziv_extra_bits;- /* XXX: correct overflow/underflow handling */- /* XXX: rigorous error analysis needed */- extra_bits = ceil_log2(e) * 2 + 1;- ret = bf_pow_ui_ui(B, radix, e, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);- overflow = !bf_is_finite(B);- /* XXX: if bf_pow_ui_ui returns an exact result, can stop- after the next operation */- if (expn_sign)- ret |= bf_div(r, T, B, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);- else- ret |= bf_mul(r, T, B, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);- if (ret & BF_ST_MEM_ERROR)- break;- if ((ret & BF_ST_INEXACT) &&- !bf_can_round(r, prec, flags & BF_RND_MASK, prec1) &&- !overflow) {- /* and more precision and retry */- ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);- } else {- /* XXX: need to use __bf_round() to pass the inexact- flag for the subnormal case */- ret = bf_round(r, prec, flags) | (ret & BF_ST_INEXACT);- break;- }- }- }- bf_delete(B);- return ret;-}--static inline int to_digit(int c)-{- if (c >= '0' && c <= '9')- return c - '0';- else if (c >= 'A' && c <= 'Z')- return c - 'A' + 10;- else if (c >= 'a' && c <= 'z')- return c - 'a' + 10;- else- return 36;-}--/* add a limb at 'pos' and decrement pos. new space is created if- needed. Return 0 if OK, -1 if memory error */-static int bf_add_limb(bf_t *a, slimb_t *ppos, limb_t v)-{- slimb_t pos;- pos = *ppos;- if (unlikely(pos < 0)) {- limb_t new_size, d, *new_tab;- new_size = bf_max(a->len + 1, a->len * 3 / 2);- new_tab = bf_realloc(a->ctx, a->tab, sizeof(limb_t) * new_size);- if (!new_tab)- return -1;- a->tab = new_tab;- d = new_size - a->len;- memmove(a->tab + d, a->tab, a->len * sizeof(limb_t));- a->len = new_size;- pos += d;- }- a->tab[pos--] = v;- *ppos = pos;- return 0;-}--static int bf_tolower(int c)-{- if (c >= 'A' && c <= 'Z')- c = c - 'A' + 'a';- return c;-}--static int strcasestart(const char *str, const char *val, const char **ptr)-{- const char *p, *q;- p = str;- q = val;- while (*q != '\0') {- if (bf_tolower(*p) != *q)- return 0;- p++;- q++;- }- if (ptr)- *ptr = p;- return 1;-}--static int bf_atof_internal(bf_t *r, slimb_t *pexponent,- const char *str, const char **pnext, int radix,- limb_t prec, bf_flags_t flags, BOOL is_dec)-{- const char *p, *p_start;- int is_neg, radix_bits, exp_is_neg, ret, digits_per_limb, shift;- limb_t cur_limb;- slimb_t pos, expn, int_len, digit_count;- BOOL has_decpt, is_bin_exp;- bf_t a_s, *a;- - *pexponent = 0;- p = str;- if (!(flags & BF_ATOF_NO_NAN_INF) && radix <= 16 &&- strcasestart(p, "nan", &p)) {- bf_set_nan(r);- ret = 0;- goto done;- }- is_neg = 0;- - if (p[0] == '+') {- p++;- p_start = p;- } else if (p[0] == '-') {- is_neg = 1;- p++;- p_start = p;- } else {- p_start = p;- }- if (p[0] == '0') {- if ((p[1] == 'x' || p[1] == 'X') &&- (radix == 0 || radix == 16) &&- !(flags & BF_ATOF_NO_HEX)) {- radix = 16;- p += 2;- } else if ((p[1] == 'o' || p[1] == 'O') &&- radix == 0 && (flags & BF_ATOF_BIN_OCT)) {- p += 2;- radix = 8;- } else if ((p[1] == 'b' || p[1] == 'B') &&- radix == 0 && (flags & BF_ATOF_BIN_OCT)) {- p += 2;- radix = 2;- } else {- goto no_prefix;- }- /* there must be a digit after the prefix */- if (to_digit((uint8_t)*p) >= radix) {- bf_set_nan(r);- ret = 0;- goto done;- }- no_prefix: ;- } else {- if (!(flags & BF_ATOF_NO_NAN_INF) && radix <= 16 &&- strcasestart(p, "inf", &p)) {- bf_set_inf(r, is_neg);- ret = 0;- goto done;- }- }- - if (radix == 0)- radix = 10;- if (is_dec) {- assert(radix == 10);- radix_bits = 0;- a = r;- } else if ((radix & (radix - 1)) != 0) {- radix_bits = 0; /* base is not a power of two */- a = &a_s;- bf_init(r->ctx, a);- } else {- radix_bits = ceil_log2(radix);- a = r;- }-- /* skip leading zeros */- /* XXX: could also skip zeros after the decimal point */- while (*p == '0')- p++;-- if (radix_bits) {- shift = digits_per_limb = LIMB_BITS;- } else {- radix_bits = 0;- shift = digits_per_limb = digits_per_limb_table[radix - 2];- }- cur_limb = 0;- bf_resize(a, 1);- pos = 0;- has_decpt = FALSE;- int_len = digit_count = 0;- for(;;) {- limb_t c;- if (*p == '.' && (p > p_start || to_digit(p[1]) < radix)) {- if (has_decpt)- break;- has_decpt = TRUE;- int_len = digit_count;- p++;- }- c = to_digit(*p);- if (c >= radix)- break;- digit_count++;- p++;- if (radix_bits) {- shift -= radix_bits;- if (shift <= 0) {- cur_limb |= c >> (-shift);- if (bf_add_limb(a, &pos, cur_limb))- goto mem_error;- if (shift < 0)- cur_limb = c << (LIMB_BITS + shift);- else- cur_limb = 0;- shift += LIMB_BITS;- } else {- cur_limb |= c << shift;- }- } else {- cur_limb = cur_limb * radix + c;- shift--;- if (shift == 0) {- if (bf_add_limb(a, &pos, cur_limb))- goto mem_error;- shift = digits_per_limb;- cur_limb = 0;- }- }- }- if (!has_decpt)- int_len = digit_count;-- /* add the last limb and pad with zeros */- if (shift != digits_per_limb) {- if (radix_bits == 0) {- while (shift != 0) {- cur_limb *= radix;- shift--;- }- }- if (bf_add_limb(a, &pos, cur_limb)) {- mem_error:- ret = BF_ST_MEM_ERROR;- if (!radix_bits)- bf_delete(a);- bf_set_nan(r);- goto done;- }- }- - /* reset the next limbs to zero (we prefer to reallocate in the- renormalization) */- memset(a->tab, 0, (pos + 1) * sizeof(limb_t));-- if (p == p_start) {- ret = 0;- if (!radix_bits)- bf_delete(a);- bf_set_nan(r);- goto done;- }-- /* parse the exponent, if any */- expn = 0;- is_bin_exp = FALSE;- if (((radix == 10 && (*p == 'e' || *p == 'E')) ||- (radix != 10 && (*p == '@' ||- (radix_bits && (*p == 'p' || *p == 'P'))))) &&- p > p_start) {- is_bin_exp = (*p == 'p' || *p == 'P');- p++;- exp_is_neg = 0;- if (*p == '+') {- p++;- } else if (*p == '-') {- exp_is_neg = 1;- p++;- }- for(;;) {- int c;- c = to_digit(*p);- if (c >= 10)- break;- if (unlikely(expn > ((BF_RAW_EXP_MAX - 2 - 9) / 10))) {- /* exponent overflow */- if (exp_is_neg) {- bf_set_zero(r, is_neg);- ret = BF_ST_UNDERFLOW | BF_ST_INEXACT;- } else {- bf_set_inf(r, is_neg);- ret = BF_ST_OVERFLOW | BF_ST_INEXACT;- }- goto done;- }- p++;- expn = expn * 10 + c;- }- if (exp_is_neg)- expn = -expn;- }- if (is_dec) {- a->expn = expn + int_len;- a->sign = is_neg;- ret = bfdec_normalize_and_round((bfdec_t *)a, prec, flags);- } else if (radix_bits) {- /* XXX: may overflow */- if (!is_bin_exp)- expn *= radix_bits; - a->expn = expn + (int_len * radix_bits);- a->sign = is_neg;- ret = bf_normalize_and_round(a, prec, flags);- } else {- limb_t l;- pos++;- l = a->len - pos; /* number of limbs */- if (l == 0) {- bf_set_zero(r, is_neg);- ret = 0;- } else {- bf_t T_s, *T = &T_s;-- expn -= l * digits_per_limb - int_len;- bf_init(r->ctx, T);- if (bf_integer_from_radix(T, a->tab + pos, l, radix)) {- bf_set_nan(r);- ret = BF_ST_MEM_ERROR;- } else {- T->sign = is_neg;- if (flags & BF_ATOF_EXPONENT) {- /* return the exponent */- *pexponent = expn;- ret = bf_set(r, T);- } else {- ret = bf_mul_pow_radix(r, T, radix, expn, prec, flags);- }- }- bf_delete(T);- }- bf_delete(a);- }- done:- if (pnext)- *pnext = p;- return ret;-}--/* - Return (status, n, exp). 'status' is the floating point status. 'n'- is the parsed number. -- If (flags & BF_ATOF_EXPONENT) and if the radix is not a power of- two, the parsed number is equal to r *- (*pexponent)^radix. Otherwise *pexponent = 0.-*/-int bf_atof2(bf_t *r, slimb_t *pexponent,- const char *str, const char **pnext, int radix,- limb_t prec, bf_flags_t flags)-{- return bf_atof_internal(r, pexponent, str, pnext, radix, prec, flags,- FALSE);-}--int bf_atof(bf_t *r, const char *str, const char **pnext, int radix,- limb_t prec, bf_flags_t flags)-{- slimb_t dummy_exp;- return bf_atof_internal(r, &dummy_exp, str, pnext, radix, prec, flags, FALSE);-}--/* base conversion to radix */--#if LIMB_BITS == 64-#define RADIXL_10 UINT64_C(10000000000000000000)-#else-#define RADIXL_10 UINT64_C(1000000000)-#endif--static const uint32_t inv_log2_radix[BF_RADIX_MAX - 1][LIMB_BITS / 32 + 1] = {-#if LIMB_BITS == 32-{ 0x80000000, 0x00000000,},-{ 0x50c24e60, 0xd4d4f4a7,},-{ 0x40000000, 0x00000000,},-{ 0x372068d2, 0x0a1ee5ca,},-{ 0x3184648d, 0xb8153e7a,},-{ 0x2d983275, 0x9d5369c4,},-{ 0x2aaaaaaa, 0xaaaaaaab,},-{ 0x28612730, 0x6a6a7a54,},-{ 0x268826a1, 0x3ef3fde6,},-{ 0x25001383, 0xbac8a744,},-{ 0x23b46706, 0x82c0c709,},-{ 0x229729f1, 0xb2c83ded,},-{ 0x219e7ffd, 0xa5ad572b,},-{ 0x20c33b88, 0xda7c29ab,},-{ 0x20000000, 0x00000000,},-{ 0x1f50b57e, 0xac5884b3,},-{ 0x1eb22cc6, 0x8aa6e26f,},-{ 0x1e21e118, 0x0c5daab2,},-{ 0x1d9dcd21, 0x439834e4,},-{ 0x1d244c78, 0x367a0d65,},-{ 0x1cb40589, 0xac173e0c,},-{ 0x1c4bd95b, 0xa8d72b0d,},-{ 0x1bead768, 0x98f8ce4c,},-{ 0x1b903469, 0x050f72e5,},-{ 0x1b3b433f, 0x2eb06f15,},-{ 0x1aeb6f75, 0x9c46fc38,},-{ 0x1aa038eb, 0x0e3bfd17,},-{ 0x1a593062, 0xb38d8c56,},-{ 0x1a15f4c3, 0x2b95a2e6,},-{ 0x19d630dc, 0xcc7ddef9,},-{ 0x19999999, 0x9999999a,},-{ 0x195fec80, 0x8a609431,},-{ 0x1928ee7b, 0x0b4f22f9,},-{ 0x18f46acf, 0x8c06e318,},-{ 0x18c23246, 0xdc0a9f3d,},-#else-{ 0x80000000, 0x00000000, 0x00000000,},-{ 0x50c24e60, 0xd4d4f4a7, 0x021f57bc,},-{ 0x40000000, 0x00000000, 0x00000000,},-{ 0x372068d2, 0x0a1ee5ca, 0x19ea911b,},-{ 0x3184648d, 0xb8153e7a, 0x7fc2d2e1,},-{ 0x2d983275, 0x9d5369c4, 0x4dec1661,},-{ 0x2aaaaaaa, 0xaaaaaaaa, 0xaaaaaaab,},-{ 0x28612730, 0x6a6a7a53, 0x810fabde,},-{ 0x268826a1, 0x3ef3fde6, 0x23e2566b,},-{ 0x25001383, 0xbac8a744, 0x385a3349,},-{ 0x23b46706, 0x82c0c709, 0x3f891718,},-{ 0x229729f1, 0xb2c83ded, 0x15fba800,},-{ 0x219e7ffd, 0xa5ad572a, 0xe169744b,},-{ 0x20c33b88, 0xda7c29aa, 0x9bddee52,},-{ 0x20000000, 0x00000000, 0x00000000,},-{ 0x1f50b57e, 0xac5884b3, 0x70e28eee,},-{ 0x1eb22cc6, 0x8aa6e26f, 0x06d1a2a2,},-{ 0x1e21e118, 0x0c5daab1, 0x81b4f4bf,},-{ 0x1d9dcd21, 0x439834e3, 0x81667575,},-{ 0x1d244c78, 0x367a0d64, 0xc8204d6d,},-{ 0x1cb40589, 0xac173e0c, 0x3b7b16ba,},-{ 0x1c4bd95b, 0xa8d72b0d, 0x5879f25a,},-{ 0x1bead768, 0x98f8ce4c, 0x66cc2858,},-{ 0x1b903469, 0x050f72e5, 0x0cf5488e,},-{ 0x1b3b433f, 0x2eb06f14, 0x8c89719c,},-{ 0x1aeb6f75, 0x9c46fc37, 0xab5fc7e9,},-{ 0x1aa038eb, 0x0e3bfd17, 0x1bd62080,},-{ 0x1a593062, 0xb38d8c56, 0x7998ab45,},-{ 0x1a15f4c3, 0x2b95a2e6, 0x46aed6a0,},-{ 0x19d630dc, 0xcc7ddef9, 0x5aadd61b,},-{ 0x19999999, 0x99999999, 0x9999999a,},-{ 0x195fec80, 0x8a609430, 0xe1106014,},-{ 0x1928ee7b, 0x0b4f22f9, 0x5f69791d,},-{ 0x18f46acf, 0x8c06e318, 0x4d2aeb2c,},-{ 0x18c23246, 0xdc0a9f3d, 0x3fe16970,},-#endif-};--static const limb_t log2_radix[BF_RADIX_MAX - 1] = {-#if LIMB_BITS == 32-0x20000000,-0x32b80347,-0x40000000,-0x4a4d3c26,-0x52b80347,-0x59d5d9fd,-0x60000000,-0x6570068e,-0x6a4d3c26,-0x6eb3a9f0,-0x72b80347,-0x766a008e,-0x79d5d9fd,-0x7d053f6d,-0x80000000,-0x82cc7edf,-0x8570068e,-0x87ef05ae,-0x8a4d3c26,-0x8c8ddd45,-0x8eb3a9f0,-0x90c10501,-0x92b80347,-0x949a784c,-0x966a008e,-0x982809d6,-0x99d5d9fd,-0x9b74948f,-0x9d053f6d,-0x9e88c6b3,-0xa0000000,-0xa16bad37,-0xa2cc7edf,-0xa4231623,-0xa570068e,-#else-0x2000000000000000,-0x32b803473f7ad0f4,-0x4000000000000000,-0x4a4d3c25e68dc57f,-0x52b803473f7ad0f4,-0x59d5d9fd5010b366,-0x6000000000000000,-0x6570068e7ef5a1e8,-0x6a4d3c25e68dc57f,-0x6eb3a9f01975077f,-0x72b803473f7ad0f4,-0x766a008e4788cbcd,-0x79d5d9fd5010b366,-0x7d053f6d26089673,-0x8000000000000000,-0x82cc7edf592262d0,-0x8570068e7ef5a1e8,-0x87ef05ae409a0289,-0x8a4d3c25e68dc57f,-0x8c8ddd448f8b845a,-0x8eb3a9f01975077f,-0x90c10500d63aa659,-0x92b803473f7ad0f4,-0x949a784bcd1b8afe,-0x966a008e4788cbcd,-0x982809d5be7072dc,-0x99d5d9fd5010b366,-0x9b74948f5532da4b,-0x9d053f6d26089673,-0x9e88c6b3626a72aa,-0xa000000000000000,-0xa16bad3758efd873,-0xa2cc7edf592262d0,-0xa4231623369e78e6,-0xa570068e7ef5a1e8,-#endif-};--/* compute floor(a*b) or ceil(a*b) with b = log2(radix) or- b=1/log2(radix). For is_inv = 0, strict accuracy is not guaranteed- when radix is not a power of two. */-slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv,- int is_ceil1)-{- int is_neg;- limb_t a;- BOOL is_ceil;-- is_ceil = is_ceil1;- a = a1;- if (a1 < 0) {- a = -a;- is_neg = 1;- } else {- is_neg = 0;- }- is_ceil ^= is_neg;- if ((radix & (radix - 1)) == 0) {- int radix_bits;- /* radix is a power of two */- radix_bits = ceil_log2(radix);- if (is_inv) {- if (is_ceil)- a += radix_bits - 1;- a = a / radix_bits;- } else {- a = a * radix_bits;- }- } else {- const uint32_t *tab;- limb_t b0, b1;- dlimb_t t;- - if (is_inv) {- tab = inv_log2_radix[radix - 2];-#if LIMB_BITS == 32- b1 = tab[0];- b0 = tab[1];-#else- b1 = ((limb_t)tab[0] << 32) | tab[1];- b0 = (limb_t)tab[2] << 32;-#endif- t = (dlimb_t)b0 * (dlimb_t)a;- t = (dlimb_t)b1 * (dlimb_t)a + (t >> LIMB_BITS);- a = t >> (LIMB_BITS - 1);- } else {- b0 = log2_radix[radix - 2];- t = (dlimb_t)b0 * (dlimb_t)a;- a = t >> (LIMB_BITS - 3);- }- /* a = floor(result) and 'result' cannot be an integer */- a += is_ceil;- }- if (is_neg)- a = -a;- return a;-}--/* 'n' is the number of output limbs */-static void bf_integer_to_radix_rec(bf_t *pow_tab,- limb_t *out, const bf_t *a, limb_t n,- int level, limb_t n0, limb_t radixl,- unsigned int radixl_bits)-{- limb_t n1, n2, q_prec;- assert(n >= 1);- if (n == 1) {- out[0] = get_bits(a->tab, a->len, a->len * LIMB_BITS - a->expn);- } else if (n == 2) {- dlimb_t t;- slimb_t pos;- pos = a->len * LIMB_BITS - a->expn;- t = ((dlimb_t)get_bits(a->tab, a->len, pos + LIMB_BITS) << LIMB_BITS) |- get_bits(a->tab, a->len, pos);- if (likely(radixl == RADIXL_10)) {- /* use division by a constant when possible */- out[0] = t % RADIXL_10;- out[1] = t / RADIXL_10;- } else {- out[0] = t % radixl;- out[1] = t / radixl;- }- } else {- bf_t Q, R, *B, *B_inv;- int q_add;- bf_init(a->ctx, &Q);- bf_init(a->ctx, &R);- n2 = (((n0 * 2) >> (level + 1)) + 1) / 2;- n1 = n - n2;- B = &pow_tab[2 * level];- B_inv = &pow_tab[2 * level + 1];- if (B->len == 0) {- /* compute BASE^n2 */- bf_pow_ui_ui(B, radixl, n2, BF_PREC_INF, BF_RNDZ);- /* we use enough bits for the maximum possible 'n1' value,- i.e. n2 + 1 */- bf_set_ui(&R, 1);- bf_div(B_inv, &R, B, (n2 + 1) * radixl_bits + 2, BF_RNDN);- }- // printf("%d: n1=% " PRId64 " n2=%" PRId64 "\n", level, n1, n2);- q_prec = n1 * radixl_bits;- bf_mul(&Q, a, B_inv, q_prec, BF_RNDN);- bf_rint(&Q, BF_RNDZ);- - bf_mul(&R, &Q, B, BF_PREC_INF, BF_RNDZ);- bf_sub(&R, a, &R, BF_PREC_INF, BF_RNDZ);- /* adjust if necessary */- q_add = 0;- while (R.sign && R.len != 0) {- bf_add(&R, &R, B, BF_PREC_INF, BF_RNDZ);- q_add--;- }- while (bf_cmpu(&R, B) >= 0) {- bf_sub(&R, &R, B, BF_PREC_INF, BF_RNDZ);- q_add++;- }- if (q_add != 0) {- bf_add_si(&Q, &Q, q_add, BF_PREC_INF, BF_RNDZ);- }- bf_integer_to_radix_rec(pow_tab, out + n2, &Q, n1, level + 1, n0,- radixl, radixl_bits);- bf_integer_to_radix_rec(pow_tab, out, &R, n2, level + 1, n0,- radixl, radixl_bits);- bf_delete(&Q);- bf_delete(&R);- }-}--static void bf_integer_to_radix(bf_t *r, const bf_t *a, limb_t radixl)-{- bf_context_t *s = r->ctx;- limb_t r_len;- bf_t *pow_tab;- int i, pow_tab_len;- - r_len = r->len;- pow_tab_len = (ceil_log2(r_len) + 2) * 2; /* XXX: check */- pow_tab = bf_malloc(s, sizeof(pow_tab[0]) * pow_tab_len);- for(i = 0; i < pow_tab_len; i++)- bf_init(r->ctx, &pow_tab[i]);-- bf_integer_to_radix_rec(pow_tab, r->tab, a, r_len, 0, r_len, radixl,- ceil_log2(radixl));-- for(i = 0; i < pow_tab_len; i++) {- bf_delete(&pow_tab[i]);- }- bf_free(s, pow_tab);-}--/* a must be >= 0. 'P' is the wanted number of digits in radix- 'radix'. 'r' is the mantissa represented as an integer. *pE- contains the exponent. Return != 0 if memory error. */-static int bf_convert_to_radix(bf_t *r, slimb_t *pE,- const bf_t *a, int radix,- limb_t P, bf_rnd_t rnd_mode,- BOOL is_fixed_exponent)-{- slimb_t E, e, prec, extra_bits, ziv_extra_bits, prec0;- bf_t B_s, *B = &B_s;- int e_sign, ret, res;- - if (a->len == 0) {- /* zero case */- *pE = 0;- return bf_set(r, a);- }-- if (is_fixed_exponent) {- E = *pE;- } else {- /* compute the new exponent */- E = 1 + bf_mul_log2_radix(a->expn - 1, radix, TRUE, FALSE);- }- // bf_print_str("a", a);- // printf("E=%ld P=%ld radix=%d\n", E, P, radix);- - for(;;) {- e = P - E;- e_sign = 0;- if (e < 0) {- e = -e;- e_sign = 1;- }- /* Note: precision for log2(radix) is not critical here */- prec0 = bf_mul_log2_radix(P, radix, FALSE, TRUE);- ziv_extra_bits = 16;- for(;;) {- prec = prec0 + ziv_extra_bits;- /* XXX: rigorous error analysis needed */- extra_bits = ceil_log2(e) * 2 + 1;- ret = bf_pow_ui_ui(r, radix, e, prec + extra_bits,- BF_RNDN | BF_FLAG_EXT_EXP);- if (!e_sign)- ret |= bf_mul(r, r, a, prec + extra_bits,- BF_RNDN | BF_FLAG_EXT_EXP);- else- ret |= bf_div(r, a, r, prec + extra_bits,- BF_RNDN | BF_FLAG_EXT_EXP);- if (ret & BF_ST_MEM_ERROR)- return BF_ST_MEM_ERROR;- /* if the result is not exact, check that it can be safely- rounded to an integer */- if ((ret & BF_ST_INEXACT) &&- !bf_can_round(r, r->expn, rnd_mode, prec)) {- /* and more precision and retry */- ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);- continue;- } else {- ret = bf_rint(r, rnd_mode);- if (ret & BF_ST_MEM_ERROR)- return BF_ST_MEM_ERROR;- break;- }- }- if (is_fixed_exponent)- break;- /* check that the result is < B^P */- /* XXX: do a fast approximate test first ? */- bf_init(r->ctx, B);- ret = bf_pow_ui_ui(B, radix, P, BF_PREC_INF, BF_RNDZ);- if (ret) {- bf_delete(B);- return ret;- }- res = bf_cmpu(r, B);- bf_delete(B);- if (res < 0)- break;- /* try a larger exponent */- E++;- }- *pE = E;- return 0;-}--static void limb_to_a(char *buf, limb_t n, unsigned int radix, int len)-{- int digit, i;-- if (radix == 10) {- /* specific case with constant divisor */- for(i = len - 1; i >= 0; i--) {- digit = (limb_t)n % 10;- n = (limb_t)n / 10;- buf[i] = digit + '0';- }- } else {- for(i = len - 1; i >= 0; i--) {- digit = (limb_t)n % radix;- n = (limb_t)n / radix;- if (digit < 10)- digit += '0';- else- digit += 'a' - 10;- buf[i] = digit;- }- }-}--/* for power of 2 radixes */-static void limb_to_a2(char *buf, limb_t n, unsigned int radix_bits, int len)-{- int digit, i;- unsigned int mask;-- mask = (1 << radix_bits) - 1;- for(i = len - 1; i >= 0; i--) {- digit = n & mask;- n >>= radix_bits;- if (digit < 10)- digit += '0';- else- digit += 'a' - 10;- buf[i] = digit;- }-}--/* 'a' must be an integer if the is_dec = FALSE or if the radix is not- a power of two. A dot is added before the 'dot_pos' digit. dot_pos- = n_digits does not display the dot. 0 <= dot_pos <=- n_digits. n_digits >= 1. */-static void output_digits(DynBuf *s, const bf_t *a1, int radix, limb_t n_digits,- limb_t dot_pos, BOOL is_dec)-{- limb_t i, v, l;- slimb_t pos, pos_incr;- int digits_per_limb, buf_pos, radix_bits, first_buf_pos;- char buf[65];- bf_t a_s, *a;-- if (is_dec) {- digits_per_limb = LIMB_DIGITS;- a = (bf_t *)a1;- radix_bits = 0;- pos = a->len;- pos_incr = 1;- first_buf_pos = 0;- } else if ((radix & (radix - 1)) == 0) {- a = (bf_t *)a1;- radix_bits = ceil_log2(radix);- digits_per_limb = LIMB_BITS / radix_bits;- pos_incr = digits_per_limb * radix_bits;- /* digits are aligned relative to the radix point */- pos = a->len * LIMB_BITS + smod(-a->expn, radix_bits);- first_buf_pos = 0;- } else {- limb_t n, radixl;-- digits_per_limb = digits_per_limb_table[radix - 2];- radixl = get_limb_radix(radix);- a = &a_s;- bf_init(a1->ctx, a);- n = (n_digits + digits_per_limb - 1) / digits_per_limb;- bf_resize(a, n);- bf_integer_to_radix(a, a1, radixl);- radix_bits = 0;- pos = n;- pos_incr = 1;- first_buf_pos = pos * digits_per_limb - n_digits;- }- buf_pos = digits_per_limb;- i = 0;- while (i < n_digits) {- if (buf_pos == digits_per_limb) {- pos -= pos_incr;- if (radix_bits == 0) {- v = get_limbz(a, pos);- limb_to_a(buf, v, radix, digits_per_limb);- } else {- v = get_bits(a->tab, a->len, pos);- limb_to_a2(buf, v, radix_bits, digits_per_limb);- }- buf_pos = first_buf_pos;- first_buf_pos = 0;- }- if (i < dot_pos) {- l = dot_pos;- } else {- if (i == dot_pos)- dbuf_putc(s, '.');- l = n_digits;- }- l = bf_min(digits_per_limb - buf_pos, l - i);- dbuf_put(s, (uint8_t *)(buf + buf_pos), l);- buf_pos += l;- i += l;- }- if (a != a1)- bf_delete(a);-}--static void *bf_dbuf_realloc(void *opaque, void *ptr, size_t size)-{- bf_context_t *s = opaque;- return bf_realloc(s, ptr, size);-}--/* return the length in bytes. A trailing '\0' is added */-static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix,- limb_t prec, bf_flags_t flags, BOOL is_dec)-{- bf_context_t *ctx = a2->ctx;- DynBuf s_s, *s = &s_s;- int radix_bits;- - // bf_print_str("ftoa", a2);- // printf("radix=%d\n", radix);- dbuf_init2(s, ctx, bf_dbuf_realloc);- if (a2->expn == BF_EXP_NAN) {- dbuf_putstr(s, "NaN");- } else {- if (a2->sign)- dbuf_putc(s, '-');- if (a2->expn == BF_EXP_INF) {- if (flags & BF_FTOA_JS_QUIRKS)- dbuf_putstr(s, "Infinity");- else- dbuf_putstr(s, "Inf");- } else {- int fmt, ret;- slimb_t n_digits, n, i, n_max, n1;- bf_t a1_s, *a1 = &a1_s;-- if ((radix & (radix - 1)) != 0)- radix_bits = 0;- else- radix_bits = ceil_log2(radix);-- fmt = flags & BF_FTOA_FORMAT_MASK;- bf_init(ctx, a1);- if (fmt == BF_FTOA_FORMAT_FRAC) {- if (is_dec || radix_bits != 0) {- if (bf_set(a1, a2))- goto fail1;-#ifdef USE_BF_DEC- if (is_dec) {- if (bfdec_round((bfdec_t *)a1, prec, (flags & BF_RND_MASK) | BF_FLAG_RADPNT_PREC) & BF_ST_MEM_ERROR)- goto fail1;- n = a1->expn;- } else-#endif- {- if (bf_round(a1, prec * radix_bits, (flags & BF_RND_MASK) | BF_FLAG_RADPNT_PREC) & BF_ST_MEM_ERROR)- goto fail1;- n = ceil_div(a1->expn, radix_bits);- }- if (flags & BF_FTOA_ADD_PREFIX) {- if (radix == 16)- dbuf_putstr(s, "0x");- else if (radix == 8)- dbuf_putstr(s, "0o");- else if (radix == 2)- dbuf_putstr(s, "0b");- }- if (a1->expn == BF_EXP_ZERO) {- dbuf_putstr(s, "0");- if (prec > 0) {- dbuf_putstr(s, ".");- for(i = 0; i < prec; i++) {- dbuf_putc(s, '0');- }- }- } else {- n_digits = prec + n;- if (n <= 0) {- /* 0.x */- dbuf_putstr(s, "0.");- for(i = 0; i < -n; i++) {- dbuf_putc(s, '0');- }- if (n_digits > 0) {- output_digits(s, a1, radix, n_digits, n_digits, is_dec);- }- } else {- output_digits(s, a1, radix, n_digits, n, is_dec);- }- }- } else {- size_t pos, start;- bf_t a_s, *a = &a_s;-- /* make a positive number */- a->tab = a2->tab;- a->len = a2->len;- a->expn = a2->expn;- a->sign = 0;- - /* one more digit for the rounding */- n = 1 + bf_mul_log2_radix(bf_max(a->expn, 0), radix, TRUE, TRUE);- n_digits = n + prec;- n1 = n;- if (bf_convert_to_radix(a1, &n1, a, radix, n_digits,- flags & BF_RND_MASK, TRUE))- goto fail1;- start = s->size;- output_digits(s, a1, radix, n_digits, n, is_dec);- /* remove leading zeros because we allocated one more digit */- pos = start;- while ((pos + 1) < s->size && s->buf[pos] == '0' &&- s->buf[pos + 1] != '.')- pos++;- if (pos > start) {- memmove(s->buf + start, s->buf + pos, s->size - pos);- s->size -= (pos - start);- }- }- } else {-#ifdef USE_BF_DEC- if (is_dec) {- if (bf_set(a1, a2))- goto fail1;- if (fmt == BF_FTOA_FORMAT_FIXED) {- n_digits = prec;- n_max = n_digits;- if (bfdec_round((bfdec_t *)a1, prec, (flags & BF_RND_MASK)) & BF_ST_MEM_ERROR)- goto fail1;- } else {- /* prec is ignored */- prec = n_digits = a1->len * LIMB_DIGITS;- /* remove the trailing zero digits */- while (n_digits > 1 &&- get_digit(a1->tab, a1->len, prec - n_digits) == 0) {- n_digits--;- }- n_max = n_digits + 4;- }- n = a1->expn;- } else-#endif- if (radix_bits != 0) {- if (bf_set(a1, a2))- goto fail1;- if (fmt == BF_FTOA_FORMAT_FIXED) {- slimb_t prec_bits;- n_digits = prec;- n_max = n_digits;- /* align to the radix point */- prec_bits = prec * radix_bits -- smod(-a1->expn, radix_bits);- if (bf_round(a1, prec_bits,- (flags & BF_RND_MASK)) & BF_ST_MEM_ERROR)- goto fail1;- } else {- limb_t digit_mask;- slimb_t pos;- /* position of the digit before the most- significant digit in bits */- pos = a1->len * LIMB_BITS +- smod(-a1->expn, radix_bits);- n_digits = ceil_div(pos, radix_bits);- /* remove the trailing zero digits */- digit_mask = ((limb_t)1 << radix_bits) - 1;- while (n_digits > 1 &&- (get_bits(a1->tab, a1->len, pos - n_digits * radix_bits) & digit_mask) == 0) {- n_digits--;- }- n_max = n_digits + 4;- }- n = ceil_div(a1->expn, radix_bits);- } else {- bf_t a_s, *a = &a_s;- - /* make a positive number */- a->tab = a2->tab;- a->len = a2->len;- a->expn = a2->expn;- a->sign = 0;- - if (fmt == BF_FTOA_FORMAT_FIXED) {- n_digits = prec;- n_max = n_digits;- } else {- slimb_t n_digits_max, n_digits_min;- - assert(prec != BF_PREC_INF);- n_digits = 1 + bf_mul_log2_radix(prec, radix, TRUE, TRUE);- /* max number of digits for non exponential- notation. The rational is to have the same rule- as JS i.e. n_max = 21 for 64 bit float in base 10. */- n_max = n_digits + 4;- if (fmt == BF_FTOA_FORMAT_FREE_MIN) {- bf_t b_s, *b = &b_s;- - /* find the minimum number of digits by- dichotomy. */- /* XXX: inefficient */- n_digits_max = n_digits;- n_digits_min = 1;- bf_init(ctx, b);- while (n_digits_min < n_digits_max) {- n_digits = (n_digits_min + n_digits_max) / 2;- if (bf_convert_to_radix(a1, &n, a, radix, n_digits,- flags & BF_RND_MASK, FALSE)) {- bf_delete(b);- goto fail1;- }- /* convert back to a number and compare */- ret = bf_mul_pow_radix(b, a1, radix, n - n_digits,- prec,- (flags & ~BF_RND_MASK) |- BF_RNDN);- if (ret & BF_ST_MEM_ERROR) {- bf_delete(b);- goto fail1;- }- if (bf_cmpu(b, a) == 0) {- n_digits_max = n_digits;- } else {- n_digits_min = n_digits + 1;- }- }- bf_delete(b);- n_digits = n_digits_max;- }- }- if (bf_convert_to_radix(a1, &n, a, radix, n_digits,- flags & BF_RND_MASK, FALSE)) {- fail1:- bf_delete(a1);- goto fail;- }- }- if (a1->expn == BF_EXP_ZERO &&- fmt != BF_FTOA_FORMAT_FIXED &&- !(flags & BF_FTOA_FORCE_EXP)) {- /* just output zero */- dbuf_putstr(s, "0");- } else {- if (flags & BF_FTOA_ADD_PREFIX) {- if (radix == 16)- dbuf_putstr(s, "0x");- else if (radix == 8)- dbuf_putstr(s, "0o");- else if (radix == 2)- dbuf_putstr(s, "0b");- }- if (a1->expn == BF_EXP_ZERO)- n = 1;- if ((flags & BF_FTOA_FORCE_EXP) ||- n <= -6 || n > n_max) {- const char *fmt;- /* exponential notation */- output_digits(s, a1, radix, n_digits, 1, is_dec);- if (radix_bits != 0 && radix <= 16) {- if (flags & BF_FTOA_JS_QUIRKS)- fmt = "p%+" PRId_LIMB;- else- fmt = "p%" PRId_LIMB;- dbuf_printf(s, fmt, (n - 1) * radix_bits);- } else {- if (flags & BF_FTOA_JS_QUIRKS)- fmt = "%c%+" PRId_LIMB;- else- fmt = "%c%" PRId_LIMB;- dbuf_printf(s, fmt,- radix <= 10 ? 'e' : '@', n - 1);- }- } else if (n <= 0) {- /* 0.x */- dbuf_putstr(s, "0.");- for(i = 0; i < -n; i++) {- dbuf_putc(s, '0');- }- output_digits(s, a1, radix, n_digits, n_digits, is_dec);- } else {- if (n_digits <= n) {- /* no dot */- output_digits(s, a1, radix, n_digits, n_digits, is_dec);- for(i = 0; i < (n - n_digits); i++)- dbuf_putc(s, '0');- } else {- output_digits(s, a1, radix, n_digits, n, is_dec);- }- }- }- }- bf_delete(a1);- }- }- dbuf_putc(s, '\0');- if (dbuf_error(s))- goto fail;- if (plen)- *plen = s->size - 1;- return (char *)s->buf;- fail:- bf_free(ctx, s->buf);- if (plen)- *plen = 0;- return NULL;-}--char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec,- bf_flags_t flags)-{- return bf_ftoa_internal(plen, a, radix, prec, flags, FALSE);-}--/***************************************************************/-/* transcendental functions */--/* Note: the algorithm is from MPFR */-static void bf_const_log2_rec(bf_t *T, bf_t *P, bf_t *Q, limb_t n1,- limb_t n2, BOOL need_P)-{- bf_context_t *s = T->ctx;- if ((n2 - n1) == 1) {- if (n1 == 0) {- bf_set_ui(P, 3);- } else {- bf_set_ui(P, n1);- P->sign = 1;- }- bf_set_ui(Q, 2 * n1 + 1);- Q->expn += 2;- bf_set(T, P);- } else {- limb_t m;- bf_t T1_s, *T1 = &T1_s;- bf_t P1_s, *P1 = &P1_s;- bf_t Q1_s, *Q1 = &Q1_s;- - m = n1 + ((n2 - n1) >> 1);- bf_const_log2_rec(T, P, Q, n1, m, TRUE);- bf_init(s, T1);- bf_init(s, P1);- bf_init(s, Q1);- bf_const_log2_rec(T1, P1, Q1, m, n2, need_P);- bf_mul(T, T, Q1, BF_PREC_INF, BF_RNDZ);- bf_mul(T1, T1, P, BF_PREC_INF, BF_RNDZ);- bf_add(T, T, T1, BF_PREC_INF, BF_RNDZ);- if (need_P)- bf_mul(P, P, P1, BF_PREC_INF, BF_RNDZ);- bf_mul(Q, Q, Q1, BF_PREC_INF, BF_RNDZ);- bf_delete(T1);- bf_delete(P1);- bf_delete(Q1);- }-}--/* compute log(2) with faithful rounding at precision 'prec' */-static void bf_const_log2_internal(bf_t *T, limb_t prec)-{- limb_t w, N;- bf_t P_s, *P = &P_s;- bf_t Q_s, *Q = &Q_s;-- w = prec + 15;- N = w / 3 + 1;- bf_init(T->ctx, P);- bf_init(T->ctx, Q);- bf_const_log2_rec(T, P, Q, 0, N, FALSE);- bf_div(T, T, Q, prec, BF_RNDN);- bf_delete(P);- bf_delete(Q);-}--/* PI constant */--#define CHUD_A 13591409-#define CHUD_B 545140134-#define CHUD_C 640320-#define CHUD_BITS_PER_TERM 47--static void chud_bs(bf_t *P, bf_t *Q, bf_t *G, int64_t a, int64_t b, int need_g,- limb_t prec)-{- bf_context_t *s = P->ctx;- int64_t c;-- if (a == (b - 1)) {- bf_t T0, T1;- - bf_init(s, &T0);- bf_init(s, &T1);- bf_set_ui(G, 2 * b - 1);- bf_mul_ui(G, G, 6 * b - 1, prec, BF_RNDN);- bf_mul_ui(G, G, 6 * b - 5, prec, BF_RNDN);- bf_set_ui(&T0, CHUD_B);- bf_mul_ui(&T0, &T0, b, prec, BF_RNDN);- bf_set_ui(&T1, CHUD_A);- bf_add(&T0, &T0, &T1, prec, BF_RNDN);- bf_mul(P, G, &T0, prec, BF_RNDN);- P->sign = b & 1;-- bf_set_ui(Q, b);- bf_mul_ui(Q, Q, b, prec, BF_RNDN);- bf_mul_ui(Q, Q, b, prec, BF_RNDN);- bf_mul_ui(Q, Q, (uint64_t)CHUD_C * CHUD_C * CHUD_C / 24, prec, BF_RNDN);- bf_delete(&T0);- bf_delete(&T1);- } else {- bf_t P2, Q2, G2;- - bf_init(s, &P2);- bf_init(s, &Q2);- bf_init(s, &G2);-- c = (a + b) / 2;- chud_bs(P, Q, G, a, c, 1, prec);- chud_bs(&P2, &Q2, &G2, c, b, need_g, prec);- - /* Q = Q1 * Q2 */- /* G = G1 * G2 */- /* P = P1 * Q2 + P2 * G1 */- bf_mul(&P2, &P2, G, prec, BF_RNDN);- if (!need_g)- bf_set_ui(G, 0);- bf_mul(P, P, &Q2, prec, BF_RNDN);- bf_add(P, P, &P2, prec, BF_RNDN);- bf_delete(&P2);-- bf_mul(Q, Q, &Q2, prec, BF_RNDN);- bf_delete(&Q2);- if (need_g)- bf_mul(G, G, &G2, prec, BF_RNDN);- bf_delete(&G2);- }-}--/* compute Pi with faithful rounding at precision 'prec' using the- Chudnovsky formula */-static void bf_const_pi_internal(bf_t *Q, limb_t prec)-{- bf_context_t *s = Q->ctx;- int64_t n, prec1;- bf_t P, G;-- /* number of serie terms */- n = prec / CHUD_BITS_PER_TERM + 1;- /* XXX: precision analysis */- prec1 = prec + 32;-- bf_init(s, &P);- bf_init(s, &G);-- chud_bs(&P, Q, &G, 0, n, 0, BF_PREC_INF);- - bf_mul_ui(&G, Q, CHUD_A, prec1, BF_RNDN);- bf_add(&P, &G, &P, prec1, BF_RNDN);- bf_div(Q, Q, &P, prec1, BF_RNDF);- - bf_set_ui(&P, CHUD_C);- bf_sqrt(&G, &P, prec1, BF_RNDF);- bf_mul_ui(&G, &G, (uint64_t)CHUD_C / 12, prec1, BF_RNDF);- bf_mul(Q, Q, &G, prec, BF_RNDN);- bf_delete(&P);- bf_delete(&G);-}--static int bf_const_get(bf_t *T, limb_t prec, bf_flags_t flags,- BFConstCache *c,- void (*func)(bf_t *res, limb_t prec), int sign)-{- limb_t ziv_extra_bits, prec1;-- ziv_extra_bits = 32;- for(;;) {- prec1 = prec + ziv_extra_bits;- if (c->prec < prec1) {- if (c->val.len == 0)- bf_init(T->ctx, &c->val);- func(&c->val, prec1);- c->prec = prec1;- } else {- prec1 = c->prec;- }- bf_set(T, &c->val);- T->sign = sign;- if (!bf_can_round(T, prec, flags & BF_RND_MASK, prec1)) {- /* and more precision and retry */- ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);- } else {- break;- }- }- return bf_round(T, prec, flags);-}--static void bf_const_free(BFConstCache *c)-{- bf_delete(&c->val);- memset(c, 0, sizeof(*c));-}--int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags)-{- bf_context_t *s = T->ctx;- return bf_const_get(T, prec, flags, &s->log2_cache, bf_const_log2_internal, 0);-}--/* return rounded pi * (1 - 2 * sign) */-static int bf_const_pi_signed(bf_t *T, int sign, limb_t prec, bf_flags_t flags)-{- bf_context_t *s = T->ctx;- return bf_const_get(T, prec, flags, &s->pi_cache, bf_const_pi_internal,- sign);-}--int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags)-{- return bf_const_pi_signed(T, 0, prec, flags);-}--void bf_clear_cache(bf_context_t *s)-{-#ifdef USE_FFT_MUL- fft_clear_cache(s);-#endif- bf_const_free(&s->log2_cache);- bf_const_free(&s->pi_cache);-}--/* ZivFunc should compute the result 'r' with faithful rounding at- precision 'prec'. For efficiency purposes, the final bf_round()- does not need to be done in the function. */-typedef int ZivFunc(bf_t *r, const bf_t *a, limb_t prec, void *opaque);--static int bf_ziv_rounding(bf_t *r, const bf_t *a,- limb_t prec, bf_flags_t flags,- ZivFunc *f, void *opaque)-{- int rnd_mode, ret;- slimb_t prec1, ziv_extra_bits;- - rnd_mode = flags & BF_RND_MASK;- if (rnd_mode == BF_RNDF) {- /* no need to iterate */- f(r, a, prec, opaque);- ret = 0;- } else {- ziv_extra_bits = 32;- for(;;) {- prec1 = prec + ziv_extra_bits;- ret = f(r, a, prec1, opaque);- if (ret & (BF_ST_OVERFLOW | BF_ST_UNDERFLOW | BF_ST_MEM_ERROR)) {- /* overflow or underflow should never happen because- it indicates the rounding cannot be done correctly,- but we do not catch all the cases */- return ret;- }- /* if the result is exact, we can stop */- if (!(ret & BF_ST_INEXACT)) {- ret = 0;- break;- }- if (bf_can_round(r, prec, rnd_mode, prec1)) {- ret = BF_ST_INEXACT;- break;- }- ziv_extra_bits = ziv_extra_bits * 2;- // printf("ziv_extra_bits=%" PRId64 "\n", (int64_t)ziv_extra_bits);- }- }- if (r->len == 0)- return ret;- else- return __bf_round(r, prec, flags, r->len, ret);-}--/* add (1 - 2*e_sign) * 2^e */-static int bf_add_epsilon(bf_t *r, const bf_t *a, slimb_t e, int e_sign,- limb_t prec, int flags)-{- bf_t T_s, *T = &T_s;- int ret;- /* small argument case: result = 1 + epsilon * sign(x) */- bf_init(a->ctx, T);- bf_set_ui(T, 1);- T->sign = e_sign;- T->expn += e;- ret = bf_add(r, r, T, prec, flags);- bf_delete(T);- return ret;-}--/* Compute the exponential using faithful rounding at precision 'prec'.- Note: the algorithm is from MPFR */-static int bf_exp_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)-{- bf_context_t *s = r->ctx;- bf_t T_s, *T = &T_s;- slimb_t n, K, l, i, prec1;- - assert(r != a);-- /* argument reduction:- T = a - n*log(2) with 0 <= T < log(2) and n integer.- */- bf_init(s, T);- if (a->expn <= -1) {- /* 0 <= abs(a) <= 0.5 */- if (a->sign)- n = -1;- else- n = 0;- } else {- bf_const_log2(T, LIMB_BITS, BF_RNDZ);- bf_div(T, a, T, LIMB_BITS, BF_RNDD);- bf_get_limb(&n, T, 0);- }-- K = bf_isqrt((prec + 1) / 2);- l = (prec - 1) / K + 1;- /* XXX: precision analysis ? */- prec1 = prec + (K + 2 * l + 18) + K + 8;- if (a->expn > 0)- prec1 += a->expn;- // printf("n=%ld K=%ld prec1=%ld\n", n, K, prec1);-- bf_const_log2(T, prec1, BF_RNDF);- bf_mul_si(T, T, n, prec1, BF_RNDN);- bf_sub(T, a, T, prec1, BF_RNDN);-- /* reduce the range of T */- bf_mul_2exp(T, -K, BF_PREC_INF, BF_RNDZ);- - /* Taylor expansion around zero :- 1 + x + x^2/2 + ... + x^n/n! - = (1 + x * (1 + x/2 * (1 + ... (x/n))))- */- {- bf_t U_s, *U = &U_s;- - bf_init(s, U);- bf_set_ui(r, 1);- for(i = l ; i >= 1; i--) {- bf_set_ui(U, i);- bf_div(U, T, U, prec1, BF_RNDN);- bf_mul(r, r, U, prec1, BF_RNDN);- bf_add_si(r, r, 1, prec1, BF_RNDN);- }- bf_delete(U);- }- bf_delete(T);- - /* undo the range reduction */- for(i = 0; i < K; i++) {- bf_mul(r, r, r, prec1, BF_RNDN | BF_FLAG_EXT_EXP);- }-- /* undo the argument reduction */- bf_mul_2exp(r, n, BF_PREC_INF, BF_RNDZ | BF_FLAG_EXT_EXP);-- return BF_ST_INEXACT;-}--/* crude overflow and underflow tests for exp(a). a_low <= a <= a_high */-static int check_exp_underflow_overflow(bf_context_t *s, bf_t *r,- const bf_t *a_low, const bf_t *a_high,- limb_t prec, bf_flags_t flags)-{- bf_t T_s, *T = &T_s;- bf_t log2_s, *log2 = &log2_s;- slimb_t e_min, e_max;- - if (a_high->expn <= 0)- return 0;-- e_max = (limb_t)1 << (bf_get_exp_bits(flags) - 1);- e_min = -e_max + 3;- if (flags & BF_FLAG_SUBNORMAL)- e_min -= (prec - 1);- - bf_init(s, T);- bf_init(s, log2);- bf_const_log2(log2, LIMB_BITS, BF_RNDU);- bf_mul_ui(T, log2, e_max, LIMB_BITS, BF_RNDU);- /* a_low > e_max * log(2) implies exp(a) > e_max */- if (bf_cmp_lt(T, a_low) > 0) {- /* overflow */- bf_delete(T);- bf_delete(log2);- return bf_set_overflow(r, 0, prec, flags);- }- /* a_high < (e_min - 2) * log(2) implies exp(a) < (e_min - 2) */- bf_const_log2(log2, LIMB_BITS, BF_RNDD);- bf_mul_si(T, log2, e_min - 2, LIMB_BITS, BF_RNDD);- if (bf_cmp_lt(a_high, T)) {- int rnd_mode = flags & BF_RND_MASK;- - /* underflow */- bf_delete(T);- bf_delete(log2);- if (rnd_mode == BF_RNDU) {- /* set the smallest value */- bf_set_ui(r, 1);- r->expn = e_min;- } else {- bf_set_zero(r, 0);- }- return BF_ST_UNDERFLOW | BF_ST_INEXACT;- }- bf_delete(log2);- bf_delete(T);- return 0;-}--int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)-{- bf_context_t *s = r->ctx;- int ret;- assert(r != a);- if (a->len == 0) {- if (a->expn == BF_EXP_NAN) {- bf_set_nan(r);- } else if (a->expn == BF_EXP_INF) {- if (a->sign)- bf_set_zero(r, 0);- else- bf_set_inf(r, 0);- } else {- bf_set_ui(r, 1);- }- return 0;- }-- ret = check_exp_underflow_overflow(s, r, a, a, prec, flags);- if (ret)- return ret;- if (a->expn < 0 && (-a->expn) >= (prec + 2)) { - /* small argument case: result = 1 + epsilon * sign(x) */- bf_set_ui(r, 1);- return bf_add_epsilon(r, r, -(prec + 2), a->sign, prec, flags);- }- - return bf_ziv_rounding(r, a, prec, flags, bf_exp_internal, NULL);-}--static int bf_log_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)-{- bf_context_t *s = r->ctx;- bf_t T_s, *T = &T_s;- bf_t U_s, *U = &U_s;- bf_t V_s, *V = &V_s;- slimb_t n, prec1, l, i, K;- - assert(r != a);-- bf_init(s, T);- /* argument reduction 1 */- /* T=a*2^n with 2/3 <= T <= 4/3 */- {- bf_t U_s, *U = &U_s;- bf_set(T, a);- n = T->expn;- T->expn = 0;- /* U= ~ 2/3 */- bf_init(s, U);- bf_set_ui(U, 0xaaaaaaaa); - U->expn = 0;- if (bf_cmp_lt(T, U)) {- T->expn++;- n--;- }- bf_delete(U);- }- // printf("n=%ld\n", n);- // bf_print_str("T", T);-- /* XXX: precision analysis */- /* number of iterations for argument reduction 2 */- K = bf_isqrt((prec + 1) / 2); - /* order of Taylor expansion */- l = prec / (2 * K) + 1; - /* precision of the intermediate computations */- prec1 = prec + K + 2 * l + 32;-- bf_init(s, U);- bf_init(s, V);- - /* Note: cancellation occurs here, so we use more precision (XXX:- reduce the precision by computing the exact cancellation) */- bf_add_si(T, T, -1, BF_PREC_INF, BF_RNDN); -- /* argument reduction 2 */- for(i = 0; i < K; i++) {- /* T = T / (1 + sqrt(1 + T)) */- bf_add_si(U, T, 1, prec1, BF_RNDN);- bf_sqrt(V, U, prec1, BF_RNDF);- bf_add_si(U, V, 1, prec1, BF_RNDN);- bf_div(T, T, U, prec1, BF_RNDN);- }-- {- bf_t Y_s, *Y = &Y_s;- bf_t Y2_s, *Y2 = &Y2_s;- bf_init(s, Y);- bf_init(s, Y2);-- /* compute ln(1+x) = ln((1+y)/(1-y)) with y=x/(2+x)- = y + y^3/3 + ... + y^(2*l + 1) / (2*l+1) - with Y=Y^2- = y*(1+Y/3+Y^2/5+...) = y*(1+Y*(1/3+Y*(1/5 + ...)))- */- bf_add_si(Y, T, 2, prec1, BF_RNDN);- bf_div(Y, T, Y, prec1, BF_RNDN);-- bf_mul(Y2, Y, Y, prec1, BF_RNDN);- bf_set_ui(r, 0);- for(i = l; i >= 1; i--) {- bf_set_ui(U, 1);- bf_set_ui(V, 2 * i + 1);- bf_div(U, U, V, prec1, BF_RNDN);- bf_add(r, r, U, prec1, BF_RNDN);- bf_mul(r, r, Y2, prec1, BF_RNDN);- }- bf_add_si(r, r, 1, prec1, BF_RNDN);- bf_mul(r, r, Y, prec1, BF_RNDN);- bf_delete(Y);- bf_delete(Y2);- }- bf_delete(V);- bf_delete(U);-- /* multiplication by 2 for the Taylor expansion and undo the- argument reduction 2*/- bf_mul_2exp(r, K + 1, BF_PREC_INF, BF_RNDZ);- - /* undo the argument reduction 1 */- bf_const_log2(T, prec1, BF_RNDF);- bf_mul_si(T, T, n, prec1, BF_RNDN);- bf_add(r, r, T, prec1, BF_RNDN);- - bf_delete(T);- return BF_ST_INEXACT;-}--int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)-{- bf_context_t *s = r->ctx;- bf_t T_s, *T = &T_s;- - assert(r != a);- if (a->len == 0) {- if (a->expn == BF_EXP_NAN) {- bf_set_nan(r);- return 0;- } else if (a->expn == BF_EXP_INF) {- if (a->sign) {- bf_set_nan(r);- return BF_ST_INVALID_OP;- } else {- bf_set_inf(r, 0);- return 0;- }- } else {- bf_set_inf(r, 1);- return 0;- }- }- if (a->sign) {- bf_set_nan(r);- return BF_ST_INVALID_OP;- }- bf_init(s, T);- bf_set_ui(T, 1);- if (bf_cmp_eq(a, T)) {- bf_set_zero(r, 0);- bf_delete(T);- return 0;- }- bf_delete(T);-- return bf_ziv_rounding(r, a, prec, flags, bf_log_internal, NULL);-}--/* x and y finite and x > 0 */-static int bf_pow_generic(bf_t *r, const bf_t *x, limb_t prec, void *opaque)-{- bf_context_t *s = r->ctx;- const bf_t *y = opaque;- bf_t T_s, *T = &T_s;- limb_t prec1;-- bf_init(s, T);- /* XXX: proof for the added precision */- prec1 = prec + 32;- bf_log(T, x, prec1, BF_RNDF | BF_FLAG_EXT_EXP);- bf_mul(T, T, y, prec1, BF_RNDF | BF_FLAG_EXT_EXP);- if (bf_is_nan(T))- bf_set_nan(r);- else- bf_exp_internal(r, T, prec1, NULL); /* no overflow/underlow test needed */- bf_delete(T);- return BF_ST_INEXACT;-}--/* x and y finite, x > 0, y integer and y fits on one limb */-static int bf_pow_int(bf_t *r, const bf_t *x, limb_t prec, void *opaque)-{- bf_context_t *s = r->ctx;- const bf_t *y = opaque;- bf_t T_s, *T = &T_s;- limb_t prec1;- int ret;- slimb_t y1;- - bf_get_limb(&y1, y, 0);- if (y1 < 0)- y1 = -y1;- /* XXX: proof for the added precision */- prec1 = prec + ceil_log2(y1) * 2 + 8;- ret = bf_pow_ui(r, x, y1 < 0 ? -y1 : y1, prec1, BF_RNDN | BF_FLAG_EXT_EXP);- if (y->sign) {- bf_init(s, T);- bf_set_ui(T, 1);- ret |= bf_div(r, T, r, prec1, BF_RNDN | BF_FLAG_EXT_EXP);- bf_delete(T);- }- return ret;-}--/* x must be a finite non zero float. Return TRUE if there is a- floating point number r such as x=r^(2^n) and return this floating- point number 'r'. Otherwise return FALSE and r is undefined. */-static BOOL check_exact_power2n(bf_t *r, const bf_t *x, slimb_t n)-{- bf_context_t *s = r->ctx;- bf_t T_s, *T = &T_s;- slimb_t e, i, er;- limb_t v;- - /* x = m*2^e with m odd integer */- e = bf_get_exp_min(x);- /* fast check on the exponent */- if (n > (LIMB_BITS - 1)) {- if (e != 0)- return FALSE;- er = 0;- } else {- if ((e & (((limb_t)1 << n) - 1)) != 0)- return FALSE;- er = e >> n;- }- /* every perfect odd square = 1 modulo 8 */- v = get_bits(x->tab, x->len, x->len * LIMB_BITS - x->expn + e);- if ((v & 7) != 1)- return FALSE;-- bf_init(s, T);- bf_set(T, x);- T->expn -= e;- for(i = 0; i < n; i++) {- if (i != 0)- bf_set(T, r);- if (bf_sqrtrem(r, NULL, T) != 0)- return FALSE;- }- r->expn += er;- return TRUE;-}--/* prec = BF_PREC_INF is accepted for x and y integers and y >= 0 */-int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags)-{- bf_context_t *s = r->ctx;- bf_t T_s, *T = &T_s;- bf_t ytmp_s;- BOOL y_is_int, y_is_odd;- int r_sign, ret, rnd_mode;- slimb_t y_emin;- - if (x->len == 0 || y->len == 0) {- if (y->expn == BF_EXP_ZERO) {- /* pow(x, 0) = 1 */- bf_set_ui(r, 1);- } else if (x->expn == BF_EXP_NAN) {- bf_set_nan(r);- } else {- int cmp_x_abs_1;- bf_set_ui(r, 1);- cmp_x_abs_1 = bf_cmpu(x, r);- if (cmp_x_abs_1 == 0 && (flags & BF_POW_JS_QUIRKS) &&- (y->expn >= BF_EXP_INF)) {- bf_set_nan(r);- } else if (cmp_x_abs_1 == 0 &&- (!x->sign || y->expn != BF_EXP_NAN)) {- /* pow(1, y) = 1 even if y = NaN */- /* pow(-1, +/-inf) = 1 */- } else if (y->expn == BF_EXP_NAN) {- bf_set_nan(r);- } else if (y->expn == BF_EXP_INF) {- if (y->sign == (cmp_x_abs_1 > 0)) {- bf_set_zero(r, 0);- } else {- bf_set_inf(r, 0);- }- } else {- y_emin = bf_get_exp_min(y);- y_is_odd = (y_emin == 0);- if (y->sign == (x->expn == BF_EXP_ZERO)) {- bf_set_inf(r, y_is_odd & x->sign);- if (y->sign) {- /* pow(0, y) with y < 0 */- return BF_ST_DIVIDE_ZERO;- }- } else {- bf_set_zero(r, y_is_odd & x->sign);- }- }- }- return 0;- }- bf_init(s, T);- bf_set(T, x);- y_emin = bf_get_exp_min(y);- y_is_int = (y_emin >= 0);- rnd_mode = flags & BF_RND_MASK;- if (x->sign) {- if (!y_is_int) {- bf_set_nan(r);- bf_delete(T);- return BF_ST_INVALID_OP;- }- y_is_odd = (y_emin == 0);- r_sign = y_is_odd;- /* change the directed rounding mode if the sign of the result- is changed */- if (r_sign && (rnd_mode == BF_RNDD || rnd_mode == BF_RNDU))- flags ^= 1;- bf_neg(T);- } else {- r_sign = 0;- }-- bf_set_ui(r, 1);- if (bf_cmp_eq(T, r)) {- /* abs(x) = 1: nothing more to do */- ret = 0;- } else {- /* check the overflow/underflow cases */- {- bf_t al_s, *al = &al_s;- bf_t ah_s, *ah = &ah_s;- limb_t precl = LIMB_BITS;- - bf_init(s, al);- bf_init(s, ah);- /* compute bounds of log(abs(x)) * y with a low precision */- /* XXX: compute bf_log() once */- /* XXX: add a fast test before this slow test */- bf_log(al, T, precl, BF_RNDD);- bf_log(ah, T, precl, BF_RNDU);- bf_mul(al, al, y, precl, BF_RNDD ^ y->sign);- bf_mul(ah, ah, y, precl, BF_RNDU ^ y->sign);- ret = check_exp_underflow_overflow(s, r, al, ah, prec, flags);- bf_delete(al);- bf_delete(ah);- if (ret)- goto done;- }- - if (y_is_int) {- slimb_t T_bits, e;- int_pow:- T_bits = T->expn - bf_get_exp_min(T);- if (T_bits == 1) {- /* pow(2^b, y) = 2^(b*y) */- bf_mul_si(T, y, T->expn - 1, LIMB_BITS, BF_RNDZ);- bf_get_limb(&e, T, 0);- bf_set_ui(r, 1);- ret = bf_mul_2exp(r, e, prec, flags);- } else if (prec == BF_PREC_INF) {- slimb_t y1;- /* specific case for infinite precision (integer case) */- bf_get_limb(&y1, y, 0);- assert(!y->sign);- /* x must be an integer, so abs(x) >= 2 */- if (y1 >= ((slimb_t)1 << BF_EXP_BITS_MAX)) {- bf_delete(T);- return bf_set_overflow(r, 0, BF_PREC_INF, flags);- }- ret = bf_pow_ui(r, T, y1, BF_PREC_INF, BF_RNDZ);- } else {- if (y->expn <= 31) {- /* small enough power: use exponentiation in all cases */- } else if (y->sign) {- /* cannot be exact */- goto general_case;- } else {- if (rnd_mode == BF_RNDF)- goto general_case; /* no need to track exact results */- /* see if the result has a chance to be exact:- if x=a*2^b (a odd), x^y=a^y*2^(b*y)- x^y needs a precision of at least floor_log2(a)*y bits- */- bf_mul_si(r, y, T_bits - 1, LIMB_BITS, BF_RNDZ);- bf_get_limb(&e, r, 0);- if (prec < e)- goto general_case;- }- ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_int, (void *)y);- }- } else {- if (rnd_mode != BF_RNDF) {- bf_t *y1;- if (y_emin < 0 && check_exact_power2n(r, T, -y_emin)) {- /* the problem is reduced to a power to an integer */-#if 0- printf("\nn=%" PRId64 "\n", -(int64_t)y_emin);- bf_print_str("T", T);- bf_print_str("r", r);-#endif- bf_set(T, r);- y1 = &ytmp_s;- y1->tab = y->tab;- y1->len = y->len;- y1->sign = y->sign;- y1->expn = y->expn - y_emin;- y = y1;- goto int_pow;- }- }- general_case:- ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_generic, (void *)y);- }- }- done:- bf_delete(T);- r->sign = r_sign;- return ret;-}--/* compute sqrt(-2*x-x^2) to get |sin(x)| from cos(x) - 1. */-static void bf_sqrt_sin(bf_t *r, const bf_t *x, limb_t prec1)-{- bf_context_t *s = r->ctx;- bf_t T_s, *T = &T_s;- bf_init(s, T);- bf_set(T, x);- bf_mul(r, T, T, prec1, BF_RNDN);- bf_mul_2exp(T, 1, BF_PREC_INF, BF_RNDZ);- bf_add(T, T, r, prec1, BF_RNDN);- bf_neg(T);- bf_sqrt(r, T, prec1, BF_RNDF);- bf_delete(T);-}--static int bf_sincos(bf_t *s, bf_t *c, const bf_t *a, limb_t prec)-{- bf_context_t *s1 = a->ctx;- bf_t T_s, *T = &T_s;- bf_t U_s, *U = &U_s;- bf_t r_s, *r = &r_s;- slimb_t K, prec1, i, l, mod, prec2;- int is_neg;- - assert(c != a && s != a);-- bf_init(s1, T);- bf_init(s1, U);- bf_init(s1, r);- - /* XXX: precision analysis */- K = bf_isqrt(prec / 2);- l = prec / (2 * K) + 1;- prec1 = prec + 2 * K + l + 8;- - /* after the modulo reduction, -pi/4 <= T <= pi/4 */- if (a->expn <= -1) {- /* abs(a) <= 0.25: no modulo reduction needed */- bf_set(T, a);- mod = 0;- } else {- slimb_t cancel;- cancel = 0;- for(;;) {- prec2 = prec1 + a->expn + cancel;- bf_const_pi(U, prec2, BF_RNDF);- bf_mul_2exp(U, -1, BF_PREC_INF, BF_RNDZ);- bf_remquo(&mod, T, a, U, prec2, BF_RNDN, BF_RNDN);- // printf("T.expn=%ld prec2=%ld\n", T->expn, prec2);- if (mod == 0 || (T->expn != BF_EXP_ZERO &&- (T->expn + prec2) >= (prec1 - 1)))- break;- /* increase the number of bits until the precision is good enough */- cancel = bf_max(-T->expn, (cancel + 1) * 3 / 2);- }- mod &= 3;- }- - is_neg = T->sign;- - /* compute cosm1(x) = cos(x) - 1 */- bf_mul(T, T, T, prec1, BF_RNDN);- bf_mul_2exp(T, -2 * K, BF_PREC_INF, BF_RNDZ);- - /* Taylor expansion:- -x^2/2 + x^4/4! - x^6/6! + ...- */- bf_set_ui(r, 1);- for(i = l ; i >= 1; i--) {- bf_set_ui(U, 2 * i - 1);- bf_mul_ui(U, U, 2 * i, BF_PREC_INF, BF_RNDZ);- bf_div(U, T, U, prec1, BF_RNDN);- bf_mul(r, r, U, prec1, BF_RNDN);- bf_neg(r);- if (i != 1)- bf_add_si(r, r, 1, prec1, BF_RNDN);- }- bf_delete(U);-- /* undo argument reduction:- cosm1(2*x)= 2*(2*cosm1(x)+cosm1(x)^2)- */- for(i = 0; i < K; i++) {- bf_mul(T, r, r, prec1, BF_RNDN);- bf_mul_2exp(r, 1, BF_PREC_INF, BF_RNDZ);- bf_add(r, r, T, prec1, BF_RNDN);- bf_mul_2exp(r, 1, BF_PREC_INF, BF_RNDZ);- }- bf_delete(T);-- if (c) {- if ((mod & 1) == 0) {- bf_add_si(c, r, 1, prec1, BF_RNDN);- } else {- bf_sqrt_sin(c, r, prec1);- c->sign = is_neg ^ 1;- }- c->sign ^= mod >> 1;- }- if (s) {- if ((mod & 1) == 0) {- bf_sqrt_sin(s, r, prec1);- s->sign = is_neg;- } else {- bf_add_si(s, r, 1, prec1, BF_RNDN);- }- s->sign ^= mod >> 1;- }- bf_delete(r);- return BF_ST_INEXACT;-}--static int bf_cos_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)-{- return bf_sincos(NULL, r, a, prec);-}--int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)-{- if (a->len == 0) {- if (a->expn == BF_EXP_NAN) {- bf_set_nan(r);- return 0;- } else if (a->expn == BF_EXP_INF) {- bf_set_nan(r);- return BF_ST_INVALID_OP;- } else {- bf_set_ui(r, 1);- return 0;- }- }-- /* small argument case: result = 1+r(x) with r(x) = -x^2/2 +- O(X^4). We assume r(x) < 2^(2*EXP(x) - 1). */- if (a->expn < 0) {- slimb_t e;- e = 2 * a->expn - 1;- if (e < -(prec + 2)) {- bf_set_ui(r, 1);- return bf_add_epsilon(r, r, e, 1, prec, flags);- }- }- - return bf_ziv_rounding(r, a, prec, flags, bf_cos_internal, NULL);-}--static int bf_sin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)-{- return bf_sincos(r, NULL, a, prec);-}--int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)-{- if (a->len == 0) {- if (a->expn == BF_EXP_NAN) {- bf_set_nan(r);- return 0;- } else if (a->expn == BF_EXP_INF) {- bf_set_nan(r);- return BF_ST_INVALID_OP;- } else {- bf_set_zero(r, a->sign);- return 0;- }- }-- /* small argument case: result = x+r(x) with r(x) = -x^3/6 +- O(X^5). We assume r(x) < 2^(3*EXP(x) - 2). */- if (a->expn < 0) {- slimb_t e;- e = sat_add(2 * a->expn, a->expn - 2);- if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {- bf_set(r, a);- return bf_add_epsilon(r, r, e, 1 - a->sign, prec, flags);- }- }-- return bf_ziv_rounding(r, a, prec, flags, bf_sin_internal, NULL);-}--static int bf_tan_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)-{- bf_context_t *s = r->ctx;- bf_t T_s, *T = &T_s;- limb_t prec1;- - /* XXX: precision analysis */- prec1 = prec + 8;- bf_init(s, T);- bf_sincos(r, T, a, prec1);- bf_div(r, r, T, prec1, BF_RNDF);- bf_delete(T);- return BF_ST_INEXACT;-}--int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)-{- assert(r != a);- if (a->len == 0) {- if (a->expn == BF_EXP_NAN) {- bf_set_nan(r);- return 0;- } else if (a->expn == BF_EXP_INF) {- bf_set_nan(r);- return BF_ST_INVALID_OP;- } else {- bf_set_zero(r, a->sign);- return 0;- }- }-- /* small argument case: result = x+r(x) with r(x) = x^3/3 +- O(X^5). We assume r(x) < 2^(3*EXP(x) - 1). */- if (a->expn < 0) {- slimb_t e;- e = sat_add(2 * a->expn, a->expn - 1);- if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {- bf_set(r, a);- return bf_add_epsilon(r, r, e, a->sign, prec, flags);- }- }- - return bf_ziv_rounding(r, a, prec, flags, bf_tan_internal, NULL);-}--/* if add_pi2 is true, add pi/2 to the result (used for acos(x) to- avoid cancellation) */-static int bf_atan_internal(bf_t *r, const bf_t *a, limb_t prec,- void *opaque)-{- bf_context_t *s = r->ctx;- BOOL add_pi2 = (BOOL)(intptr_t)opaque;- bf_t T_s, *T = &T_s;- bf_t U_s, *U = &U_s;- bf_t V_s, *V = &V_s;- bf_t X2_s, *X2 = &X2_s;- int cmp_1;- slimb_t prec1, i, K, l;- - /* XXX: precision analysis */- K = bf_isqrt((prec + 1) / 2);- l = prec / (2 * K) + 1;- prec1 = prec + K + 2 * l + 32;- // printf("prec=%d K=%d l=%d prec1=%d\n", (int)prec, (int)K, (int)l, (int)prec1);- - bf_init(s, T);- cmp_1 = (a->expn >= 1); /* a >= 1 */- if (cmp_1) {- bf_set_ui(T, 1);- bf_div(T, T, a, prec1, BF_RNDN);- } else {- bf_set(T, a);- }-- /* abs(T) <= 1 */-- /* argument reduction */-- bf_init(s, U);- bf_init(s, V);- bf_init(s, X2);- for(i = 0; i < K; i++) {- /* T = T / (1 + sqrt(1 + T^2)) */- bf_mul(U, T, T, prec1, BF_RNDN);- bf_add_si(U, U, 1, prec1, BF_RNDN);- bf_sqrt(V, U, prec1, BF_RNDN);- bf_add_si(V, V, 1, prec1, BF_RNDN);- bf_div(T, T, V, prec1, BF_RNDN);- }-- /* Taylor series: - x - x^3/3 + ... + (-1)^ l * y^(2*l + 1) / (2*l+1) - */- bf_mul(X2, T, T, prec1, BF_RNDN);- bf_set_ui(r, 0);- for(i = l; i >= 1; i--) {- bf_set_si(U, 1);- bf_set_ui(V, 2 * i + 1);- bf_div(U, U, V, prec1, BF_RNDN);- bf_neg(r);- bf_add(r, r, U, prec1, BF_RNDN);- bf_mul(r, r, X2, prec1, BF_RNDN);- }- bf_neg(r);- bf_add_si(r, r, 1, prec1, BF_RNDN);- bf_mul(r, r, T, prec1, BF_RNDN);-- /* undo the argument reduction */- bf_mul_2exp(r, K, BF_PREC_INF, BF_RNDZ);- - bf_delete(U);- bf_delete(V);- bf_delete(X2);-- i = add_pi2;- if (cmp_1 > 0) {- /* undo the inversion : r = sign(a)*PI/2 - r */- bf_neg(r);- i += 1 - 2 * a->sign;- }- /* add i*(pi/2) with -1 <= i <= 2 */- if (i != 0) {- bf_const_pi(T, prec1, BF_RNDF);- if (i != 2)- bf_mul_2exp(T, -1, BF_PREC_INF, BF_RNDZ);- T->sign = (i < 0);- bf_add(r, T, r, prec1, BF_RNDN);- }- - bf_delete(T);- return BF_ST_INEXACT;-}--int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)-{- bf_context_t *s = r->ctx;- bf_t T_s, *T = &T_s;- int res;- - if (a->len == 0) {- if (a->expn == BF_EXP_NAN) {- bf_set_nan(r);- return 0;- } else if (a->expn == BF_EXP_INF) {- /* -PI/2 or PI/2 */- bf_const_pi_signed(r, a->sign, prec, flags);- bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ);- return BF_ST_INEXACT;- } else {- bf_set_zero(r, a->sign);- return 0;- }- }- - bf_init(s, T);- bf_set_ui(T, 1);- res = bf_cmpu(a, T);- bf_delete(T);- if (res == 0) {- /* short cut: abs(a) == 1 -> +/-pi/4 */- bf_const_pi_signed(r, a->sign, prec, flags);- bf_mul_2exp(r, -2, BF_PREC_INF, BF_RNDZ);- return BF_ST_INEXACT;- }-- /* small argument case: result = x+r(x) with r(x) = -x^3/3 +- O(X^5). We assume r(x) < 2^(3*EXP(x) - 1). */- if (a->expn < 0) {- slimb_t e;- e = sat_add(2 * a->expn, a->expn - 1);- if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {- bf_set(r, a);- return bf_add_epsilon(r, r, e, 1 - a->sign, prec, flags);- }- }- - return bf_ziv_rounding(r, a, prec, flags, bf_atan_internal, (void *)FALSE);-}--static int bf_atan2_internal(bf_t *r, const bf_t *y, limb_t prec, void *opaque)-{- bf_context_t *s = r->ctx;- const bf_t *x = opaque;- bf_t T_s, *T = &T_s;- limb_t prec1;- int ret;- - if (y->expn == BF_EXP_NAN || x->expn == BF_EXP_NAN) {- bf_set_nan(r);- return 0;- }-- /* compute atan(y/x) assumming inf/inf = 1 and 0/0 = 0 */- bf_init(s, T);- prec1 = prec + 32;- if (y->expn == BF_EXP_INF && x->expn == BF_EXP_INF) {- bf_set_ui(T, 1);- T->sign = y->sign ^ x->sign;- } else if (y->expn == BF_EXP_ZERO && x->expn == BF_EXP_ZERO) {- bf_set_zero(T, y->sign ^ x->sign);- } else {- bf_div(T, y, x, prec1, BF_RNDF);- }- ret = bf_atan(r, T, prec1, BF_RNDF);-- if (x->sign) {- /* if x < 0 (it includes -0), return sign(y)*pi + atan(y/x) */- bf_const_pi(T, prec1, BF_RNDF);- T->sign = y->sign;- bf_add(r, r, T, prec1, BF_RNDN);- ret |= BF_ST_INEXACT;- }-- bf_delete(T);- return ret;-}--int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x,- limb_t prec, bf_flags_t flags)-{- return bf_ziv_rounding(r, y, prec, flags, bf_atan2_internal, (void *)x);-}--static int bf_asin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)-{- bf_context_t *s = r->ctx;- BOOL is_acos = (BOOL)(intptr_t)opaque;- bf_t T_s, *T = &T_s;- limb_t prec1, prec2;- - /* asin(x) = atan(x/sqrt(1-x^2)) - acos(x) = pi/2 - asin(x) */- prec1 = prec + 8;- /* increase the precision in x^2 to compensate the cancellation in- (1-x^2) if x is close to 1 */- /* XXX: use less precision when possible */- if (a->expn >= 0)- prec2 = BF_PREC_INF;- else- prec2 = prec1;- bf_init(s, T);- bf_mul(T, a, a, prec2, BF_RNDN);- bf_neg(T);- bf_add_si(T, T, 1, prec2, BF_RNDN);-- bf_sqrt(r, T, prec1, BF_RNDN);- bf_div(T, a, r, prec1, BF_RNDN);- if (is_acos)- bf_neg(T);- bf_atan_internal(r, T, prec1, (void *)(intptr_t)is_acos);- bf_delete(T);- return BF_ST_INEXACT;-}--int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)-{- bf_context_t *s = r->ctx;- bf_t T_s, *T = &T_s;- int res;-- if (a->len == 0) {- if (a->expn == BF_EXP_NAN) {- bf_set_nan(r);- return 0;- } else if (a->expn == BF_EXP_INF) {- bf_set_nan(r);- return BF_ST_INVALID_OP;- } else {- bf_set_zero(r, a->sign);- return 0;- }- }- bf_init(s, T);- bf_set_ui(T, 1);- res = bf_cmpu(a, T);- bf_delete(T);- if (res > 0) {- bf_set_nan(r);- return BF_ST_INVALID_OP;- }- - /* small argument case: result = x+r(x) with r(x) = x^3/6 +- O(X^5). We assume r(x) < 2^(3*EXP(x) - 2). */- if (a->expn < 0) {- slimb_t e;- e = sat_add(2 * a->expn, a->expn - 2);- if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {- bf_set(r, a);- return bf_add_epsilon(r, r, e, a->sign, prec, flags);- }- }-- return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)FALSE);-}--int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)-{- bf_context_t *s = r->ctx;- bf_t T_s, *T = &T_s;- int res;-- if (a->len == 0) {- if (a->expn == BF_EXP_NAN) {- bf_set_nan(r);- return 0;- } else if (a->expn == BF_EXP_INF) {- bf_set_nan(r);- return BF_ST_INVALID_OP;- } else {- bf_const_pi(r, prec, flags);- bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ);- return BF_ST_INEXACT;- }- }- bf_init(s, T);- bf_set_ui(T, 1);- res = bf_cmpu(a, T);- bf_delete(T);- if (res > 0) {- bf_set_nan(r);- return BF_ST_INVALID_OP;- } else if (res == 0 && a->sign == 0) {- bf_set_zero(r, 0);- return 0;- }- - return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)TRUE);-}--/***************************************************************/-/* decimal floating point numbers */--#ifdef USE_BF_DEC--#define adddq(r1, r0, a1, a0) \- do { \- limb_t __t = r0; \- r0 += (a0); \- r1 += (a1) + (r0 < __t); \- } while (0)--#define subdq(r1, r0, a1, a0) \- do { \- limb_t __t = r0; \- r0 -= (a0); \- r1 -= (a1) + (r0 > __t); \- } while (0)--#if LIMB_BITS == 64--/* Note: we assume __int128 is available */-#define muldq(r1, r0, a, b) \- do { \- unsigned __int128 __t; \- __t = (unsigned __int128)(a) * (unsigned __int128)(b); \- r0 = __t; \- r1 = __t >> 64; \- } while (0)--#define divdq(q, r, a1, a0, b) \- do { \- unsigned __int128 __t; \- limb_t __b = (b); \- __t = ((unsigned __int128)(a1) << 64) | (a0); \- q = __t / __b; \- r = __t % __b; \- } while (0)--#else--#define muldq(r1, r0, a, b) \- do { \- uint64_t __t; \- __t = (uint64_t)(a) * (uint64_t)(b); \- r0 = __t; \- r1 = __t >> 32; \- } while (0)--#define divdq(q, r, a1, a0, b) \- do { \- uint64_t __t; \- limb_t __b = (b); \- __t = ((uint64_t)(a1) << 32) | (a0); \- q = __t / __b; \- r = __t % __b; \- } while (0)--#endif /* LIMB_BITS != 64 */--static inline __maybe_unused limb_t shrd(limb_t low, limb_t high, long shift)-{- if (shift != 0)- low = (low >> shift) | (high << (LIMB_BITS - shift));- return low;-}--static inline __maybe_unused limb_t shld(limb_t a1, limb_t a0, long shift)-{- if (shift != 0)- return (a1 << shift) | (a0 >> (LIMB_BITS - shift));- else- return a1;-}--#if LIMB_DIGITS == 19--/* WARNING: hardcoded for b = 1e19. It is assumed that:- 0 <= a1 < 2^63 */-#define divdq_base(q, r, a1, a0)\-do {\- uint64_t __a0, __a1, __t0, __t1, __b = BF_DEC_BASE; \- __a0 = a0;\- __a1 = a1;\- __t0 = __a1;\- __t0 = shld(__t0, __a0, 1);\- muldq(q, __t1, __t0, UINT64_C(17014118346046923173)); \- muldq(__t1, __t0, q, __b);\- subdq(__a1, __a0, __t1, __t0);\- subdq(__a1, __a0, 1, __b * 2); \- __t0 = (slimb_t)__a1 >> 1; \- q += 2 + __t0;\- adddq(__a1, __a0, 0, __b & __t0);\- q += __a1; \- __a0 += __b & __a1; \- r = __a0;\-} while(0)--#elif LIMB_DIGITS == 9--/* WARNING: hardcoded for b = 1e9. It is assumed that:- 0 <= a1 < 2^29 */-#define divdq_base(q, r, a1, a0)\-do {\- uint32_t __t0, __t1, __b = BF_DEC_BASE; \- __t0 = a1;\- __t1 = a0;\- __t0 = (__t0 << 3) | (__t1 >> (32 - 3)); \- muldq(q, __t1, __t0, 2305843009U);\- r = a0 - q * __b;\- __t1 = (r >= __b);\- q += __t1;\- if (__t1)\- r -= __b;\-} while(0)--#endif--/* fast integer division by a fixed constant */--typedef struct FastDivData {- limb_t m1; /* multiplier */- int8_t shift1;- int8_t shift2;-} FastDivData;--/* From "Division by Invariant Integers using Multiplication" by- Torborn Granlund and Peter L. Montgomery */-/* d must be != 0 */-static inline __maybe_unused void fast_udiv_init(FastDivData *s, limb_t d)-{- int l;- limb_t q, r, m1;- if (d == 1)- l = 0;- else- l = 64 - clz64(d - 1);- divdq(q, r, ((limb_t)1 << l) - d, 0, d);- (void)r;- m1 = q + 1;- // printf("d=%lu l=%d m1=0x%016lx\n", d, l, m1);- s->m1 = m1;- s->shift1 = l;- if (s->shift1 > 1)- s->shift1 = 1;- s->shift2 = l - 1;- if (s->shift2 < 0)- s->shift2 = 0;-}--static inline limb_t fast_udiv(limb_t a, const FastDivData *s)-{- limb_t t0, t1;- muldq(t1, t0, s->m1, a);- t0 = (a - t1) >> s->shift1;- return (t1 + t0) >> s->shift2;-}--/* contains 10^i */-const limb_t mp_pow_dec[LIMB_DIGITS + 1] = {- 1U,- 10U,- 100U,- 1000U,- 10000U,- 100000U,- 1000000U,- 10000000U,- 100000000U,- 1000000000U,-#if LIMB_BITS == 64- 10000000000U,- 100000000000U,- 1000000000000U,- 10000000000000U,- 100000000000000U,- 1000000000000000U,- 10000000000000000U,- 100000000000000000U,- 1000000000000000000U,- 10000000000000000000U,-#endif-};--/* precomputed from fast_udiv_init(10^i) */-static const FastDivData mp_pow_div[LIMB_DIGITS + 1] = {-#if LIMB_BITS == 32- { 0x00000001, 0, 0 },- { 0x9999999a, 1, 3 },- { 0x47ae147b, 1, 6 },- { 0x0624dd30, 1, 9 },- { 0xa36e2eb2, 1, 13 },- { 0x4f8b588f, 1, 16 },- { 0x0c6f7a0c, 1, 19 },- { 0xad7f29ac, 1, 23 },- { 0x5798ee24, 1, 26 },- { 0x12e0be83, 1, 29 },-#else- { 0x0000000000000001, 0, 0 },- { 0x999999999999999a, 1, 3 },- { 0x47ae147ae147ae15, 1, 6 },- { 0x0624dd2f1a9fbe77, 1, 9 },- { 0xa36e2eb1c432ca58, 1, 13 },- { 0x4f8b588e368f0847, 1, 16 },- { 0x0c6f7a0b5ed8d36c, 1, 19 },- { 0xad7f29abcaf48579, 1, 23 },- { 0x5798ee2308c39dfa, 1, 26 },- { 0x12e0be826d694b2f, 1, 29 },- { 0xb7cdfd9d7bdbab7e, 1, 33 },- { 0x5fd7fe17964955fe, 1, 36 },- { 0x19799812dea11198, 1, 39 },- { 0xc25c268497681c27, 1, 43 },- { 0x6849b86a12b9b01f, 1, 46 },- { 0x203af9ee756159b3, 1, 49 },- { 0xcd2b297d889bc2b7, 1, 53 },- { 0x70ef54646d496893, 1, 56 },- { 0x2725dd1d243aba0f, 1, 59 },- { 0xd83c94fb6d2ac34d, 1, 63 },-#endif-};--/* divide by 10^shift with 0 <= shift <= LIMB_DIGITS */-static inline limb_t fast_shr_dec(limb_t a, int shift)-{- return fast_udiv(a, &mp_pow_div[shift]);-}--/* division and remainder by 10^shift */-#define fast_shr_rem_dec(q, r, a, shift) q = fast_shr_dec(a, shift), r = a - q * mp_pow_dec[shift]- -limb_t mp_add_dec(limb_t *res, const limb_t *op1, const limb_t *op2, - mp_size_t n, limb_t carry)-{- limb_t base = BF_DEC_BASE;- mp_size_t i;- limb_t k, a, v;-- k=carry;- for(i=0;i<n;i++) {- /* XXX: reuse the trick in add_mod */- v = op1[i];- a = v + op2[i] + k - base;- k = a <= v;- if (!k) - a += base;- res[i]=a;- }- return k;-}--limb_t mp_add_ui_dec(limb_t *tab, limb_t b, mp_size_t n)-{- limb_t base = BF_DEC_BASE;- mp_size_t i;- limb_t k, a, v;-- k=b;- for(i=0;i<n;i++) {- v = tab[i];- a = v + k - base;- k = a <= v;- if (!k) - a += base;- tab[i] = a;- if (k == 0)- break;- }- return k;-}--limb_t mp_sub_dec(limb_t *res, const limb_t *op1, const limb_t *op2, - mp_size_t n, limb_t carry)-{- limb_t base = BF_DEC_BASE;- mp_size_t i;- limb_t k, v, a;-- k=carry;- for(i=0;i<n;i++) {- v = op1[i];- a = v - op2[i] - k;- k = a > v;- if (k)- a += base;- res[i] = a;- }- return k;-}--limb_t mp_sub_ui_dec(limb_t *tab, limb_t b, mp_size_t n)-{- limb_t base = BF_DEC_BASE;- mp_size_t i;- limb_t k, v, a;- - k=b;- for(i=0;i<n;i++) {- v = tab[i];- a = v - k;- k = a > v;- if (k)- a += base;- tab[i]=a;- if (k == 0)- break;- }- return k;-}--/* taba[] = taba[] * b + l. 0 <= b, l <= base - 1. Return the high carry */-limb_t mp_mul1_dec(limb_t *tabr, const limb_t *taba, mp_size_t n, - limb_t b, limb_t l)-{- mp_size_t i;- limb_t t0, t1, r;-- for(i = 0; i < n; i++) {- muldq(t1, t0, taba[i], b);- adddq(t1, t0, 0, l);- divdq_base(l, r, t1, t0);- tabr[i] = r;- }- return l;-}--/* tabr[] += taba[] * b. 0 <= b <= base - 1. Return the value to add- to the high word */-limb_t mp_add_mul1_dec(limb_t *tabr, const limb_t *taba, mp_size_t n,- limb_t b)-{- mp_size_t i;- limb_t l, t0, t1, r;-- l = 0;- for(i = 0; i < n; i++) {- muldq(t1, t0, taba[i], b);- adddq(t1, t0, 0, l);- adddq(t1, t0, 0, tabr[i]);- divdq_base(l, r, t1, t0);- tabr[i] = r;- }- return l;-}--/* tabr[] -= taba[] * b. 0 <= b <= base - 1. Return the value to- substract to the high word. */-limb_t mp_sub_mul1_dec(limb_t *tabr, const limb_t *taba, mp_size_t n,- limb_t b)-{- limb_t base = BF_DEC_BASE;- mp_size_t i;- limb_t l, t0, t1, r, a, v, c;-- /* XXX: optimize */- l = 0;- for(i = 0; i < n; i++) {- muldq(t1, t0, taba[i], b);- adddq(t1, t0, 0, l);- divdq_base(l, r, t1, t0);- v = tabr[i];- a = v - r;- c = a > v;- if (c)- a += base;- /* never bigger than base because r = 0 when l = base - 1 */- l += c;- tabr[i] = a;- }- return l;-}--/* size of the result : op1_size + op2_size. */-void mp_mul_basecase_dec(limb_t *result, - const limb_t *op1, mp_size_t op1_size, - const limb_t *op2, mp_size_t op2_size) -{- mp_size_t i;- limb_t r;- - result[op1_size] = mp_mul1_dec(result, op1, op1_size, op2[0], 0);-- for(i=1;i<op2_size;i++) {- r = mp_add_mul1_dec(result + i, op1, op1_size, op2[i]);- result[i + op1_size] = r;- }-}--/* taba[] = (taba[] + r*base^na) / b. 0 <= b < base. 0 <= r <- b. Return the remainder. */-limb_t mp_div1_dec(limb_t *tabr, const limb_t *taba, mp_size_t na, - limb_t b, limb_t r)-{- limb_t base = BF_DEC_BASE;- mp_size_t i;- limb_t t0, t1, q;- int shift;--#if (BF_DEC_BASE % 2) == 0- if (b == 2) {- limb_t base_div2;- /* Note: only works if base is even */- base_div2 = base >> 1;- if (r)- r = base_div2;- for(i = na - 1; i >= 0; i--) {- t0 = taba[i];- tabr[i] = (t0 >> 1) + r;- r = 0;- if (t0 & 1)- r = base_div2;- }- if (r)- r = 1;- } else -#endif- if (na >= UDIV1NORM_THRESHOLD) {- shift = clz(b);- if (shift == 0) {- /* normalized case: b >= 2^(LIMB_BITS-1) */- limb_t b_inv;- b_inv = udiv1norm_init(b);- for(i = na - 1; i >= 0; i--) {- muldq(t1, t0, r, base);- adddq(t1, t0, 0, taba[i]);- q = udiv1norm(&r, t1, t0, b, b_inv);- tabr[i] = q;- }- } else {- limb_t b_inv;- b <<= shift;- b_inv = udiv1norm_init(b);- for(i = na - 1; i >= 0; i--) {- muldq(t1, t0, r, base);- adddq(t1, t0, 0, taba[i]);- t1 = (t1 << shift) | (t0 >> (LIMB_BITS - shift));- t0 <<= shift;- q = udiv1norm(&r, t1, t0, b, b_inv);- r >>= shift;- tabr[i] = q;- }- }- } else {- for(i = na - 1; i >= 0; i--) {- muldq(t1, t0, r, base);- adddq(t1, t0, 0, taba[i]);- divdq(q, r, t1, t0, b);- tabr[i] = q;- }- }- return r;-}--static __maybe_unused void mp_print_str_dec(const char *str,- const limb_t *tab, slimb_t n)-{- slimb_t i;- printf("%s=", str);- for(i = n - 1; i >= 0; i--) {- if (i != n - 1)- printf("_");- printf("%0*" PRIu_LIMB, LIMB_DIGITS, tab[i]);- }- printf("\n");-}--static __maybe_unused void mp_print_str_h_dec(const char *str,- const limb_t *tab, slimb_t n,- limb_t high)-{- slimb_t i;- printf("%s=", str);- printf("%0*" PRIu_LIMB, LIMB_DIGITS, high);- for(i = n - 1; i >= 0; i--) {- printf("_");- printf("%0*" PRIu_LIMB, LIMB_DIGITS, tab[i]);- }- printf("\n");-}--//#define DEBUG_DIV_SLOW--#define DIV_STATIC_ALLOC_LEN 16--/* return q = a / b and r = a % b. -- taba[na] must be allocated if tabb1[nb - 1] < B / 2. tabb1[nb - 1]- must be != zero. na must be >= nb. 's' can be NULL if tabb1[nb - 1]- >= B / 2.-- The remainder is is returned in taba and contains nb libms. tabq- contains na - nb + 1 limbs. No overlap is permitted.-- Running time of the standard method: (na - nb + 1) * nb- Return 0 if OK, -1 if memory alloc error-*/-/* XXX: optimize */-static int mp_div_dec(bf_context_t *s, limb_t *tabq,- limb_t *taba, mp_size_t na, - const limb_t *tabb1, mp_size_t nb)-{- limb_t base = BF_DEC_BASE;- limb_t r, mult, t0, t1, a, c, q, v, *tabb;- mp_size_t i, j;- limb_t static_tabb[DIV_STATIC_ALLOC_LEN];- -#ifdef DEBUG_DIV_SLOW- mp_print_str_dec("a", taba, na);- mp_print_str_dec("b", tabb1, nb);-#endif-- /* normalize tabb */- r = tabb1[nb - 1];- assert(r != 0);- i = na - nb;- if (r >= BF_DEC_BASE / 2) {- mult = 1;- tabb = (limb_t *)tabb1;- q = 1;- for(j = nb - 1; j >= 0; j--) {- if (taba[i + j] != tabb[j]) {- if (taba[i + j] < tabb[j])- q = 0;- break;- }- }- tabq[i] = q;- if (q) {- mp_sub_dec(taba + i, taba + i, tabb, nb, 0);- }- i--;- } else {- mult = base / (r + 1);- if (likely(nb <= DIV_STATIC_ALLOC_LEN)) {- tabb = static_tabb;- } else {- tabb = bf_malloc(s, sizeof(limb_t) * nb);- if (!tabb)- return -1;- }- mp_mul1_dec(tabb, tabb1, nb, mult, 0);- taba[na] = mp_mul1_dec(taba, taba, na, mult, 0);- }--#ifdef DEBUG_DIV_SLOW- printf("mult=" FMT_LIMB "\n", mult);- mp_print_str_dec("a_norm", taba, na + 1);- mp_print_str_dec("b_norm", tabb, nb);-#endif-- for(; i >= 0; i--) {- if (unlikely(taba[i + nb] >= tabb[nb - 1])) {- /* XXX: check if it is really possible */- q = base - 1;- } else {- muldq(t1, t0, taba[i + nb], base);- adddq(t1, t0, 0, taba[i + nb - 1]);- divdq(q, r, t1, t0, tabb[nb - 1]);- }- // printf("i=%d q1=%ld\n", i, q);-- r = mp_sub_mul1_dec(taba + i, tabb, nb, q);- // mp_dump("r1", taba + i, nb, bd);- // printf("r2=%ld\n", r);-- v = taba[i + nb];- a = v - r;- c = a > v;- if (c)- a += base;- taba[i + nb] = a;-- if (c != 0) {- /* negative result */- for(;;) {- q--;- c = mp_add_dec(taba + i, taba + i, tabb, nb, 0);- /* propagate carry and test if positive result */- if (c != 0) {- if (++taba[i + nb] == base) {- break;- }- }- }- }- tabq[i] = q;- }--#ifdef DEBUG_DIV_SLOW- mp_print_str_dec("q", tabq, na - nb + 1);- mp_print_str_dec("r", taba, nb);-#endif-- /* remove the normalization */- if (mult != 1) {- mp_div1_dec(taba, taba, nb, mult, 0);- if (unlikely(tabb != static_tabb))- bf_free(s, tabb);- }- return 0;-}--/* divide by 10^shift */-static limb_t mp_shr_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n, - limb_t shift, limb_t high)-{- mp_size_t i;- limb_t l, a, q, r;-- assert(shift >= 1 && shift < LIMB_DIGITS);- l = high;- for(i = n - 1; i >= 0; i--) {- a = tab[i];- fast_shr_rem_dec(q, r, a, shift);- tab_r[i] = q + l * mp_pow_dec[LIMB_DIGITS - shift];- l = r;- }- return l;-}--/* multiply by 10^shift */-static limb_t mp_shl_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n, - limb_t shift, limb_t low)-{- mp_size_t i;- limb_t l, a, q, r;-- assert(shift >= 1 && shift < LIMB_DIGITS);- l = low;- for(i = 0; i < n; i++) {- a = tab[i];- fast_shr_rem_dec(q, r, a, LIMB_DIGITS - shift);- tab_r[i] = r * mp_pow_dec[shift] + l;- l = q;- }- return l;-}--static limb_t mp_sqrtrem2_dec(limb_t *tabs, limb_t *taba)-{- int k;- dlimb_t a, b, r;- limb_t taba1[2], s, r0, r1;-- /* convert to binary and normalize */- a = (dlimb_t)taba[1] * BF_DEC_BASE + taba[0];- k = clz(a >> LIMB_BITS) & ~1;- b = a << k;- taba1[0] = b;- taba1[1] = b >> LIMB_BITS;- mp_sqrtrem2(&s, taba1);- s >>= (k >> 1);- /* convert the remainder back to decimal */- r = a - (dlimb_t)s * (dlimb_t)s;- divdq_base(r1, r0, r >> LIMB_BITS, r);- taba[0] = r0;- tabs[0] = s;- return r1;-}--//#define DEBUG_SQRTREM_DEC--/* tmp_buf must contain (n / 2 + 1 limbs) */-static limb_t mp_sqrtrem_rec_dec(limb_t *tabs, limb_t *taba, limb_t n,- limb_t *tmp_buf)-{- limb_t l, h, rh, ql, qh, c, i;- - if (n == 1)- return mp_sqrtrem2_dec(tabs, taba);-#ifdef DEBUG_SQRTREM_DEC- mp_print_str_dec("a", taba, 2 * n);-#endif- l = n / 2;- h = n - l;- qh = mp_sqrtrem_rec_dec(tabs + l, taba + 2 * l, h, tmp_buf);-#ifdef DEBUG_SQRTREM_DEC- mp_print_str_dec("s1", tabs + l, h);- mp_print_str_h_dec("r1", taba + 2 * l, h, qh);- mp_print_str_h_dec("r2", taba + l, n, qh);-#endif- - /* the remainder is in taba + 2 * l. Its high bit is in qh */- if (qh) {- mp_sub_dec(taba + 2 * l, taba + 2 * l, tabs + l, h, 0);- }- /* instead of dividing by 2*s, divide by s (which is normalized)- and update q and r */- mp_div_dec(NULL, tmp_buf, taba + l, n, tabs + l, h);- qh += tmp_buf[l];- for(i = 0; i < l; i++)- tabs[i] = tmp_buf[i];- ql = mp_div1_dec(tabs, tabs, l, 2, qh & 1);- qh = qh >> 1; /* 0 or 1 */- if (ql)- rh = mp_add_dec(taba + l, taba + l, tabs + l, h, 0);- else- rh = 0;-#ifdef DEBUG_SQRTREM_DEC- mp_print_str_h_dec("q", tabs, l, qh);- mp_print_str_h_dec("u", taba + l, h, rh);-#endif- - mp_add_ui_dec(tabs + l, qh, h);-#ifdef DEBUG_SQRTREM_DEC- mp_print_str_dec("s2", tabs, n);-#endif- - /* q = qh, tabs[l - 1 ... 0], r = taba[n - 1 ... l] */- /* subtract q^2. if qh = 1 then q = B^l, so we can take shortcuts */- if (qh) {- c = qh;- } else {- mp_mul_basecase_dec(taba + n, tabs, l, tabs, l);- c = mp_sub_dec(taba, taba, taba + n, 2 * l, 0);- }- rh -= mp_sub_ui_dec(taba + 2 * l, c, n - 2 * l);- if ((slimb_t)rh < 0) {- mp_sub_ui_dec(tabs, 1, n);- rh += mp_add_mul1_dec(taba, tabs, n, 2);- rh += mp_add_ui_dec(taba, 1, n);- }- return rh;-}--/* 'taba' has 2*n limbs with n >= 1 and taba[2*n-1] >= B/4. Return (s,- r) with s=floor(sqrt(a)) and r=a-s^2. 0 <= r <= 2 * s. tabs has n- limbs. r is returned in the lower n limbs of taba. Its r[n] is the- returned value of the function. */-int mp_sqrtrem_dec(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n)-{- limb_t tmp_buf1[8];- limb_t *tmp_buf;- mp_size_t n2;- n2 = n / 2 + 1;- if (n2 <= countof(tmp_buf1)) {- tmp_buf = tmp_buf1;- } else {- tmp_buf = bf_malloc(s, sizeof(limb_t) * n2);- if (!tmp_buf)- return -1;- }- taba[n] = mp_sqrtrem_rec_dec(tabs, taba, n, tmp_buf);- if (tmp_buf != tmp_buf1)- bf_free(s, tmp_buf);- return 0;-}--/* return the number of leading zero digits, from 0 to LIMB_DIGITS */-static int clz_dec(limb_t a)-{- if (a == 0)- return LIMB_DIGITS;- switch(LIMB_BITS - 1 - clz(a)) {- case 0: /* 1-1 */- return LIMB_DIGITS - 1;- case 1: /* 2-3 */- return LIMB_DIGITS - 1;- case 2: /* 4-7 */- return LIMB_DIGITS - 1;- case 3: /* 8-15 */- if (a < 10)- return LIMB_DIGITS - 1;- else- return LIMB_DIGITS - 2;- case 4: /* 16-31 */- return LIMB_DIGITS - 2;- case 5: /* 32-63 */- return LIMB_DIGITS - 2;- case 6: /* 64-127 */- if (a < 100)- return LIMB_DIGITS - 2;- else- return LIMB_DIGITS - 3;- case 7: /* 128-255 */- return LIMB_DIGITS - 3;- case 8: /* 256-511 */- return LIMB_DIGITS - 3;- case 9: /* 512-1023 */- if (a < 1000)- return LIMB_DIGITS - 3;- else- return LIMB_DIGITS - 4;- case 10: /* 1024-2047 */- return LIMB_DIGITS - 4;- case 11: /* 2048-4095 */- return LIMB_DIGITS - 4;- case 12: /* 4096-8191 */- return LIMB_DIGITS - 4;- case 13: /* 8192-16383 */- if (a < 10000)- return LIMB_DIGITS - 4;- else- return LIMB_DIGITS - 5;- case 14: /* 16384-32767 */- return LIMB_DIGITS - 5;- case 15: /* 32768-65535 */- return LIMB_DIGITS - 5;- case 16: /* 65536-131071 */- if (a < 100000)- return LIMB_DIGITS - 5;- else- return LIMB_DIGITS - 6;- case 17: /* 131072-262143 */- return LIMB_DIGITS - 6;- case 18: /* 262144-524287 */- return LIMB_DIGITS - 6;- case 19: /* 524288-1048575 */- if (a < 1000000)- return LIMB_DIGITS - 6;- else- return LIMB_DIGITS - 7;- case 20: /* 1048576-2097151 */- return LIMB_DIGITS - 7;- case 21: /* 2097152-4194303 */- return LIMB_DIGITS - 7;- case 22: /* 4194304-8388607 */- return LIMB_DIGITS - 7;- case 23: /* 8388608-16777215 */- if (a < 10000000)- return LIMB_DIGITS - 7;- else- return LIMB_DIGITS - 8;- case 24: /* 16777216-33554431 */- return LIMB_DIGITS - 8;- case 25: /* 33554432-67108863 */- return LIMB_DIGITS - 8;- case 26: /* 67108864-134217727 */- if (a < 100000000)- return LIMB_DIGITS - 8;- else- return LIMB_DIGITS - 9;-#if LIMB_BITS == 64- case 27: /* 134217728-268435455 */- return LIMB_DIGITS - 9;- case 28: /* 268435456-536870911 */- return LIMB_DIGITS - 9;- case 29: /* 536870912-1073741823 */- if (a < 1000000000)- return LIMB_DIGITS - 9;- else- return LIMB_DIGITS - 10;- case 30: /* 1073741824-2147483647 */- return LIMB_DIGITS - 10;- case 31: /* 2147483648-4294967295 */- return LIMB_DIGITS - 10;- case 32: /* 4294967296-8589934591 */- return LIMB_DIGITS - 10;- case 33: /* 8589934592-17179869183 */- if (a < 10000000000)- return LIMB_DIGITS - 10;- else- return LIMB_DIGITS - 11;- case 34: /* 17179869184-34359738367 */- return LIMB_DIGITS - 11;- case 35: /* 34359738368-68719476735 */- return LIMB_DIGITS - 11;- case 36: /* 68719476736-137438953471 */- if (a < 100000000000)- return LIMB_DIGITS - 11;- else- return LIMB_DIGITS - 12;- case 37: /* 137438953472-274877906943 */- return LIMB_DIGITS - 12;- case 38: /* 274877906944-549755813887 */- return LIMB_DIGITS - 12;- case 39: /* 549755813888-1099511627775 */- if (a < 1000000000000)- return LIMB_DIGITS - 12;- else- return LIMB_DIGITS - 13;- case 40: /* 1099511627776-2199023255551 */- return LIMB_DIGITS - 13;- case 41: /* 2199023255552-4398046511103 */- return LIMB_DIGITS - 13;- case 42: /* 4398046511104-8796093022207 */- return LIMB_DIGITS - 13;- case 43: /* 8796093022208-17592186044415 */- if (a < 10000000000000)- return LIMB_DIGITS - 13;- else- return LIMB_DIGITS - 14;- case 44: /* 17592186044416-35184372088831 */- return LIMB_DIGITS - 14;- case 45: /* 35184372088832-70368744177663 */- return LIMB_DIGITS - 14;- case 46: /* 70368744177664-140737488355327 */- if (a < 100000000000000)- return LIMB_DIGITS - 14;- else- return LIMB_DIGITS - 15;- case 47: /* 140737488355328-281474976710655 */- return LIMB_DIGITS - 15;- case 48: /* 281474976710656-562949953421311 */- return LIMB_DIGITS - 15;- case 49: /* 562949953421312-1125899906842623 */- if (a < 1000000000000000)- return LIMB_DIGITS - 15;- else- return LIMB_DIGITS - 16;- case 50: /* 1125899906842624-2251799813685247 */- return LIMB_DIGITS - 16;- case 51: /* 2251799813685248-4503599627370495 */- return LIMB_DIGITS - 16;- case 52: /* 4503599627370496-9007199254740991 */- return LIMB_DIGITS - 16;- case 53: /* 9007199254740992-18014398509481983 */- if (a < 10000000000000000)- return LIMB_DIGITS - 16;- else- return LIMB_DIGITS - 17;- case 54: /* 18014398509481984-36028797018963967 */- return LIMB_DIGITS - 17;- case 55: /* 36028797018963968-72057594037927935 */- return LIMB_DIGITS - 17;- case 56: /* 72057594037927936-144115188075855871 */- if (a < 100000000000000000)- return LIMB_DIGITS - 17;- else- return LIMB_DIGITS - 18;- case 57: /* 144115188075855872-288230376151711743 */- return LIMB_DIGITS - 18;- case 58: /* 288230376151711744-576460752303423487 */- return LIMB_DIGITS - 18;- case 59: /* 576460752303423488-1152921504606846975 */- if (a < 1000000000000000000)- return LIMB_DIGITS - 18;- else- return LIMB_DIGITS - 19;-#endif- default:- return 0;- }-}--/* for debugging */-void bfdec_print_str(const char *str, const bfdec_t *a)-{- slimb_t i;- printf("%s=", str);-- if (a->expn == BF_EXP_NAN) {- printf("NaN");- } else {- if (a->sign)- putchar('-');- if (a->expn == BF_EXP_ZERO) {- putchar('0');- } else if (a->expn == BF_EXP_INF) {- printf("Inf");- } else {- printf("0.");- for(i = a->len - 1; i >= 0; i--)- printf("%0*" PRIu_LIMB, LIMB_DIGITS, a->tab[i]);- printf("e%" PRId_LIMB, a->expn);- }- }- printf("\n");-}--/* return != 0 if one digit between 0 and bit_pos inclusive is not zero. */-static inline limb_t scan_digit_nz(const bfdec_t *r, slimb_t bit_pos)-{- slimb_t pos;- limb_t v, q;- int shift;-- if (bit_pos < 0)- return 0;- pos = (limb_t)bit_pos / LIMB_DIGITS;- shift = (limb_t)bit_pos % LIMB_DIGITS;- fast_shr_rem_dec(q, v, r->tab[pos], shift + 1);- (void)q;- if (v != 0)- return 1;- pos--;- while (pos >= 0) {- if (r->tab[pos] != 0)- return 1;- pos--;- }- return 0;-}--static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos)-{- slimb_t i;- int shift;- i = floor_div(pos, LIMB_DIGITS);- if (i < 0 || i >= len)- return 0;- shift = pos - i * LIMB_DIGITS;- return fast_shr_dec(tab[i], shift) % 10;-}--#if 0-static limb_t get_digits(const limb_t *tab, limb_t len, slimb_t pos)-{- limb_t a0, a1;- int shift;- slimb_t i;- - i = floor_div(pos, LIMB_DIGITS);- shift = pos - i * LIMB_DIGITS;- if (i >= 0 && i < len)- a0 = tab[i];- else- a0 = 0;- if (shift == 0) {- return a0;- } else {- i++;- if (i >= 0 && i < len)- a1 = tab[i];- else- a1 = 0;- return fast_shr_dec(a0, shift) +- fast_urem(a1, &mp_pow_div[LIMB_DIGITS - shift]) *- mp_pow_dec[shift];- }-}-#endif--/* return the addend for rounding. Note that prec can be <= 0 for bf_rint() */-static int bfdec_get_rnd_add(int *pret, const bfdec_t *r, limb_t l,- slimb_t prec, int rnd_mode)-{- int add_one, inexact;- limb_t digit1, digit0;- - // bfdec_print_str("get_rnd_add", r);- if (rnd_mode == BF_RNDF) {- digit0 = 1; /* faithful rounding does not honor the INEXACT flag */- } else {- /* starting limb for bit 'prec + 1' */- digit0 = scan_digit_nz(r, l * LIMB_DIGITS - 1 - bf_max(0, prec + 1));- }-- /* get the digit at 'prec' */- digit1 = get_digit(r->tab, l, l * LIMB_DIGITS - 1 - prec);- inexact = (digit1 | digit0) != 0;- - add_one = 0;- switch(rnd_mode) {- case BF_RNDZ:- break;- case BF_RNDN:- if (digit1 == 5) {- if (digit0) {- add_one = 1;- } else {- /* round to even */- add_one =- get_digit(r->tab, l, l * LIMB_DIGITS - 1 - (prec - 1)) & 1;- }- } else if (digit1 > 5) {- add_one = 1;- }- break;- case BF_RNDD:- case BF_RNDU:- if (r->sign == (rnd_mode == BF_RNDD))- add_one = inexact;- break;- case BF_RNDNA:- case BF_RNDF:- add_one = (digit1 >= 5);- break;- case BF_RNDA:- add_one = inexact;- break;- default:- abort();- }- - if (inexact)- *pret |= BF_ST_INEXACT;- return add_one;-}--/* round to prec1 bits assuming 'r' is non zero and finite. 'r' is- assumed to have length 'l' (1 <= l <= r->len). prec1 can be- BF_PREC_INF. BF_FLAG_SUBNORMAL is not supported. Cannot fail with- BF_ST_MEM_ERROR.- */-static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l)-{- int shift, add_one, rnd_mode, ret;- slimb_t i, bit_pos, pos, e_min, e_max, e_range, prec;-- /* XXX: align to IEEE 754 2008 for decimal numbers ? */- e_range = (limb_t)1 << (bf_get_exp_bits(flags) - 1);- e_min = -e_range + 3;- e_max = e_range;- - if (flags & BF_FLAG_RADPNT_PREC) {- /* 'prec' is the precision after the decimal point */- if (prec1 != BF_PREC_INF)- prec = r->expn + prec1;- else- prec = prec1;- } else if (unlikely(r->expn < e_min) && (flags & BF_FLAG_SUBNORMAL)) {- /* restrict the precision in case of potentially subnormal- result */- assert(prec1 != BF_PREC_INF);- prec = prec1 - (e_min - r->expn);- } else {- prec = prec1;- }- - /* round to prec bits */- rnd_mode = flags & BF_RND_MASK;- ret = 0;- add_one = bfdec_get_rnd_add(&ret, r, l, prec, rnd_mode);- - if (prec <= 0) {- if (add_one) {- bfdec_resize(r, 1); /* cannot fail because r is non zero */- r->tab[0] = BF_DEC_BASE / 10;- r->expn += 1 - prec;- ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;- return ret;- } else {- goto underflow;- }- } else if (add_one) {- limb_t carry;- - /* add one starting at digit 'prec - 1' */- bit_pos = l * LIMB_DIGITS - 1 - (prec - 1);- pos = bit_pos / LIMB_DIGITS;- carry = mp_pow_dec[bit_pos % LIMB_DIGITS];- carry = mp_add_ui_dec(r->tab + pos, carry, l - pos);- if (carry) {- /* shift right by one digit */- mp_shr_dec(r->tab + pos, r->tab + pos, l - pos, 1, 1);- r->expn++;- }- }- - /* check underflow */- if (unlikely(r->expn < e_min)) {- if (flags & BF_FLAG_SUBNORMAL) {- /* if inexact, also set the underflow flag */- if (ret & BF_ST_INEXACT)- ret |= BF_ST_UNDERFLOW;- } else {- underflow:- bfdec_set_zero(r, r->sign);- ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;- return ret;- }- }- - /* check overflow */- if (unlikely(r->expn > e_max)) {- bfdec_set_inf(r, r->sign);- ret |= BF_ST_OVERFLOW | BF_ST_INEXACT;- return ret;- }- - /* keep the bits starting at 'prec - 1' */- bit_pos = l * LIMB_DIGITS - 1 - (prec - 1);- i = floor_div(bit_pos, LIMB_DIGITS);- if (i >= 0) {- shift = smod(bit_pos, LIMB_DIGITS);- if (shift != 0) {- r->tab[i] = fast_shr_dec(r->tab[i], shift) *- mp_pow_dec[shift];- }- } else {- i = 0;- }- /* remove trailing zeros */- while (r->tab[i] == 0)- i++;- if (i > 0) {- l -= i;- memmove(r->tab, r->tab + i, l * sizeof(limb_t));- }- bfdec_resize(r, l); /* cannot fail */- return ret;-}--/* Cannot fail with BF_ST_MEM_ERROR. */-int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags)-{- if (r->len == 0)- return 0;- return __bfdec_round(r, prec, flags, r->len);-}--/* 'r' must be a finite number. Cannot fail with BF_ST_MEM_ERROR. */-int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags)-{- limb_t l, v;- int shift, ret;- - // bfdec_print_str("bf_renorm", r);- l = r->len;- while (l > 0 && r->tab[l - 1] == 0)- l--;- if (l == 0) {- /* zero */- r->expn = BF_EXP_ZERO;- bfdec_resize(r, 0); /* cannot fail */- ret = 0;- } else {- r->expn -= (r->len - l) * LIMB_DIGITS;- /* shift to have the MSB set to '1' */- v = r->tab[l - 1];- shift = clz_dec(v);- if (shift != 0) {- mp_shl_dec(r->tab, r->tab, l, shift, 0);- r->expn -= shift;- }- ret = __bfdec_round(r, prec1, flags, l);- }- // bf_print_str("r_final", r);- return ret;-}--int bfdec_set_ui(bfdec_t *r, uint64_t v)-{-#if LIMB_BITS == 32- if (v >= BF_DEC_BASE * BF_DEC_BASE) {- if (bfdec_resize(r, 3))- goto fail;- r->tab[0] = v % BF_DEC_BASE;- v /= BF_DEC_BASE;- r->tab[1] = v % BF_DEC_BASE;- r->tab[2] = v / BF_DEC_BASE;- r->expn = 3 * LIMB_DIGITS;- } else-#endif- if (v >= BF_DEC_BASE) {- if (bfdec_resize(r, 2))- goto fail;- r->tab[0] = v % BF_DEC_BASE;- r->tab[1] = v / BF_DEC_BASE;- r->expn = 2 * LIMB_DIGITS;- } else {- if (bfdec_resize(r, 1))- goto fail;- r->tab[0] = v;- r->expn = LIMB_DIGITS;- }- r->sign = 0;- return bfdec_normalize_and_round(r, BF_PREC_INF, 0);- fail:- bfdec_set_nan(r);- return BF_ST_MEM_ERROR;-}--int bfdec_set_si(bfdec_t *r, int64_t v)-{- int ret;- if (v < 0) {- ret = bfdec_set_ui(r, -v);- r->sign = 1;- } else {- ret = bfdec_set_ui(r, v);- }- return ret;-}--static int bfdec_add_internal(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, bf_flags_t flags, int b_neg)-{- bf_context_t *s = r->ctx;- int is_sub, cmp_res, a_sign, b_sign, ret;-- a_sign = a->sign;- b_sign = b->sign ^ b_neg;- is_sub = a_sign ^ b_sign;- cmp_res = bfdec_cmpu(a, b);- if (cmp_res < 0) {- const bfdec_t *tmp;- tmp = a;- a = b;- b = tmp;- a_sign = b_sign; /* b_sign is never used later */- }- /* abs(a) >= abs(b) */- if (cmp_res == 0 && is_sub && a->expn < BF_EXP_INF) {- /* zero result */- bfdec_set_zero(r, (flags & BF_RND_MASK) == BF_RNDD);- ret = 0;- } else if (a->len == 0 || b->len == 0) {- ret = 0;- if (a->expn >= BF_EXP_INF) {- if (a->expn == BF_EXP_NAN) {- /* at least one operand is NaN */- bfdec_set_nan(r);- ret = 0;- } else if (b->expn == BF_EXP_INF && is_sub) {- /* infinities with different signs */- bfdec_set_nan(r);- ret = BF_ST_INVALID_OP;- } else {- bfdec_set_inf(r, a_sign);- }- } else {- /* at least one zero and not subtract */- if (bfdec_set(r, a))- return BF_ST_MEM_ERROR;- r->sign = a_sign;- goto renorm;- }- } else {- slimb_t d, a_offset, b_offset, i, r_len;- limb_t carry;- limb_t *b1_tab;- int b_shift;- mp_size_t b1_len;- - d = a->expn - b->expn;-- /* XXX: not efficient in time and memory if the precision is- not infinite */- r_len = bf_max(a->len, b->len + (d + LIMB_DIGITS - 1) / LIMB_DIGITS);- if (bfdec_resize(r, r_len))- goto fail;- r->sign = a_sign;- r->expn = a->expn;-- a_offset = r_len - a->len;- for(i = 0; i < a_offset; i++)- r->tab[i] = 0;- for(i = 0; i < a->len; i++)- r->tab[a_offset + i] = a->tab[i];- - b_shift = d % LIMB_DIGITS;- if (b_shift == 0) {- b1_len = b->len;- b1_tab = (limb_t *)b->tab;- } else {- b1_len = b->len + 1;- b1_tab = bf_malloc(s, sizeof(limb_t) * b1_len);- if (!b1_tab)- goto fail;- b1_tab[0] = mp_shr_dec(b1_tab + 1, b->tab, b->len, b_shift, 0) *- mp_pow_dec[LIMB_DIGITS - b_shift];- }- b_offset = r_len - (b->len + (d + LIMB_DIGITS - 1) / LIMB_DIGITS);- - if (is_sub) {- carry = mp_sub_dec(r->tab + b_offset, r->tab + b_offset,- b1_tab, b1_len, 0);- if (carry != 0) {- carry = mp_sub_ui_dec(r->tab + b_offset + b1_len, carry,- r_len - (b_offset + b1_len));- assert(carry == 0);- }- } else {- carry = mp_add_dec(r->tab + b_offset, r->tab + b_offset,- b1_tab, b1_len, 0);- if (carry != 0) {- carry = mp_add_ui_dec(r->tab + b_offset + b1_len, carry,- r_len - (b_offset + b1_len));- }- if (carry != 0) {- if (bfdec_resize(r, r_len + 1)) {- if (b_shift != 0)- bf_free(s, b1_tab);- goto fail;- }- r->tab[r_len] = 1;- r->expn += LIMB_DIGITS;- }- }- if (b_shift != 0)- bf_free(s, b1_tab);- renorm:- ret = bfdec_normalize_and_round(r, prec, flags);- }- return ret;- fail:- bfdec_set_nan(r);- return BF_ST_MEM_ERROR;-}--static int __bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,- bf_flags_t flags)-{- return bfdec_add_internal(r, a, b, prec, flags, 0);-}--static int __bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,- bf_flags_t flags)-{- return bfdec_add_internal(r, a, b, prec, flags, 1);-}--int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,- bf_flags_t flags)-{- return bf_op2((bf_t *)r, (bf_t *)a, (bf_t *)b, prec, flags,- (bf_op2_func_t *)__bfdec_add);-}--int bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,- bf_flags_t flags)-{- return bf_op2((bf_t *)r, (bf_t *)a, (bf_t *)b, prec, flags,- (bf_op2_func_t *)__bfdec_sub);-}--int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,- bf_flags_t flags)-{- int ret, r_sign;-- if (a->len < b->len) {- const bfdec_t *tmp = a;- a = b;- b = tmp;- }- r_sign = a->sign ^ b->sign;- /* here b->len <= a->len */- if (b->len == 0) {- if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {- bfdec_set_nan(r);- ret = 0;- } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_INF) {- if ((a->expn == BF_EXP_INF && b->expn == BF_EXP_ZERO) ||- (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_INF)) {- bfdec_set_nan(r);- ret = BF_ST_INVALID_OP;- } else {- bfdec_set_inf(r, r_sign);- ret = 0;- }- } else {- bfdec_set_zero(r, r_sign);- ret = 0;- }- } else {- bfdec_t tmp, *r1 = NULL;- limb_t a_len, b_len;- limb_t *a_tab, *b_tab;- - a_len = a->len;- b_len = b->len;- a_tab = a->tab;- b_tab = b->tab;- - if (r == a || r == b) {- bfdec_init(r->ctx, &tmp);- r1 = r;- r = &tmp;- }- if (bfdec_resize(r, a_len + b_len)) {- bfdec_set_nan(r);- ret = BF_ST_MEM_ERROR;- goto done;- }- mp_mul_basecase_dec(r->tab, a_tab, a_len, b_tab, b_len);- r->sign = r_sign;- r->expn = a->expn + b->expn;- ret = bfdec_normalize_and_round(r, prec, flags);- done:- if (r == &tmp)- bfdec_move(r1, &tmp);- }- return ret;-}--int bfdec_mul_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,- bf_flags_t flags)-{- bfdec_t b;- int ret;- bfdec_init(r->ctx, &b);- ret = bfdec_set_si(&b, b1);- ret |= bfdec_mul(r, a, &b, prec, flags);- bfdec_delete(&b);- return ret;-}--int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,- bf_flags_t flags)-{- bfdec_t b;- int ret;- - bfdec_init(r->ctx, &b);- ret = bfdec_set_si(&b, b1);- ret |= bfdec_add(r, a, &b, prec, flags);- bfdec_delete(&b);- return ret;-}--static int __bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b,- limb_t prec, bf_flags_t flags)-{- int ret, r_sign;- limb_t n, nb, precl;- - r_sign = a->sign ^ b->sign;- if (a->expn >= BF_EXP_INF || b->expn >= BF_EXP_INF) {- if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {- bfdec_set_nan(r);- return 0;- } else if (a->expn == BF_EXP_INF && b->expn == BF_EXP_INF) {- bfdec_set_nan(r);- return BF_ST_INVALID_OP;- } else if (a->expn == BF_EXP_INF) {- bfdec_set_inf(r, r_sign);- return 0;- } else {- bfdec_set_zero(r, r_sign);- return 0;- }- } else if (a->expn == BF_EXP_ZERO) {- if (b->expn == BF_EXP_ZERO) {- bfdec_set_nan(r);- return BF_ST_INVALID_OP;- } else {- bfdec_set_zero(r, r_sign);- return 0;- }- } else if (b->expn == BF_EXP_ZERO) {- bfdec_set_inf(r, r_sign);- return BF_ST_DIVIDE_ZERO;- }-- nb = b->len;- if (prec == BF_PREC_INF) {- /* infinite precision: return BF_ST_INVALID_OP if not an exact- result */- /* XXX: check */- precl = nb + 1;- } else if (flags & BF_FLAG_RADPNT_PREC) {- /* number of digits after the decimal point */- /* XXX: check (2 extra digits for rounding + 2 digits) */- precl = (bf_max(a->expn - b->expn, 0) + 2 +- prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS;- } else {- /* number of limbs of the quotient (2 extra digits for rounding) */- precl = (prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS;- }- n = bf_max(a->len, precl);- - {- limb_t *taba, na, i;- slimb_t d;- - na = n + nb;- taba = bf_malloc(r->ctx, (na + 1) * sizeof(limb_t));- if (!taba)- goto fail;- d = na - a->len;- memset(taba, 0, d * sizeof(limb_t));- memcpy(taba + d, a->tab, a->len * sizeof(limb_t));- if (bfdec_resize(r, n + 1))- goto fail1;- if (mp_div_dec(r->ctx, r->tab, taba, na, b->tab, nb)) {- fail1:- bf_free(r->ctx, taba);- goto fail;- }- /* see if non zero remainder */- for(i = 0; i < nb; i++) {- if (taba[i] != 0)- break;- }- bf_free(r->ctx, taba);- if (i != nb) {- if (prec == BF_PREC_INF) {- bfdec_set_nan(r);- return BF_ST_INVALID_OP;- } else {- r->tab[0] |= 1;- }- }- r->expn = a->expn - b->expn + LIMB_DIGITS;- r->sign = r_sign;- ret = bfdec_normalize_and_round(r, prec, flags);- }- return ret;- fail:- bfdec_set_nan(r);- return BF_ST_MEM_ERROR;-}--int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,- bf_flags_t flags)-{- return bf_op2((bf_t *)r, (bf_t *)a, (bf_t *)b, prec, flags,- (bf_op2_func_t *)__bfdec_div);-}--/* a and b must be finite numbers with a >= 0 and b > 0. 'q' is the- integer defined as floor(a/b) and r = a - q * b. */-static void bfdec_tdivremu(bf_context_t *s, bfdec_t *q, bfdec_t *r,- const bfdec_t *a, const bfdec_t *b)-{- if (bfdec_cmpu(a, b) < 0) {- bfdec_set_ui(q, 0);- bfdec_set(r, a);- } else {- bfdec_div(q, a, b, 0, BF_RNDZ | BF_FLAG_RADPNT_PREC);- bfdec_mul(r, q, b, BF_PREC_INF, BF_RNDZ);- bfdec_sub(r, a, r, BF_PREC_INF, BF_RNDZ);- }-}--/* division and remainder. - - rnd_mode is the rounding mode for the quotient. The additional- rounding mode BF_RND_EUCLIDIAN is supported.-- 'q' is an integer. 'r' is rounded with prec and flags (prec can be- BF_PREC_INF).-*/-int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,- limb_t prec, bf_flags_t flags, int rnd_mode)-{- bf_context_t *s = q->ctx;- bfdec_t a1_s, *a1 = &a1_s;- bfdec_t b1_s, *b1 = &b1_s;- bfdec_t r1_s, *r1 = &r1_s;- int q_sign, res;- BOOL is_ceil, is_rndn;- - assert(q != a && q != b);- assert(r != a && r != b);- assert(q != r);- - if (a->len == 0 || b->len == 0) {- bfdec_set_zero(q, 0);- if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {- bfdec_set_nan(r);- return 0;- } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_ZERO) {- bfdec_set_nan(r);- return BF_ST_INVALID_OP;- } else {- bfdec_set(r, a);- return bfdec_round(r, prec, flags);- }- }-- q_sign = a->sign ^ b->sign;- is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);- switch(rnd_mode) {- default:- case BF_RNDZ:- case BF_RNDN:- case BF_RNDNA:- is_ceil = FALSE;- break;- case BF_RNDD:- is_ceil = q_sign;- break;- case BF_RNDU:- is_ceil = q_sign ^ 1;- break;- case BF_RNDA:- is_ceil = TRUE;- break;- case BF_DIVREM_EUCLIDIAN:- is_ceil = a->sign;- break;- }-- a1->expn = a->expn;- a1->tab = a->tab;- a1->len = a->len;- a1->sign = 0;- - b1->expn = b->expn;- b1->tab = b->tab;- b1->len = b->len;- b1->sign = 0;-- // bfdec_print_str("a1", a1);- // bfdec_print_str("b1", b1);- /* XXX: could improve to avoid having a large 'q' */- bfdec_tdivremu(s, q, r, a1, b1);- if (bfdec_is_nan(q) || bfdec_is_nan(r))- goto fail;- // bfdec_print_str("q", q);- // bfdec_print_str("r", r);- - if (r->len != 0) {- if (is_rndn) {- bfdec_init(s, r1);- if (bfdec_set(r1, r))- goto fail;- if (bfdec_mul_si(r1, r1, 2, BF_PREC_INF, BF_RNDZ)) {- bfdec_delete(r1);- goto fail;- }- res = bfdec_cmpu(r1, b);- bfdec_delete(r1);- if (res > 0 ||- (res == 0 &&- (rnd_mode == BF_RNDNA ||- (get_digit(q->tab, q->len, q->len * LIMB_DIGITS - q->expn) & 1) != 0))) {- goto do_sub_r;- }- } else if (is_ceil) {- do_sub_r:- res = bfdec_add_si(q, q, 1, BF_PREC_INF, BF_RNDZ);- res |= bfdec_sub(r, r, b1, BF_PREC_INF, BF_RNDZ);- if (res & BF_ST_MEM_ERROR)- goto fail;- }- }-- r->sign ^= a->sign;- q->sign = q_sign;- return bfdec_round(r, prec, flags);- fail:- bfdec_set_nan(q);- bfdec_set_nan(r);- return BF_ST_MEM_ERROR;-}--int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,- bf_flags_t flags, int rnd_mode)-{- bfdec_t q_s, *q = &q_s;- int ret;- - bfdec_init(r->ctx, q);- ret = bfdec_divrem(q, r, a, b, prec, flags, rnd_mode);- bfdec_delete(q);- return ret;-}--/* convert to integer (infinite precision) */-int bfdec_rint(bfdec_t *r, int rnd_mode)-{- return bfdec_round(r, 0, rnd_mode | BF_FLAG_RADPNT_PREC);-}--int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags)-{- bf_context_t *s = a->ctx;- int ret, k;- limb_t *a1, v;- slimb_t n, n1, prec1;- limb_t res;-- assert(r != a);-- if (a->len == 0) {- if (a->expn == BF_EXP_NAN) {- bfdec_set_nan(r);- } else if (a->expn == BF_EXP_INF && a->sign) {- goto invalid_op;- } else {- bfdec_set(r, a);- }- ret = 0;- } else if (a->sign || prec == BF_PREC_INF) {- invalid_op:- bfdec_set_nan(r);- ret = BF_ST_INVALID_OP;- } else {- if (flags & BF_FLAG_RADPNT_PREC) {- prec1 = bf_max(floor_div(a->expn + 1, 2) + prec, 1);- } else {- prec1 = prec;- }- /* convert the mantissa to an integer with at least 2 *- prec + 4 digits */- n = (2 * (prec1 + 2) + 2 * LIMB_DIGITS - 1) / (2 * LIMB_DIGITS);- if (bfdec_resize(r, n))- goto fail;- a1 = bf_malloc(s, sizeof(limb_t) * 2 * n);- if (!a1)- goto fail;- n1 = bf_min(2 * n, a->len);- memset(a1, 0, (2 * n - n1) * sizeof(limb_t));- memcpy(a1 + 2 * n - n1, a->tab + a->len - n1, n1 * sizeof(limb_t));- if (a->expn & 1) {- res = mp_shr_dec(a1, a1, 2 * n, 1, 0);- } else {- res = 0;- }- /* normalize so that a1 >= B^(2*n)/4. Not need for n = 1- because mp_sqrtrem2_dec already does it */- k = 0;- if (n > 1) {- v = a1[2 * n - 1];- while (v < BF_DEC_BASE / 4) {- k++;- v *= 4;- }- if (k != 0)- mp_mul1_dec(a1, a1, 2 * n, 1 << (2 * k), 0);- }- if (mp_sqrtrem_dec(s, r->tab, a1, n)) {- bf_free(s, a1);- goto fail;- }- if (k != 0)- mp_div1_dec(r->tab, r->tab, n, 1 << k, 0);- if (!res) {- res = mp_scan_nz(a1, n + 1);- }- bf_free(s, a1);- if (!res) {- res = mp_scan_nz(a->tab, a->len - n1);- }- if (res != 0)- r->tab[0] |= 1;- r->sign = 0;- r->expn = (a->expn + 1) >> 1;- ret = bfdec_round(r, prec, flags);- }- return ret;- fail:- bfdec_set_nan(r);- return BF_ST_MEM_ERROR;-}--/* The rounding mode is always BF_RNDZ. Return BF_ST_OVERFLOW if there- is an overflow and 0 otherwise. No memory error is possible. */-int bfdec_get_int32(int *pres, const bfdec_t *a)-{- uint32_t v;- int ret;- if (a->expn >= BF_EXP_INF) {- ret = 0;- if (a->expn == BF_EXP_INF) {- v = (uint32_t)INT32_MAX + a->sign;- /* XXX: return overflow ? */- } else {- v = INT32_MAX;- }- } else if (a->expn <= 0) {- v = 0;- ret = 0;- } else if (a->expn <= 9) {- v = fast_shr_dec(a->tab[a->len - 1], LIMB_DIGITS - a->expn);- if (a->sign)- v = -v;- ret = 0;- } else if (a->expn == 10) {- uint64_t v1;- uint32_t v_max;-#if LIMB_BITS == 64- v1 = fast_shr_dec(a->tab[a->len - 1], LIMB_DIGITS - a->expn);-#else- v1 = (uint64_t)a->tab[a->len - 1] * 10 +- get_digit(a->tab, a->len, (a->len - 1) * LIMB_DIGITS - 1);-#endif- v_max = (uint32_t)INT32_MAX + a->sign;- if (v1 > v_max) {- v = v_max;- ret = BF_ST_OVERFLOW;- } else {- v = v1;- if (a->sign)- v = -v;- ret = 0;- }- } else {- v = (uint32_t)INT32_MAX + a->sign;- ret = BF_ST_OVERFLOW;- }- *pres = v;- return ret;-}--/* power to an integer with infinite precision */-int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b)-{- int ret, n_bits, i;- - assert(r != a);- if (b == 0)- return bfdec_set_ui(r, 1);- ret = bfdec_set(r, a);- n_bits = LIMB_BITS - clz(b);- for(i = n_bits - 2; i >= 0; i--) {- ret |= bfdec_mul(r, r, r, BF_PREC_INF, BF_RNDZ);- if ((b >> i) & 1)- ret |= bfdec_mul(r, r, a, BF_PREC_INF, BF_RNDZ);- }- return ret;-}--char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags)-{- return bf_ftoa_internal(plen, (const bf_t *)a, 10, prec, flags, TRUE);-}--int bfdec_atof(bfdec_t *r, const char *str, const char **pnext,- limb_t prec, bf_flags_t flags)-{- slimb_t dummy_exp;- return bf_atof_internal((bf_t *)r, &dummy_exp, str, pnext, 10, prec,- flags, TRUE);-}--#endif /* USE_BF_DEC */--#ifdef USE_FFT_MUL-/***************************************************************/-/* Integer multiplication with FFT */--/* or LIMB_BITS at bit position 'pos' in tab */-static inline void put_bits(limb_t *tab, limb_t len, slimb_t pos, limb_t val)-{- limb_t i;- int p;-- i = pos >> LIMB_LOG2_BITS;- p = pos & (LIMB_BITS - 1);- if (i < len)- tab[i] |= val << p;- if (p != 0) {- i++;- if (i < len) {- tab[i] |= val >> (LIMB_BITS - p);- }- }-}--#if defined(__AVX2__)--typedef double NTTLimb;--/* we must have: modulo >= 1 << NTT_MOD_LOG2_MIN */-#define NTT_MOD_LOG2_MIN 50-#define NTT_MOD_LOG2_MAX 51-#define NB_MODS 5-#define NTT_PROOT_2EXP 39-static const int ntt_int_bits[NB_MODS] = { 254, 203, 152, 101, 50, };--static const limb_t ntt_mods[NB_MODS] = { 0x00073a8000000001, 0x0007858000000001, 0x0007a38000000001, 0x0007a68000000001, 0x0007fd8000000001,-};--static const limb_t ntt_proot[2][NB_MODS] = {- { 0x00056198d44332c8, 0x0002eb5d640aad39, 0x00047e31eaa35fd0, 0x0005271ac118a150, 0x00075e0ce8442bd5, },- { 0x000461169761bcc5, 0x0002dac3cb2da688, 0x0004abc97751e3bf, 0x000656778fc8c485, 0x0000dc6469c269fa, },-};--static const limb_t ntt_mods_cr[NB_MODS * (NB_MODS - 1) / 2] = {- 0x00020e4da740da8e, 0x0004c3dc09c09c1d, 0x000063bd097b4271, 0x000799d8f18f18fd,- 0x0005384222222264, 0x000572b07c1f07fe, 0x00035cd08888889a,- 0x00066015555557e3, 0x000725960b60b623,- 0x0002fc1fa1d6ce12,-};--#else--typedef limb_t NTTLimb;--#if LIMB_BITS == 64--#define NTT_MOD_LOG2_MIN 61-#define NTT_MOD_LOG2_MAX 62-#define NB_MODS 5-#define NTT_PROOT_2EXP 51-static const int ntt_int_bits[NB_MODS] = { 307, 246, 185, 123, 61, };--static const limb_t ntt_mods[NB_MODS] = { 0x28d8000000000001, 0x2a88000000000001, 0x2ed8000000000001, 0x3508000000000001, 0x3aa8000000000001,-};--static const limb_t ntt_proot[2][NB_MODS] = {- { 0x1b8ea61034a2bea7, 0x21a9762de58206fb, 0x02ca782f0756a8ea, 0x278384537a3e50a1, 0x106e13fee74ce0ab, },- { 0x233513af133e13b8, 0x1d13140d1c6f75f1, 0x12cde57f97e3eeda, 0x0d6149e23cbe654f, 0x36cd204f522a1379, },-};--static const limb_t ntt_mods_cr[NB_MODS * (NB_MODS - 1) / 2] = {- 0x08a9ed097b425eea, 0x18a44aaaaaaaaab3, 0x2493f57f57f57f5d, 0x126b8d0649a7f8d4,- 0x09d80ed7303b5ccc, 0x25b8bcf3cf3cf3d5, 0x2ce6ce63398ce638,- 0x0e31fad40a57eb59, 0x02a3529fd4a7f52f,- 0x3a5493e93e93e94a,-};--#elif LIMB_BITS == 32--/* we must have: modulo >= 1 << NTT_MOD_LOG2_MIN */-#define NTT_MOD_LOG2_MIN 29-#define NTT_MOD_LOG2_MAX 30-#define NB_MODS 5-#define NTT_PROOT_2EXP 20-static const int ntt_int_bits[NB_MODS] = { 148, 119, 89, 59, 29, };--static const limb_t ntt_mods[NB_MODS] = { 0x0000000032b00001, 0x0000000033700001, 0x0000000036d00001, 0x0000000037300001, 0x000000003e500001,-};--static const limb_t ntt_proot[2][NB_MODS] = {- { 0x0000000032525f31, 0x0000000005eb3b37, 0x00000000246eda9f, 0x0000000035f25901, 0x00000000022f5768, },- { 0x00000000051eba1a, 0x00000000107be10e, 0x000000001cd574e0, 0x00000000053806e6, 0x000000002cd6bf98, },-};--static const limb_t ntt_mods_cr[NB_MODS * (NB_MODS - 1) / 2] = {- 0x000000000449559a, 0x000000001eba6ca9, 0x000000002ec18e46, 0x000000000860160b,- 0x000000000d321307, 0x000000000bf51120, 0x000000000f662938,- 0x000000000932ab3e, 0x000000002f40eef8,- 0x000000002e760905,-};--#endif /* LIMB_BITS */--#endif /* !AVX2 */--#if defined(__AVX2__)-#define NTT_TRIG_K_MAX 18-#else-#define NTT_TRIG_K_MAX 19-#endif--typedef struct BFNTTState {- bf_context_t *ctx;- - /* used for mul_mod_fast() */- limb_t ntt_mods_div[NB_MODS];-- limb_t ntt_proot_pow[NB_MODS][2][NTT_PROOT_2EXP + 1];- limb_t ntt_proot_pow_inv[NB_MODS][2][NTT_PROOT_2EXP + 1];- NTTLimb *ntt_trig[NB_MODS][2][NTT_TRIG_K_MAX + 1];- /* 1/2^n mod m */- limb_t ntt_len_inv[NB_MODS][NTT_PROOT_2EXP + 1][2];-#if defined(__AVX2__)- __m256d ntt_mods_cr_vec[NB_MODS * (NB_MODS - 1) / 2];- __m256d ntt_mods_vec[NB_MODS];- __m256d ntt_mods_inv_vec[NB_MODS];-#else- limb_t ntt_mods_cr_inv[NB_MODS * (NB_MODS - 1) / 2];-#endif-} BFNTTState;--static NTTLimb *get_trig(BFNTTState *s, int k, int inverse, int m_idx);--/* add modulo with up to (LIMB_BITS-1) bit modulo */-static inline limb_t add_mod(limb_t a, limb_t b, limb_t m)-{- limb_t r;- r = a + b;- if (r >= m)- r -= m;- return r;-}--/* sub modulo with up to LIMB_BITS bit modulo */-static inline limb_t sub_mod(limb_t a, limb_t b, limb_t m)-{- limb_t r;- r = a - b;- if (r > a)- r += m;- return r;-}--/* return (r0+r1*B) mod m - precondition: 0 <= r0+r1*B < 2^(64+NTT_MOD_LOG2_MIN) -*/-static inline limb_t mod_fast(dlimb_t r, - limb_t m, limb_t m_inv)-{- limb_t a1, q, t0, r1, r0;- - a1 = r >> NTT_MOD_LOG2_MIN;- - q = ((dlimb_t)a1 * m_inv) >> LIMB_BITS;- r = r - (dlimb_t)q * m - m * 2;- r1 = r >> LIMB_BITS;- t0 = (slimb_t)r1 >> 1;- r += m & t0;- r0 = r;- r1 = r >> LIMB_BITS;- r0 += m & r1;- return r0;-}--/* faster version using precomputed modulo inverse. - precondition: 0 <= a * b < 2^(64+NTT_MOD_LOG2_MIN) */-static inline limb_t mul_mod_fast(limb_t a, limb_t b, - limb_t m, limb_t m_inv)-{- dlimb_t r;- r = (dlimb_t)a * (dlimb_t)b;- return mod_fast(r, m, m_inv);-}--static inline limb_t init_mul_mod_fast(limb_t m)-{- dlimb_t t;- assert(m < (limb_t)1 << NTT_MOD_LOG2_MAX);- assert(m >= (limb_t)1 << NTT_MOD_LOG2_MIN);- t = (dlimb_t)1 << (LIMB_BITS + NTT_MOD_LOG2_MIN);- return t / m;-}--/* Faster version used when the multiplier is constant. 0 <= a < 2^64,- 0 <= b < m. */-static inline limb_t mul_mod_fast2(limb_t a, limb_t b, - limb_t m, limb_t b_inv)-{- limb_t r, q;-- q = ((dlimb_t)a * (dlimb_t)b_inv) >> LIMB_BITS;- r = a * b - q * m;- if (r >= m)- r -= m;- return r;-}--/* Faster version used when the multiplier is constant. 0 <= a < 2^64,- 0 <= b < m. Let r = a * b mod m. The return value is 'r' or 'r +- m'. */-static inline limb_t mul_mod_fast3(limb_t a, limb_t b, - limb_t m, limb_t b_inv)-{- limb_t r, q;-- q = ((dlimb_t)a * (dlimb_t)b_inv) >> LIMB_BITS;- r = a * b - q * m;- return r;-}--static inline limb_t init_mul_mod_fast2(limb_t b, limb_t m)-{- return ((dlimb_t)b << LIMB_BITS) / m;-}--#ifdef __AVX2__--static inline limb_t ntt_limb_to_int(NTTLimb a, limb_t m)-{- slimb_t v;- v = a;- if (v < 0)- v += m;- if (v >= m)- v -= m;- return v;-}--static inline NTTLimb int_to_ntt_limb(limb_t a, limb_t m)-{- return (slimb_t)a;-}--static inline NTTLimb int_to_ntt_limb2(limb_t a, limb_t m)-{- if (a >= (m / 2))- a -= m;- return (slimb_t)a;-}--/* return r + m if r < 0 otherwise r. */-static inline __m256d ntt_mod1(__m256d r, __m256d m)-{- return _mm256_blendv_pd(r, r + m, r);-}--/* input: abs(r) < 2 * m. Output: abs(r) < m */-static inline __m256d ntt_mod(__m256d r, __m256d mf, __m256d m2f)-{- return _mm256_blendv_pd(r, r + m2f, r) - mf;-}--/* input: abs(a*b) < 2 * m^2, output: abs(r) < m */-static inline __m256d ntt_mul_mod(__m256d a, __m256d b, __m256d mf,- __m256d m_inv)-{- __m256d r, q, ab1, ab0, qm0, qm1;- ab1 = a * b;- q = _mm256_round_pd(ab1 * m_inv, 0); /* round to nearest */- qm1 = q * mf;- qm0 = _mm256_fmsub_pd(q, mf, qm1); /* low part */- ab0 = _mm256_fmsub_pd(a, b, ab1); /* low part */- r = (ab1 - qm1) + (ab0 - qm0);- return r;-}--static void *bf_aligned_malloc(bf_context_t *s, size_t size, size_t align)-{- void *ptr;- void **ptr1;- ptr = bf_malloc(s, size + sizeof(void *) + align - 1);- if (!ptr)- return NULL;- ptr1 = (void **)(((uintptr_t)ptr + sizeof(void *) + align - 1) &- ~(align - 1));- ptr1[-1] = ptr;- return ptr1;-}--static void bf_aligned_free(bf_context_t *s, void *ptr)-{- if (!ptr)- return;- bf_free(s, ((void **)ptr)[-1]);-}--static void *ntt_malloc(BFNTTState *s, size_t size)-{- return bf_aligned_malloc(s->ctx, size, 64);-}--static void ntt_free(BFNTTState *s, void *ptr)-{- bf_aligned_free(s->ctx, ptr);-}--static no_inline int ntt_fft(BFNTTState *s,- NTTLimb *out_buf, NTTLimb *in_buf,- NTTLimb *tmp_buf, int fft_len_log2,- int inverse, int m_idx)-{- limb_t nb_blocks, fft_per_block, p, k, n, stride_in, i, j;- NTTLimb *tab_in, *tab_out, *tmp, *trig;- __m256d m_inv, mf, m2f, c, a0, a1, b0, b1;- limb_t m;- int l;- - m = ntt_mods[m_idx];- - m_inv = _mm256_set1_pd(1.0 / (double)m);- mf = _mm256_set1_pd(m);- m2f = _mm256_set1_pd(m * 2);-- n = (limb_t)1 << fft_len_log2;- assert(n >= 8);- stride_in = n / 2;-- tab_in = in_buf;- tab_out = tmp_buf;- trig = get_trig(s, fft_len_log2, inverse, m_idx);- if (!trig)- return -1;- p = 0;- for(k = 0; k < stride_in; k += 4) {- a0 = _mm256_load_pd(&tab_in[k]);- a1 = _mm256_load_pd(&tab_in[k + stride_in]);- c = _mm256_load_pd(trig);- trig += 4;- b0 = ntt_mod(a0 + a1, mf, m2f);- b1 = ntt_mul_mod(a0 - a1, c, mf, m_inv);- a0 = _mm256_permute2f128_pd(b0, b1, 0x20);- a1 = _mm256_permute2f128_pd(b0, b1, 0x31);- a0 = _mm256_permute4x64_pd(a0, 0xd8);- a1 = _mm256_permute4x64_pd(a1, 0xd8);- _mm256_store_pd(&tab_out[p], a0);- _mm256_store_pd(&tab_out[p + 4], a1);- p += 2 * 4;- }- tmp = tab_in;- tab_in = tab_out;- tab_out = tmp;-- trig = get_trig(s, fft_len_log2 - 1, inverse, m_idx);- if (!trig)- return -1;- p = 0;- for(k = 0; k < stride_in; k += 4) {- a0 = _mm256_load_pd(&tab_in[k]);- a1 = _mm256_load_pd(&tab_in[k + stride_in]);- c = _mm256_setr_pd(trig[0], trig[0], trig[1], trig[1]);- trig += 2;- b0 = ntt_mod(a0 + a1, mf, m2f);- b1 = ntt_mul_mod(a0 - a1, c, mf, m_inv);- a0 = _mm256_permute2f128_pd(b0, b1, 0x20);- a1 = _mm256_permute2f128_pd(b0, b1, 0x31);- _mm256_store_pd(&tab_out[p], a0);- _mm256_store_pd(&tab_out[p + 4], a1);- p += 2 * 4;- }- tmp = tab_in;- tab_in = tab_out;- tab_out = tmp;- - nb_blocks = n / 4;- fft_per_block = 4;-- l = fft_len_log2 - 2;- while (nb_blocks != 2) {- nb_blocks >>= 1;- p = 0;- k = 0;- trig = get_trig(s, l, inverse, m_idx);- if (!trig)- return -1;- for(i = 0; i < nb_blocks; i++) {- c = _mm256_set1_pd(trig[0]);- trig++;- for(j = 0; j < fft_per_block; j += 4) {- a0 = _mm256_load_pd(&tab_in[k + j]);- a1 = _mm256_load_pd(&tab_in[k + j + stride_in]);- b0 = ntt_mod(a0 + a1, mf, m2f);- b1 = ntt_mul_mod(a0 - a1, c, mf, m_inv);- _mm256_store_pd(&tab_out[p + j], b0);- _mm256_store_pd(&tab_out[p + j + fft_per_block], b1);- }- k += fft_per_block;- p += 2 * fft_per_block;- }- fft_per_block <<= 1;- l--;- tmp = tab_in;- tab_in = tab_out;- tab_out = tmp;- }-- tab_out = out_buf;- for(k = 0; k < stride_in; k += 4) {- a0 = _mm256_load_pd(&tab_in[k]);- a1 = _mm256_load_pd(&tab_in[k + stride_in]);- b0 = ntt_mod(a0 + a1, mf, m2f);- b1 = ntt_mod(a0 - a1, mf, m2f);- _mm256_store_pd(&tab_out[k], b0);- _mm256_store_pd(&tab_out[k + stride_in], b1);- }- return 0;-}--static void ntt_vec_mul(BFNTTState *s,- NTTLimb *tab1, NTTLimb *tab2, limb_t fft_len_log2,- int k_tot, int m_idx)-{- limb_t i, c_inv, n, m;- __m256d m_inv, mf, a, b, c;- - m = ntt_mods[m_idx];- c_inv = s->ntt_len_inv[m_idx][k_tot][0];- m_inv = _mm256_set1_pd(1.0 / (double)m);- mf = _mm256_set1_pd(m);- c = _mm256_set1_pd(int_to_ntt_limb(c_inv, m));- n = (limb_t)1 << fft_len_log2;- for(i = 0; i < n; i += 4) {- a = _mm256_load_pd(&tab1[i]);- b = _mm256_load_pd(&tab2[i]);- a = ntt_mul_mod(a, b, mf, m_inv);- a = ntt_mul_mod(a, c, mf, m_inv);- _mm256_store_pd(&tab1[i], a);- }-}--static no_inline void mul_trig(NTTLimb *buf,- limb_t n, limb_t c1, limb_t m, limb_t m_inv1)-{- limb_t i, c2, c3, c4;- __m256d c, c_mul, a0, mf, m_inv;- assert(n >= 2);- - mf = _mm256_set1_pd(m);- m_inv = _mm256_set1_pd(1.0 / (double)m);-- c2 = mul_mod_fast(c1, c1, m, m_inv1);- c3 = mul_mod_fast(c2, c1, m, m_inv1);- c4 = mul_mod_fast(c2, c2, m, m_inv1);- c = _mm256_setr_pd(1, int_to_ntt_limb(c1, m),- int_to_ntt_limb(c2, m), int_to_ntt_limb(c3, m));- c_mul = _mm256_set1_pd(int_to_ntt_limb(c4, m));- for(i = 0; i < n; i += 4) {- a0 = _mm256_load_pd(&buf[i]);- a0 = ntt_mul_mod(a0, c, mf, m_inv);- _mm256_store_pd(&buf[i], a0);- c = ntt_mul_mod(c, c_mul, mf, m_inv);- }-}--#else--static void *ntt_malloc(BFNTTState *s, size_t size)-{- return bf_malloc(s->ctx, size);-}--static void ntt_free(BFNTTState *s, void *ptr)-{- bf_free(s->ctx, ptr);-}--static inline limb_t ntt_limb_to_int(NTTLimb a, limb_t m)-{- if (a >= m)- a -= m;- return a;-}--static inline NTTLimb int_to_ntt_limb(slimb_t a, limb_t m)-{- return a;-}--static no_inline int ntt_fft(BFNTTState *s, NTTLimb *out_buf, NTTLimb *in_buf,- NTTLimb *tmp_buf, int fft_len_log2,- int inverse, int m_idx)-{- limb_t nb_blocks, fft_per_block, p, k, n, stride_in, i, j, m, m2;- NTTLimb *tab_in, *tab_out, *tmp, a0, a1, b0, b1, c, *trig, c_inv;- int l;- - m = ntt_mods[m_idx];- m2 = 2 * m;- n = (limb_t)1 << fft_len_log2;- nb_blocks = n;- fft_per_block = 1;- stride_in = n / 2;- tab_in = in_buf;- tab_out = tmp_buf;- l = fft_len_log2;- while (nb_blocks != 2) {- nb_blocks >>= 1;- p = 0;- k = 0;- trig = get_trig(s, l, inverse, m_idx);- if (!trig)- return -1;- for(i = 0; i < nb_blocks; i++) {- c = trig[0];- c_inv = trig[1];- trig += 2;- for(j = 0; j < fft_per_block; j++) {- a0 = tab_in[k + j];- a1 = tab_in[k + j + stride_in];- b0 = add_mod(a0, a1, m2);- b1 = a0 - a1 + m2;- b1 = mul_mod_fast3(b1, c, m, c_inv);- tab_out[p + j] = b0;- tab_out[p + j + fft_per_block] = b1;- }- k += fft_per_block;- p += 2 * fft_per_block;- }- fft_per_block <<= 1;- l--;- tmp = tab_in;- tab_in = tab_out;- tab_out = tmp;- }- /* no twiddle in last step */- tab_out = out_buf; - for(k = 0; k < stride_in; k++) {- a0 = tab_in[k];- a1 = tab_in[k + stride_in];- b0 = add_mod(a0, a1, m2);- b1 = sub_mod(a0, a1, m2);- tab_out[k] = b0;- tab_out[k + stride_in] = b1;- }- return 0;-}--static void ntt_vec_mul(BFNTTState *s,- NTTLimb *tab1, NTTLimb *tab2, int fft_len_log2,- int k_tot, int m_idx)-{- limb_t i, norm, norm_inv, a, n, m, m_inv;- - m = ntt_mods[m_idx];- m_inv = s->ntt_mods_div[m_idx];- norm = s->ntt_len_inv[m_idx][k_tot][0];- norm_inv = s->ntt_len_inv[m_idx][k_tot][1];- n = (limb_t)1 << fft_len_log2;- for(i = 0; i < n; i++) {- a = tab1[i];- /* need to reduce the range so that the product is <- 2^(LIMB_BITS+NTT_MOD_LOG2_MIN) */- if (a >= m)- a -= m;- a = mul_mod_fast(a, tab2[i], m, m_inv);- a = mul_mod_fast3(a, norm, m, norm_inv);- tab1[i] = a;- }-}--static no_inline void mul_trig(NTTLimb *buf,- limb_t n, limb_t c_mul, limb_t m, limb_t m_inv)-{- limb_t i, c0, c_mul_inv;- - c0 = 1;- c_mul_inv = init_mul_mod_fast2(c_mul, m);- for(i = 0; i < n; i++) {- buf[i] = mul_mod_fast(buf[i], c0, m, m_inv);- c0 = mul_mod_fast2(c0, c_mul, m, c_mul_inv);- }-}--#endif /* !AVX2 */--static no_inline NTTLimb *get_trig(BFNTTState *s,- int k, int inverse, int m_idx)-{- NTTLimb *tab;- limb_t i, n2, c, c_mul, m, c_mul_inv;- - if (k > NTT_TRIG_K_MAX)- return NULL;-- tab = s->ntt_trig[m_idx][inverse][k];- if (tab)- return tab;- n2 = (limb_t)1 << (k - 1);- m = ntt_mods[m_idx];-#ifdef __AVX2__- tab = ntt_malloc(s, sizeof(NTTLimb) * n2);-#else- tab = ntt_malloc(s, sizeof(NTTLimb) * n2 * 2);-#endif- if (!tab)- return NULL;- c = 1;- c_mul = s->ntt_proot_pow[m_idx][inverse][k];- c_mul_inv = s->ntt_proot_pow_inv[m_idx][inverse][k];- for(i = 0; i < n2; i++) {-#ifdef __AVX2__- tab[i] = int_to_ntt_limb2(c, m);-#else- tab[2 * i] = int_to_ntt_limb(c, m);- tab[2 * i + 1] = init_mul_mod_fast2(c, m);-#endif- c = mul_mod_fast2(c, c_mul, m, c_mul_inv);- }- s->ntt_trig[m_idx][inverse][k] = tab;- return tab;-}--void fft_clear_cache(bf_context_t *s1)-{- int m_idx, inverse, k;- BFNTTState *s = s1->ntt_state;- if (s) {- for(m_idx = 0; m_idx < NB_MODS; m_idx++) {- for(inverse = 0; inverse < 2; inverse++) {- for(k = 0; k < NTT_TRIG_K_MAX + 1; k++) {- if (s->ntt_trig[m_idx][inverse][k]) {- ntt_free(s, s->ntt_trig[m_idx][inverse][k]);- s->ntt_trig[m_idx][inverse][k] = NULL;- }- }- }- }-#if defined(__AVX2__)- bf_aligned_free(s1, s);-#else- bf_free(s1, s);-#endif- s1->ntt_state = NULL;- }-}--#define STRIP_LEN 16--/* dst = buf1, src = buf2 */-static int ntt_fft_partial(BFNTTState *s, NTTLimb *buf1,- int k1, int k2, limb_t n1, limb_t n2, int inverse,- limb_t m_idx)-{- limb_t i, j, c_mul, c0, m, m_inv, strip_len, l;- NTTLimb *buf2, *buf3;- - buf2 = NULL;- buf3 = ntt_malloc(s, sizeof(NTTLimb) * n1);- if (!buf3)- goto fail;- if (k2 == 0) {- if (ntt_fft(s, buf1, buf1, buf3, k1, inverse, m_idx))- goto fail;- } else {- strip_len = STRIP_LEN;- buf2 = ntt_malloc(s, sizeof(NTTLimb) * n1 * strip_len);- if (!buf2)- goto fail;- m = ntt_mods[m_idx];- m_inv = s->ntt_mods_div[m_idx];- c0 = s->ntt_proot_pow[m_idx][inverse][k1 + k2];- c_mul = 1;- assert((n2 % strip_len) == 0);- for(j = 0; j < n2; j += strip_len) {- for(i = 0; i < n1; i++) {- for(l = 0; l < strip_len; l++) {- buf2[i + l * n1] = buf1[i * n2 + (j + l)];- }- }- for(l = 0; l < strip_len; l++) {- if (inverse)- mul_trig(buf2 + l * n1, n1, c_mul, m, m_inv);- if (ntt_fft(s, buf2 + l * n1, buf2 + l * n1, buf3, k1, inverse, m_idx))- goto fail;- if (!inverse)- mul_trig(buf2 + l * n1, n1, c_mul, m, m_inv);- c_mul = mul_mod_fast(c_mul, c0, m, m_inv);- }- - for(i = 0; i < n1; i++) {- for(l = 0; l < strip_len; l++) {- buf1[i * n2 + (j + l)] = buf2[i + l *n1];- }- }- }- ntt_free(s, buf2);- }- ntt_free(s, buf3);- return 0;- fail:- ntt_free(s, buf2);- ntt_free(s, buf3);- return -1;-}---/* dst = buf1, src = buf2, tmp = buf3 */-static int ntt_conv(BFNTTState *s, NTTLimb *buf1, NTTLimb *buf2,- int k, int k_tot, limb_t m_idx)-{- limb_t n1, n2, i;- int k1, k2;- - if (k <= NTT_TRIG_K_MAX) {- k1 = k;- } else {- /* recursive split of the FFT */- k1 = bf_min(k / 2, NTT_TRIG_K_MAX);- }- k2 = k - k1;- n1 = (limb_t)1 << k1;- n2 = (limb_t)1 << k2;- - if (ntt_fft_partial(s, buf1, k1, k2, n1, n2, 0, m_idx))- return -1;- if (ntt_fft_partial(s, buf2, k1, k2, n1, n2, 0, m_idx))- return -1;- if (k2 == 0) {- ntt_vec_mul(s, buf1, buf2, k, k_tot, m_idx);- } else {- for(i = 0; i < n1; i++) {- ntt_conv(s, buf1 + i * n2, buf2 + i * n2, k2, k_tot, m_idx);- }- }- if (ntt_fft_partial(s, buf1, k1, k2, n1, n2, 1, m_idx))- return -1;- return 0;-}---static no_inline void limb_to_ntt(BFNTTState *s,- NTTLimb *tabr, limb_t fft_len,- const limb_t *taba, limb_t a_len, int dpl,- int first_m_idx, int nb_mods)-{- slimb_t i, n;- dlimb_t a, b;- int j, shift;- limb_t base_mask1, a0, a1, a2, r, m, m_inv;- -#if 0- for(i = 0; i < a_len; i++) {- printf("%" PRId64 ": " FMT_LIMB "\n",- (int64_t)i, taba[i]);- }-#endif - memset(tabr, 0, sizeof(NTTLimb) * fft_len * nb_mods);- shift = dpl & (LIMB_BITS - 1);- if (shift == 0)- base_mask1 = -1;- else- base_mask1 = ((limb_t)1 << shift) - 1;- n = bf_min(fft_len, (a_len * LIMB_BITS + dpl - 1) / dpl);- for(i = 0; i < n; i++) {- a0 = get_bits(taba, a_len, i * dpl);- if (dpl <= LIMB_BITS) {- a0 &= base_mask1;- a = a0;- } else {- a1 = get_bits(taba, a_len, i * dpl + LIMB_BITS);- if (dpl <= (LIMB_BITS + NTT_MOD_LOG2_MIN)) {- a = a0 | ((dlimb_t)(a1 & base_mask1) << LIMB_BITS);- } else {- if (dpl > 2 * LIMB_BITS) {- a2 = get_bits(taba, a_len, i * dpl + LIMB_BITS * 2) &- base_mask1;- } else {- a1 &= base_mask1;- a2 = 0;- }- // printf("a=0x%016lx%016lx%016lx\n", a2, a1, a0);- a = (a0 >> (LIMB_BITS - NTT_MOD_LOG2_MAX + NTT_MOD_LOG2_MIN)) |- ((dlimb_t)a1 << (NTT_MOD_LOG2_MAX - NTT_MOD_LOG2_MIN)) |- ((dlimb_t)a2 << (LIMB_BITS + NTT_MOD_LOG2_MAX - NTT_MOD_LOG2_MIN));- a0 &= ((limb_t)1 << (LIMB_BITS - NTT_MOD_LOG2_MAX + NTT_MOD_LOG2_MIN)) - 1;- }- }- for(j = 0; j < nb_mods; j++) {- m = ntt_mods[first_m_idx + j];- m_inv = s->ntt_mods_div[first_m_idx + j];- r = mod_fast(a, m, m_inv);- if (dpl > (LIMB_BITS + NTT_MOD_LOG2_MIN)) {- b = ((dlimb_t)r << (LIMB_BITS - NTT_MOD_LOG2_MAX + NTT_MOD_LOG2_MIN)) | a0;- r = mod_fast(b, m, m_inv);- }- tabr[i + j * fft_len] = int_to_ntt_limb(r, m);- }- }-}--#if defined(__AVX2__)--#define VEC_LEN 4--typedef union {- __m256d v;- double d[4];-} VecUnion;--static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len,- const NTTLimb *buf, int fft_len_log2, int dpl,- int nb_mods)-{- const limb_t *mods = ntt_mods + NB_MODS - nb_mods;- const __m256d *mods_cr_vec, *mf, *m_inv;- VecUnion y[NB_MODS];- limb_t u[NB_MODS], carry[NB_MODS], fft_len, base_mask1, r;- slimb_t i, len, pos;- int j, k, l, shift, n_limb1, p;- dlimb_t t;- - j = NB_MODS * (NB_MODS - 1) / 2 - nb_mods * (nb_mods - 1) / 2;- mods_cr_vec = s->ntt_mods_cr_vec + j;- mf = s->ntt_mods_vec + NB_MODS - nb_mods;- m_inv = s->ntt_mods_inv_vec + NB_MODS - nb_mods;- - shift = dpl & (LIMB_BITS - 1);- if (shift == 0)- base_mask1 = -1;- else- base_mask1 = ((limb_t)1 << shift) - 1;- n_limb1 = ((unsigned)dpl - 1) / LIMB_BITS;- for(j = 0; j < NB_MODS; j++) - carry[j] = 0;- for(j = 0; j < NB_MODS; j++) - u[j] = 0; /* avoid warnings */- memset(tabr, 0, sizeof(limb_t) * r_len);- fft_len = (limb_t)1 << fft_len_log2;- len = bf_min(fft_len, (r_len * LIMB_BITS + dpl - 1) / dpl);- len = (len + VEC_LEN - 1) & ~(VEC_LEN - 1);- i = 0;- while (i < len) {- for(j = 0; j < nb_mods; j++)- y[j].v = *(__m256d *)&buf[i + fft_len * j];-- /* Chinese remainder to get mixed radix representation */- l = 0;- for(j = 0; j < nb_mods - 1; j++) {- y[j].v = ntt_mod1(y[j].v, mf[j]);- for(k = j + 1; k < nb_mods; k++) {- y[k].v = ntt_mul_mod(y[k].v - y[j].v,- mods_cr_vec[l], mf[k], m_inv[k]);- l++;- }- }- y[j].v = ntt_mod1(y[j].v, mf[j]);- - for(p = 0; p < VEC_LEN; p++) {- /* back to normal representation */- u[0] = (int64_t)y[nb_mods - 1].d[p];- l = 1;- for(j = nb_mods - 2; j >= 1; j--) {- r = (int64_t)y[j].d[p];- for(k = 0; k < l; k++) {- t = (dlimb_t)u[k] * mods[j] + r;- r = t >> LIMB_BITS;- u[k] = t;- }- u[l] = r;- l++;- }- /* XXX: for nb_mods = 5, l should be 4 */- - /* last step adds the carry */- r = (int64_t)y[0].d[p];- for(k = 0; k < l; k++) {- t = (dlimb_t)u[k] * mods[j] + r + carry[k];- r = t >> LIMB_BITS;- u[k] = t;- }- u[l] = r + carry[l];--#if 0- printf("%" PRId64 ": ", i);- for(j = nb_mods - 1; j >= 0; j--) {- printf(" %019" PRIu64, u[j]);- }- printf("\n");-#endif- - /* write the digits */- pos = i * dpl;- for(j = 0; j < n_limb1; j++) {- put_bits(tabr, r_len, pos, u[j]);- pos += LIMB_BITS;- }- put_bits(tabr, r_len, pos, u[n_limb1] & base_mask1);- /* shift by dpl digits and set the carry */- if (shift == 0) {- for(j = n_limb1 + 1; j < nb_mods; j++)- carry[j - (n_limb1 + 1)] = u[j];- } else {- for(j = n_limb1; j < nb_mods - 1; j++) {- carry[j - n_limb1] = (u[j] >> shift) |- (u[j + 1] << (LIMB_BITS - shift));- }- carry[nb_mods - 1 - n_limb1] = u[nb_mods - 1] >> shift;- }- i++;- }- }-}-#else-static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len,- const NTTLimb *buf, int fft_len_log2, int dpl,- int nb_mods)-{- const limb_t *mods = ntt_mods + NB_MODS - nb_mods;- const limb_t *mods_cr, *mods_cr_inv;- limb_t y[NB_MODS], u[NB_MODS], carry[NB_MODS], fft_len, base_mask1, r;- slimb_t i, len, pos;- int j, k, l, shift, n_limb1;- dlimb_t t;- - j = NB_MODS * (NB_MODS - 1) / 2 - nb_mods * (nb_mods - 1) / 2;- mods_cr = ntt_mods_cr + j;- mods_cr_inv = s->ntt_mods_cr_inv + j;-- shift = dpl & (LIMB_BITS - 1);- if (shift == 0)- base_mask1 = -1;- else- base_mask1 = ((limb_t)1 << shift) - 1;- n_limb1 = ((unsigned)dpl - 1) / LIMB_BITS;- for(j = 0; j < NB_MODS; j++) - carry[j] = 0;- for(j = 0; j < NB_MODS; j++) - u[j] = 0; /* avoid warnings */- memset(tabr, 0, sizeof(limb_t) * r_len);- fft_len = (limb_t)1 << fft_len_log2;- len = bf_min(fft_len, (r_len * LIMB_BITS + dpl - 1) / dpl);- for(i = 0; i < len; i++) {- for(j = 0; j < nb_mods; j++) {- y[j] = ntt_limb_to_int(buf[i + fft_len * j], mods[j]);- }-- /* Chinese remainder to get mixed radix representation */- l = 0;- for(j = 0; j < nb_mods - 1; j++) {- for(k = j + 1; k < nb_mods; k++) {- limb_t m;- m = mods[k];- /* Note: there is no overflow in the sub_mod() because- the modulos are sorted by increasing order */- y[k] = mul_mod_fast2(y[k] - y[j] + m, - mods_cr[l], m, mods_cr_inv[l]);- l++;- }- }- - /* back to normal representation */- u[0] = y[nb_mods - 1];- l = 1;- for(j = nb_mods - 2; j >= 1; j--) {- r = y[j];- for(k = 0; k < l; k++) {- t = (dlimb_t)u[k] * mods[j] + r;- r = t >> LIMB_BITS;- u[k] = t;- }- u[l] = r;- l++;- }- - /* last step adds the carry */- r = y[0];- for(k = 0; k < l; k++) {- t = (dlimb_t)u[k] * mods[j] + r + carry[k];- r = t >> LIMB_BITS;- u[k] = t;- }- u[l] = r + carry[l];--#if 0- printf("%" PRId64 ": ", (int64_t)i);- for(j = nb_mods - 1; j >= 0; j--) {- printf(" " FMT_LIMB, u[j]);- }- printf("\n");-#endif- - /* write the digits */- pos = i * dpl;- for(j = 0; j < n_limb1; j++) {- put_bits(tabr, r_len, pos, u[j]);- pos += LIMB_BITS;- }- put_bits(tabr, r_len, pos, u[n_limb1] & base_mask1);- /* shift by dpl digits and set the carry */- if (shift == 0) {- for(j = n_limb1 + 1; j < nb_mods; j++)- carry[j - (n_limb1 + 1)] = u[j];- } else {- for(j = n_limb1; j < nb_mods - 1; j++) {- carry[j - n_limb1] = (u[j] >> shift) |- (u[j + 1] << (LIMB_BITS - shift));- }- carry[nb_mods - 1 - n_limb1] = u[nb_mods - 1] >> shift;- }- }-}-#endif--static int ntt_static_init(bf_context_t *s1)-{- BFNTTState *s;- int inverse, i, j, k, l;- limb_t c, c_inv, c_inv2, m, m_inv;-- if (s1->ntt_state)- return 0;-#if defined(__AVX2__)- s = bf_aligned_malloc(s1, sizeof(*s), 64);-#else- s = bf_malloc(s1, sizeof(*s));-#endif- if (!s)- return -1;- memset(s, 0, sizeof(*s));- s1->ntt_state = s;- s->ctx = s1;- - for(j = 0; j < NB_MODS; j++) {- m = ntt_mods[j];- m_inv = init_mul_mod_fast(m);- s->ntt_mods_div[j] = m_inv;-#if defined(__AVX2__)- s->ntt_mods_vec[j] = _mm256_set1_pd(m);- s->ntt_mods_inv_vec[j] = _mm256_set1_pd(1.0 / (double)m);-#endif- c_inv2 = (m + 1) / 2; /* 1/2 */- c_inv = 1;- for(i = 0; i <= NTT_PROOT_2EXP; i++) {- s->ntt_len_inv[j][i][0] = c_inv;- s->ntt_len_inv[j][i][1] = init_mul_mod_fast2(c_inv, m);- c_inv = mul_mod_fast(c_inv, c_inv2, m, m_inv);- }-- for(inverse = 0; inverse < 2; inverse++) {- c = ntt_proot[inverse][j];- for(i = 0; i < NTT_PROOT_2EXP; i++) {- s->ntt_proot_pow[j][inverse][NTT_PROOT_2EXP - i] = c;- s->ntt_proot_pow_inv[j][inverse][NTT_PROOT_2EXP - i] =- init_mul_mod_fast2(c, m);- c = mul_mod_fast(c, c, m, m_inv);- }- }- }-- l = 0;- for(j = 0; j < NB_MODS - 1; j++) {- for(k = j + 1; k < NB_MODS; k++) {-#if defined(__AVX2__)- s->ntt_mods_cr_vec[l] = _mm256_set1_pd(int_to_ntt_limb2(ntt_mods_cr[l],- ntt_mods[k]));-#else- s->ntt_mods_cr_inv[l] = init_mul_mod_fast2(ntt_mods_cr[l],- ntt_mods[k]);-#endif- l++;- }- }- return 0;-}--int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len)-{- int dpl, fft_len_log2, n_bits, nb_mods, dpl_found, fft_len_log2_found;- int int_bits, nb_mods_found;- limb_t cost, min_cost;- - min_cost = -1;- dpl_found = 0;- nb_mods_found = 4;- fft_len_log2_found = 0;- for(nb_mods = 3; nb_mods <= NB_MODS; nb_mods++) {- int_bits = ntt_int_bits[NB_MODS - nb_mods];- dpl = bf_min((int_bits - 4) / 2,- 2 * LIMB_BITS + 2 * NTT_MOD_LOG2_MIN - NTT_MOD_LOG2_MAX);- for(;;) {- fft_len_log2 = ceil_log2((len * LIMB_BITS + dpl - 1) / dpl);- if (fft_len_log2 > NTT_PROOT_2EXP)- goto next;- n_bits = fft_len_log2 + 2 * dpl;- if (n_bits <= int_bits) {- cost = ((limb_t)(fft_len_log2 + 1) << fft_len_log2) * nb_mods;- // printf("n=%d dpl=%d: cost=%" PRId64 "\n", nb_mods, dpl, (int64_t)cost);- if (cost < min_cost) {- min_cost = cost;- dpl_found = dpl;- nb_mods_found = nb_mods;- fft_len_log2_found = fft_len_log2;- }- break;- }- dpl--;- if (dpl == 0)- break;- }- next: ;- }- if (!dpl_found)- abort();- /* limit dpl if possible to reduce fixed cost of limb/NTT conversion */- if (dpl_found > (LIMB_BITS + NTT_MOD_LOG2_MIN) &&- ((limb_t)(LIMB_BITS + NTT_MOD_LOG2_MIN) << fft_len_log2_found) >=- len * LIMB_BITS) {- dpl_found = LIMB_BITS + NTT_MOD_LOG2_MIN;- }- *pnb_mods = nb_mods_found;- *pdpl = dpl_found;- return fft_len_log2_found;-}--/* return 0 if OK, -1 if memory error */-static no_inline int fft_mul(bf_context_t *s1,- bf_t *res, limb_t *a_tab, limb_t a_len,- limb_t *b_tab, limb_t b_len, int mul_flags)-{- BFNTTState *s;- int dpl, fft_len_log2, j, nb_mods, reduced_mem;- slimb_t len, fft_len;- NTTLimb *buf1, *buf2, *ptr;-#if defined(USE_MUL_CHECK)- limb_t ha, hb, hr, h_ref;-#endif- - if (ntt_static_init(s1))- return -1;- s = s1->ntt_state;- - /* find the optimal number of digits per limb (dpl) */- len = a_len + b_len;- fft_len_log2 = bf_get_fft_size(&dpl, &nb_mods, len);- fft_len = (uint64_t)1 << fft_len_log2;- // printf("len=%" PRId64 " fft_len_log2=%d dpl=%d\n", len, fft_len_log2, dpl);-#if defined(USE_MUL_CHECK)- ha = mp_mod1(a_tab, a_len, BF_CHKSUM_MOD, 0);- hb = mp_mod1(b_tab, b_len, BF_CHKSUM_MOD, 0);-#endif- if ((mul_flags & (FFT_MUL_R_OVERLAP_A | FFT_MUL_R_OVERLAP_B)) == 0) {- if (!(mul_flags & FFT_MUL_R_NORESIZE))- bf_resize(res, 0);- } else if (mul_flags & FFT_MUL_R_OVERLAP_B) {- limb_t *tmp_tab, tmp_len;- /* it is better to free 'b' first */- tmp_tab = a_tab;- a_tab = b_tab;- b_tab = tmp_tab;- tmp_len = a_len;- a_len = b_len;- b_len = tmp_len;- }- buf1 = ntt_malloc(s, sizeof(NTTLimb) * fft_len * nb_mods);- if (!buf1)- return -1;- limb_to_ntt(s, buf1, fft_len, a_tab, a_len, dpl,- NB_MODS - nb_mods, nb_mods);- if ((mul_flags & (FFT_MUL_R_OVERLAP_A | FFT_MUL_R_OVERLAP_B)) == - FFT_MUL_R_OVERLAP_A) {- if (!(mul_flags & FFT_MUL_R_NORESIZE))- bf_resize(res, 0);- }- reduced_mem = (fft_len_log2 >= 14);- if (!reduced_mem) {- buf2 = ntt_malloc(s, sizeof(NTTLimb) * fft_len * nb_mods);- if (!buf2)- goto fail;- limb_to_ntt(s, buf2, fft_len, b_tab, b_len, dpl,- NB_MODS - nb_mods, nb_mods);- if (!(mul_flags & FFT_MUL_R_NORESIZE))- bf_resize(res, 0); /* in case res == b */- } else {- buf2 = ntt_malloc(s, sizeof(NTTLimb) * fft_len);- if (!buf2)- goto fail;- }- for(j = 0; j < nb_mods; j++) {- if (reduced_mem) {- limb_to_ntt(s, buf2, fft_len, b_tab, b_len, dpl,- NB_MODS - nb_mods + j, 1);- ptr = buf2;- } else {- ptr = buf2 + fft_len * j;- }- if (ntt_conv(s, buf1 + fft_len * j, ptr,- fft_len_log2, fft_len_log2, j + NB_MODS - nb_mods))- goto fail;- }- if (!(mul_flags & FFT_MUL_R_NORESIZE))- bf_resize(res, 0); /* in case res == b and reduced mem */- ntt_free(s, buf2);- buf2 = NULL;- if (!(mul_flags & FFT_MUL_R_NORESIZE)) {- if (bf_resize(res, len))- goto fail;- }- ntt_to_limb(s, res->tab, len, buf1, fft_len_log2, dpl, nb_mods);- ntt_free(s, buf1);-#if defined(USE_MUL_CHECK)- hr = mp_mod1(res->tab, len, BF_CHKSUM_MOD, 0);- h_ref = mul_mod(ha, hb, BF_CHKSUM_MOD);- if (hr != h_ref) {- printf("ntt_mul_error: len=%" PRId_LIMB " fft_len_log2=%d dpl=%d nb_mods=%d\n",- len, fft_len_log2, dpl, nb_mods);- // printf("ha=0x" FMT_LIMB" hb=0x" FMT_LIMB " hr=0x" FMT_LIMB " expected=0x" FMT_LIMB "\n", ha, hb, hr, h_ref);- exit(1);- }-#endif - return 0;- fail:- ntt_free(s, buf1);- ntt_free(s, buf2);- return -1;-}--#else /* USE_FFT_MUL */--int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len)-{- return 0;-}--#endif /* !USE_FFT_MUL */
− libbf-2020-01-19/libbf.h
@@ -1,534 +0,0 @@-/*- * Tiny arbitrary precision floating point library- * - * Copyright (c) 2017-2020 Fabrice Bellard- *- * Permission is hereby granted, free of charge, to any person obtaining a copy- * of this software and associated documentation files (the "Software"), to deal- * in the Software without restriction, including without limitation the rights- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell- * copies of the Software, and to permit persons to whom the Software is- * furnished to do so, subject to the following conditions:- *- * The above copyright notice and this permission notice shall be included in- * all copies or substantial portions of the Software.- *- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN- * THE SOFTWARE.- */-#ifndef LIBBF_H-#define LIBBF_H--#include <stddef.h>-#include <stdint.h>--#if defined(__x86_64__)-#define LIMB_LOG2_BITS 6-#else-#define LIMB_LOG2_BITS 5-#endif--#define LIMB_BITS (1 << LIMB_LOG2_BITS)--#if LIMB_BITS == 64-typedef __int128 int128_t;-typedef unsigned __int128 uint128_t;-typedef int64_t slimb_t;-typedef uint64_t limb_t;-typedef uint128_t dlimb_t;-#define BF_RAW_EXP_MIN INT64_MIN-#define BF_RAW_EXP_MAX INT64_MAX--#define LIMB_DIGITS 19-#define BF_DEC_BASE UINT64_C(10000000000000000000)--#else--typedef int32_t slimb_t;-typedef uint32_t limb_t;-typedef uint64_t dlimb_t;-#define BF_RAW_EXP_MIN INT32_MIN-#define BF_RAW_EXP_MAX INT32_MAX--#define LIMB_DIGITS 9-#define BF_DEC_BASE 1000000000U--#endif--/* in bits */-/* minimum number of bits for the exponent */-#define BF_EXP_BITS_MIN 3-/* maximum number of bits for the exponent */-#define BF_EXP_BITS_MAX (LIMB_BITS - 3)-/* extended range for exponent, used internally */-#define BF_EXT_EXP_BITS_MAX (BF_EXP_BITS_MAX + 1)-/* minimum possible precision */-#define BF_PREC_MIN 2-/* minimum possible precision */-#define BF_PREC_MAX (((limb_t)1 << (LIMB_BITS - 2)) - 2)-/* some operations support infinite precision */-#define BF_PREC_INF (BF_PREC_MAX + 1) /* infinite precision */--#if LIMB_BITS == 64-#define BF_CHKSUM_MOD (UINT64_C(975620677) * UINT64_C(9795002197))-#else-#define BF_CHKSUM_MOD 975620677U-#endif--#define BF_EXP_ZERO BF_RAW_EXP_MIN-#define BF_EXP_INF (BF_RAW_EXP_MAX - 1)-#define BF_EXP_NAN BF_RAW_EXP_MAX--/* +/-zero is represented with expn = BF_EXP_ZERO and len = 0,- +/-infinity is represented with expn = BF_EXP_INF and len = 0,- NaN is represented with expn = BF_EXP_NAN and len = 0 (sign is ignored)- */-typedef struct {- struct bf_context_t *ctx;- int sign;- slimb_t expn;- limb_t len;- limb_t *tab;-} bf_t;--typedef struct {- /* must be kept identical to bf_t */- struct bf_context_t *ctx;- int sign;- slimb_t expn;- limb_t len;- limb_t *tab;-} bfdec_t;--typedef enum {- BF_RNDN, /* round to nearest, ties to even */- BF_RNDZ, /* round to zero */- BF_RNDD, /* round to -inf (the code relies on (BF_RNDD xor BF_RNDU) = 1) */- BF_RNDU, /* round to +inf */- BF_RNDNA, /* round to nearest, ties away from zero */- BF_RNDA, /* round away from zero */- BF_RNDF, /* faithful rounding (nondeterministic, either RNDD or RNDU,- inexact flag is always set) */-} bf_rnd_t;--/* allow subnormal numbers. Only available if the number of exponent- bits is <= BF_EXP_BITS_USER_MAX and prec != BF_PREC_INF. */-#define BF_FLAG_SUBNORMAL (1 << 3)-/* 'prec' is the precision after the radix point instead of the whole- mantissa. Can only be used with bf_round() and- bfdec_[add|sub|mul|div|sqrt|round](). */-#define BF_FLAG_RADPNT_PREC (1 << 4)--#define BF_RND_MASK 0x7-#define BF_EXP_BITS_SHIFT 5-#define BF_EXP_BITS_MASK 0x3f--/* shortcut for bf_set_exp_bits(BF_EXT_EXP_BITS_MAX) */-#define BF_FLAG_EXT_EXP (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)--/* contains the rounding mode and number of exponents bits */-typedef uint32_t bf_flags_t;--typedef void *bf_realloc_func_t(void *opaque, void *ptr, size_t size);--typedef struct {- bf_t val;- limb_t prec;-} BFConstCache;--typedef struct bf_context_t {- void *realloc_opaque;- bf_realloc_func_t *realloc_func;- BFConstCache log2_cache;- BFConstCache pi_cache;- struct BFNTTState *ntt_state;-} bf_context_t;--static inline int bf_get_exp_bits(bf_flags_t flags)-{- int e;- e = (flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK;- if (e == BF_EXP_BITS_MASK)- return BF_EXP_BITS_MAX + 1;- else- return BF_EXP_BITS_MAX - e;-}--static inline bf_flags_t bf_set_exp_bits(int n)-{- return ((BF_EXP_BITS_MAX - n) & BF_EXP_BITS_MASK) << BF_EXP_BITS_SHIFT;-}--/* returned status */-#define BF_ST_INVALID_OP (1 << 0)-#define BF_ST_DIVIDE_ZERO (1 << 1)-#define BF_ST_OVERFLOW (1 << 2)-#define BF_ST_UNDERFLOW (1 << 3)-#define BF_ST_INEXACT (1 << 4)-/* indicate that a memory allocation error occured. NaN is returned */-#define BF_ST_MEM_ERROR (1 << 5) --#define BF_RADIX_MAX 36 /* maximum radix for bf_atof() and bf_ftoa() */--static inline slimb_t bf_max(slimb_t a, slimb_t b)-{- if (a > b)- return a;- else- return b;-}--static inline slimb_t bf_min(slimb_t a, slimb_t b)-{- if (a < b)- return a;- else- return b;-}--void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func,- void *realloc_opaque);-void bf_context_end(bf_context_t *s);-/* free memory allocated for the bf cache data */-void bf_clear_cache(bf_context_t *s);--static inline void *bf_realloc(bf_context_t *s, void *ptr, size_t size)-{- return s->realloc_func(s->realloc_opaque, ptr, size);-}--/* 'size' must be != 0 */-static inline void *bf_malloc(bf_context_t *s, size_t size)-{- return bf_realloc(s, NULL, size);-}--static inline void bf_free(bf_context_t *s, void *ptr)-{- /* must test ptr otherwise equivalent to malloc(0) */- if (ptr)- bf_realloc(s, ptr, 0);-}--void bf_init(bf_context_t *s, bf_t *r);--static inline void bf_delete(bf_t *r)-{- bf_context_t *s = r->ctx;- /* we accept to delete a zeroed bf_t structure */- if (s && r->tab) {- bf_realloc(s, r->tab, 0);- }-}--static inline void bf_neg(bf_t *r)-{- r->sign ^= 1;-}--static inline int bf_is_finite(const bf_t *a)-{- return (a->expn < BF_EXP_INF);-}--static inline int bf_is_nan(const bf_t *a)-{- return (a->expn == BF_EXP_NAN);-}--static inline int bf_is_zero(const bf_t *a)-{- return (a->expn == BF_EXP_ZERO);-}--static inline void bf_memcpy(bf_t *r, const bf_t *a)-{- *r = *a;-}--int bf_set_ui(bf_t *r, uint64_t a);-int bf_set_si(bf_t *r, int64_t a);-void bf_set_nan(bf_t *r);-void bf_set_zero(bf_t *r, int is_neg);-void bf_set_inf(bf_t *r, int is_neg);-int bf_set(bf_t *r, const bf_t *a);-void bf_move(bf_t *r, bf_t *a);-int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode);-int bf_set_float64(bf_t *a, double d);--int bf_cmpu(const bf_t *a, const bf_t *b);-int bf_cmp_full(const bf_t *a, const bf_t *b);-int bf_cmp(const bf_t *a, const bf_t *b);-static inline int bf_cmp_eq(const bf_t *a, const bf_t *b)-{- return bf_cmp(a, b) == 0;-}--static inline int bf_cmp_le(const bf_t *a, const bf_t *b)-{- return bf_cmp(a, b) <= 0;-}--static inline int bf_cmp_lt(const bf_t *a, const bf_t *b)-{- return bf_cmp(a, b) < 0;-}--int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);-int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);-int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags);-int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);-int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec, bf_flags_t flags);-int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, - bf_flags_t flags);-int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags);-int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);-#define BF_DIVREM_EUCLIDIAN BF_RNDF-int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,- limb_t prec, bf_flags_t flags, int rnd_mode);-int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,- bf_flags_t flags, int rnd_mode);-int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,- bf_flags_t flags, int rnd_mode);-/* round to integer with infinite precision */-int bf_rint(bf_t *r, int rnd_mode);-int bf_round(bf_t *r, limb_t prec, bf_flags_t flags);-int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a);-int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);-slimb_t bf_get_exp_min(const bf_t *a);-int bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b);-int bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b);-int bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b);--/* additional flags for bf_atof */-/* do not accept hex radix prefix (0x or 0X) if radix = 0 or radix = 16 */-#define BF_ATOF_NO_HEX (1 << 16)-/* accept binary (0b or 0B) or octal (0o or 0O) radix prefix if radix = 0 */-#define BF_ATOF_BIN_OCT (1 << 17)-/* Do not parse NaN or Inf */-#define BF_ATOF_NO_NAN_INF (1 << 18)-/* return the exponent separately */-#define BF_ATOF_EXPONENT (1 << 19)--int bf_atof(bf_t *a, const char *str, const char **pnext, int radix,- limb_t prec, bf_flags_t flags);-/* this version accepts prec = BF_PREC_INF and returns the radix- exponent */-int bf_atof2(bf_t *r, slimb_t *pexponent,- const char *str, const char **pnext, int radix,- limb_t prec, bf_flags_t flags);-int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,- slimb_t expn, limb_t prec, bf_flags_t flags);---/* Conversion of floating point number to string. Return a null- terminated string or NULL if memory error. *plen contains its- length if plen != NULL. The exponent letter is "e" for base 10,- "p" for bases 2, 8, 16 with a binary exponent and "@" for the other- bases. */--#define BF_FTOA_FORMAT_MASK (3 << 16)--/* fixed format: prec significant digits rounded with (flags &- BF_RND_MASK). Exponential notation is used if too many zeros are- needed.*/-#define BF_FTOA_FORMAT_FIXED (0 << 16)-/* fractional format: prec digits after the decimal point rounded with- (flags & BF_RND_MASK) */-#define BF_FTOA_FORMAT_FRAC (1 << 16)-/* free format: - - For binary radices with bf_ftoa() and for bfdec_ftoa(): use the minimum- number of digits to represent 'a'. The precision and the rounding- mode are ignored.- - For the non binary radices with bf_ftoa(): use as many digits as- necessary so that bf_atof() return the same number when using- precision 'prec', rounding to nearest and the subnormal- configuration of 'flags'. The result is meaningful only if 'a' is- already rounded to 'prec' bits. If the subnormal flag is set, the- exponent in 'flags' must also be set to the desired exponent range.-*/-#define BF_FTOA_FORMAT_FREE (2 << 16)-/* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits- (takes more computation time). Identical to BF_FTOA_FORMAT_FREE for- binary radices with bf_ftoa() and for bfdec_ftoa(). */-#define BF_FTOA_FORMAT_FREE_MIN (3 << 16)--/* force exponential notation for fixed or free format */-#define BF_FTOA_FORCE_EXP (1 << 20)-/* add 0x prefix for base 16, 0o prefix for base 8 or 0b prefix for- base 2 if non zero value */-#define BF_FTOA_ADD_PREFIX (1 << 21)-/* return "Infinity" instead of "Inf" and add a "+" for positive- exponents */-#define BF_FTOA_JS_QUIRKS (1 << 22)--char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec,- bf_flags_t flags);--/* modulo 2^n instead of saturation. NaN and infinity return 0 */-#define BF_GET_INT_MOD (1 << 0) -int bf_get_int32(int *pres, const bf_t *a, int flags);-int bf_get_int64(int64_t *pres, const bf_t *a, int flags);--/* the following functions are exported for testing only. */-void mp_print_str(const char *str, const limb_t *tab, limb_t n);-void bf_print_str(const char *str, const bf_t *a);-int bf_resize(bf_t *r, limb_t len);-int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len);-int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags);-int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k);-slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv,- int is_ceil1);-int mp_mul(bf_context_t *s, limb_t *result, - const limb_t *op1, limb_t op1_size, - const limb_t *op2, limb_t op2_size);-limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2, - limb_t n, limb_t carry);-limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n);-int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n);-int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n);-limb_t bf_isqrt(limb_t a);--/* transcendental functions */-int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags);-int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags);-int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);-int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);-#define BF_POW_JS_QUIRKS (1 << 16) /* (+/-1)^(+/-Inf) = NaN, 1^NaN = NaN */-int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags);-int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);-int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);-int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);-int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);-int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x,- limb_t prec, bf_flags_t flags);-int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);-int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);--/* decimal floating point */--static inline void bfdec_init(bf_context_t *s, bfdec_t *r)-{- bf_init(s, (bf_t *)r);-}-static inline void bfdec_delete(bfdec_t *r)-{- bf_delete((bf_t *)r);-}--static inline void bfdec_neg(bfdec_t *r)-{- r->sign ^= 1;-}--static inline int bfdec_is_finite(const bfdec_t *a)-{- return (a->expn < BF_EXP_INF);-}--static inline int bfdec_is_nan(const bfdec_t *a)-{- return (a->expn == BF_EXP_NAN);-}--static inline int bfdec_is_zero(const bfdec_t *a)-{- return (a->expn == BF_EXP_ZERO);-}--static inline void bfdec_memcpy(bfdec_t *r, const bfdec_t *a)-{- bf_memcpy((bf_t *)r, (const bf_t *)a);-}--int bfdec_set_ui(bfdec_t *r, uint64_t a);-int bfdec_set_si(bfdec_t *r, int64_t a);--static inline void bfdec_set_nan(bfdec_t *r)-{- bf_set_nan((bf_t *)r);-}-static inline void bfdec_set_zero(bfdec_t *r, int is_neg)-{- bf_set_zero((bf_t *)r, is_neg);-}-static inline void bfdec_set_inf(bfdec_t *r, int is_neg)-{- bf_set_inf((bf_t *)r, is_neg);-}-static inline int bfdec_set(bfdec_t *r, const bfdec_t *a)-{- return bf_set((bf_t *)r, (bf_t *)a);-}-static inline void bfdec_move(bfdec_t *r, bfdec_t *a)-{- bf_move((bf_t *)r, (bf_t *)a);-}-static inline int bfdec_cmpu(const bfdec_t *a, const bfdec_t *b)-{- return bf_cmpu((const bf_t *)a, (const bf_t *)b);-}-static inline int bfdec_cmp_full(const bfdec_t *a, const bfdec_t *b)-{- return bf_cmp_full((const bf_t *)a, (const bf_t *)b);-}-static inline int bfdec_cmp(const bfdec_t *a, const bfdec_t *b)-{- return bf_cmp((const bf_t *)a, (const bf_t *)b);-}-static inline int bfdec_cmp_eq(const bfdec_t *a, const bfdec_t *b)-{- return bfdec_cmp(a, b) == 0;-}-static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b)-{- return bfdec_cmp(a, b) <= 0;-}-static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b)-{- return bfdec_cmp(a, b) < 0;-}--int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,- bf_flags_t flags);-int bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,- bf_flags_t flags);-int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,- bf_flags_t flags);-int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,- bf_flags_t flags);-int bfdec_mul_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,- bf_flags_t flags);-int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,- bf_flags_t flags);-int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,- limb_t prec, bf_flags_t flags, int rnd_mode);-int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,- bf_flags_t flags, int rnd_mode);-int bfdec_rint(bfdec_t *r, int rnd_mode);-int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags);-int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags);-int bfdec_get_int32(int *pres, const bfdec_t *a);-int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b);--char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags);-int bfdec_atof(bfdec_t *r, const char *str, const char **pnext,- limb_t prec, bf_flags_t flags);--/* the following functions are exported for testing only. */-extern const limb_t mp_pow_dec[LIMB_DIGITS + 1];-void bfdec_print_str(const char *str, const bfdec_t *a);-static inline int bfdec_resize(bfdec_t *r, limb_t len)-{- return bf_resize((bf_t *)r, len);-}-int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags);--#endif /* LIBBF_H */
+ libbf-quickjs-2021-03-27/cutils.c view
@@ -0,0 +1,631 @@+/*+ * C utilities+ * + * Copyright (c) 2017 Fabrice Bellard+ * Copyright (c) 2018 Charlie Gordon+ *+ * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ *+ * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+ * THE SOFTWARE.+ */+#include <stdlib.h>+#include <stdio.h>+#include <stdarg.h>+#include <string.h>++#include "cutils.h"++void pstrcpy(char *buf, int buf_size, const char *str)+{+ int c;+ char *q = buf;++ if (buf_size <= 0)+ return;++ for(;;) {+ c = *str++;+ if (c == 0 || q >= buf + buf_size - 1)+ break;+ *q++ = c;+ }+ *q = '\0';+}++/* strcat and truncate. */+char *pstrcat(char *buf, int buf_size, const char *s)+{+ int len;+ len = strlen(buf);+ if (len < buf_size)+ pstrcpy(buf + len, buf_size - len, s);+ return buf;+}++int strstart(const char *str, const char *val, const char **ptr)+{+ const char *p, *q;+ p = str;+ q = val;+ while (*q != '\0') {+ if (*p != *q)+ return 0;+ p++;+ q++;+ }+ if (ptr)+ *ptr = p;+ return 1;+}++int has_suffix(const char *str, const char *suffix)+{+ size_t len = strlen(str);+ size_t slen = strlen(suffix);+ return (len >= slen && !memcmp(str + len - slen, suffix, slen));+}++/* Dynamic buffer package */++static void *dbuf_default_realloc(void *opaque, void *ptr, size_t size)+{+ return realloc(ptr, size);+}++void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func)+{+ memset(s, 0, sizeof(*s));+ if (!realloc_func)+ realloc_func = dbuf_default_realloc;+ s->opaque = opaque;+ s->realloc_func = realloc_func;+}++void dbuf_init(DynBuf *s)+{+ dbuf_init2(s, NULL, NULL);+}++/* return < 0 if error */+int dbuf_realloc(DynBuf *s, size_t new_size)+{+ size_t size;+ uint8_t *new_buf;+ if (new_size > s->allocated_size) {+ if (s->error)+ return -1;+ size = s->allocated_size * 3 / 2;+ if (size > new_size)+ new_size = size;+ new_buf = s->realloc_func(s->opaque, s->buf, new_size);+ if (!new_buf) {+ s->error = TRUE;+ return -1;+ }+ s->buf = new_buf;+ s->allocated_size = new_size;+ }+ return 0;+}++int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len)+{+ size_t end;+ end = offset + len;+ if (dbuf_realloc(s, end))+ return -1;+ memcpy(s->buf + offset, data, len);+ if (end > s->size)+ s->size = end;+ return 0;+}++int dbuf_put(DynBuf *s, const uint8_t *data, size_t len)+{+ if (unlikely((s->size + len) > s->allocated_size)) {+ if (dbuf_realloc(s, s->size + len))+ return -1;+ }+ memcpy(s->buf + s->size, data, len);+ s->size += len;+ return 0;+}++int dbuf_put_self(DynBuf *s, size_t offset, size_t len)+{+ if (unlikely((s->size + len) > s->allocated_size)) {+ if (dbuf_realloc(s, s->size + len))+ return -1;+ }+ memcpy(s->buf + s->size, s->buf + offset, len);+ s->size += len;+ return 0;+}++int dbuf_putc(DynBuf *s, uint8_t c)+{+ return dbuf_put(s, &c, 1);+}++int dbuf_putstr(DynBuf *s, const char *str)+{+ return dbuf_put(s, (const uint8_t *)str, strlen(str));+}++int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,+ const char *fmt, ...)+{+ va_list ap;+ char buf[128];+ int len;+ + va_start(ap, fmt);+ len = vsnprintf(buf, sizeof(buf), fmt, ap);+ va_end(ap);+ if (len < sizeof(buf)) {+ /* fast case */+ return dbuf_put(s, (uint8_t *)buf, len);+ } else {+ if (dbuf_realloc(s, s->size + len + 1))+ return -1;+ va_start(ap, fmt);+ vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size,+ fmt, ap);+ va_end(ap);+ s->size += len;+ }+ return 0;+}++void dbuf_free(DynBuf *s)+{+ /* we test s->buf as a fail safe to avoid crashing if dbuf_free()+ is called twice */+ if (s->buf) {+ s->realloc_func(s->opaque, s->buf, 0);+ }+ memset(s, 0, sizeof(*s));+}++/* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes+ are output. */+int unicode_to_utf8(uint8_t *buf, unsigned int c)+{+ uint8_t *q = buf;++ if (c < 0x80) {+ *q++ = c;+ } else {+ if (c < 0x800) {+ *q++ = (c >> 6) | 0xc0;+ } else {+ if (c < 0x10000) {+ *q++ = (c >> 12) | 0xe0;+ } else {+ if (c < 0x00200000) {+ *q++ = (c >> 18) | 0xf0;+ } else {+ if (c < 0x04000000) {+ *q++ = (c >> 24) | 0xf8;+ } else if (c < 0x80000000) {+ *q++ = (c >> 30) | 0xfc;+ *q++ = ((c >> 24) & 0x3f) | 0x80;+ } else {+ return 0;+ }+ *q++ = ((c >> 18) & 0x3f) | 0x80;+ }+ *q++ = ((c >> 12) & 0x3f) | 0x80;+ }+ *q++ = ((c >> 6) & 0x3f) | 0x80;+ }+ *q++ = (c & 0x3f) | 0x80;+ }+ return q - buf;+}++static const unsigned int utf8_min_code[5] = {+ 0x80, 0x800, 0x10000, 0x00200000, 0x04000000,+};++static const unsigned char utf8_first_code_mask[5] = {+ 0x1f, 0xf, 0x7, 0x3, 0x1,+};++/* return -1 if error. *pp is not updated in this case. max_len must+ be >= 1. The maximum length for a UTF8 byte sequence is 6 bytes. */+int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp)+{+ int l, c, b, i;++ c = *p++;+ if (c < 0x80) {+ *pp = p;+ return c;+ }+ switch(c) {+ case 0xc0: case 0xc1: case 0xc2: case 0xc3:+ case 0xc4: case 0xc5: case 0xc6: case 0xc7:+ case 0xc8: case 0xc9: case 0xca: case 0xcb:+ case 0xcc: case 0xcd: case 0xce: case 0xcf:+ case 0xd0: case 0xd1: case 0xd2: case 0xd3:+ case 0xd4: case 0xd5: case 0xd6: case 0xd7:+ case 0xd8: case 0xd9: case 0xda: case 0xdb:+ case 0xdc: case 0xdd: case 0xde: case 0xdf:+ l = 1;+ break;+ case 0xe0: case 0xe1: case 0xe2: case 0xe3:+ case 0xe4: case 0xe5: case 0xe6: case 0xe7:+ case 0xe8: case 0xe9: case 0xea: case 0xeb:+ case 0xec: case 0xed: case 0xee: case 0xef:+ l = 2;+ break;+ case 0xf0: case 0xf1: case 0xf2: case 0xf3:+ case 0xf4: case 0xf5: case 0xf6: case 0xf7:+ l = 3;+ break;+ case 0xf8: case 0xf9: case 0xfa: case 0xfb:+ l = 4;+ break;+ case 0xfc: case 0xfd:+ l = 5;+ break;+ default:+ return -1;+ }+ /* check that we have enough characters */+ if (l > (max_len - 1))+ return -1;+ c &= utf8_first_code_mask[l - 1];+ for(i = 0; i < l; i++) {+ b = *p++;+ if (b < 0x80 || b >= 0xc0)+ return -1;+ c = (c << 6) | (b & 0x3f);+ }+ if (c < utf8_min_code[l - 1])+ return -1;+ *pp = p;+ return c;+}++#if 0++#if defined(EMSCRIPTEN) || defined(__ANDROID__)++static void *rqsort_arg;+static int (*rqsort_cmp)(const void *, const void *, void *);++static int rqsort_cmp2(const void *p1, const void *p2)+{+ return rqsort_cmp(p1, p2, rqsort_arg);+}++/* not reentrant, but not needed with emscripten */+void rqsort(void *base, size_t nmemb, size_t size,+ int (*cmp)(const void *, const void *, void *),+ void *arg)+{+ rqsort_arg = arg;+ rqsort_cmp = cmp;+ qsort(base, nmemb, size, rqsort_cmp2);+}++#endif++#else++typedef void (*exchange_f)(void *a, void *b, size_t size);+typedef int (*cmp_f)(const void *, const void *, void *opaque);++static void exchange_bytes(void *a, void *b, size_t size) {+ uint8_t *ap = (uint8_t *)a;+ uint8_t *bp = (uint8_t *)b;++ while (size-- != 0) {+ uint8_t t = *ap;+ *ap++ = *bp;+ *bp++ = t;+ }+}++static void exchange_one_byte(void *a, void *b, size_t size) {+ uint8_t *ap = (uint8_t *)a;+ uint8_t *bp = (uint8_t *)b;+ uint8_t t = *ap;+ *ap = *bp;+ *bp = t;+}++static void exchange_int16s(void *a, void *b, size_t size) {+ uint16_t *ap = (uint16_t *)a;+ uint16_t *bp = (uint16_t *)b;++ for (size /= sizeof(uint16_t); size-- != 0;) {+ uint16_t t = *ap;+ *ap++ = *bp;+ *bp++ = t;+ }+}++static void exchange_one_int16(void *a, void *b, size_t size) {+ uint16_t *ap = (uint16_t *)a;+ uint16_t *bp = (uint16_t *)b;+ uint16_t t = *ap;+ *ap = *bp;+ *bp = t;+}++static void exchange_int32s(void *a, void *b, size_t size) {+ uint32_t *ap = (uint32_t *)a;+ uint32_t *bp = (uint32_t *)b;++ for (size /= sizeof(uint32_t); size-- != 0;) {+ uint32_t t = *ap;+ *ap++ = *bp;+ *bp++ = t;+ }+}++static void exchange_one_int32(void *a, void *b, size_t size) {+ uint32_t *ap = (uint32_t *)a;+ uint32_t *bp = (uint32_t *)b;+ uint32_t t = *ap;+ *ap = *bp;+ *bp = t;+}++static void exchange_int64s(void *a, void *b, size_t size) {+ uint64_t *ap = (uint64_t *)a;+ uint64_t *bp = (uint64_t *)b;++ for (size /= sizeof(uint64_t); size-- != 0;) {+ uint64_t t = *ap;+ *ap++ = *bp;+ *bp++ = t;+ }+}++static void exchange_one_int64(void *a, void *b, size_t size) {+ uint64_t *ap = (uint64_t *)a;+ uint64_t *bp = (uint64_t *)b;+ uint64_t t = *ap;+ *ap = *bp;+ *bp = t;+}++static void exchange_int128s(void *a, void *b, size_t size) {+ uint64_t *ap = (uint64_t *)a;+ uint64_t *bp = (uint64_t *)b;++ for (size /= sizeof(uint64_t) * 2; size-- != 0; ap += 2, bp += 2) {+ uint64_t t = ap[0];+ uint64_t u = ap[1];+ ap[0] = bp[0];+ ap[1] = bp[1];+ bp[0] = t;+ bp[1] = u;+ }+}++static void exchange_one_int128(void *a, void *b, size_t size) {+ uint64_t *ap = (uint64_t *)a;+ uint64_t *bp = (uint64_t *)b;+ uint64_t t = ap[0];+ uint64_t u = ap[1];+ ap[0] = bp[0];+ ap[1] = bp[1];+ bp[0] = t;+ bp[1] = u;+}++static inline exchange_f exchange_func(const void *base, size_t size) {+ switch (((uintptr_t)base | (uintptr_t)size) & 15) {+ case 0:+ if (size == sizeof(uint64_t) * 2)+ return exchange_one_int128;+ else+ return exchange_int128s;+ case 8:+ if (size == sizeof(uint64_t))+ return exchange_one_int64;+ else+ return exchange_int64s;+ case 4:+ case 12:+ if (size == sizeof(uint32_t))+ return exchange_one_int32;+ else+ return exchange_int32s;+ case 2:+ case 6:+ case 10:+ case 14:+ if (size == sizeof(uint16_t))+ return exchange_one_int16;+ else+ return exchange_int16s;+ default:+ if (size == 1)+ return exchange_one_byte;+ else+ return exchange_bytes;+ }+}++static void heapsortx(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)+{+ uint8_t *basep = (uint8_t *)base;+ size_t i, n, c, r;+ exchange_f swap = exchange_func(base, size);++ if (nmemb > 1) {+ i = (nmemb / 2) * size;+ n = nmemb * size;++ while (i > 0) {+ i -= size;+ for (r = i; (c = r * 2 + size) < n; r = c) {+ if (c < n - size && cmp(basep + c, basep + c + size, opaque) <= 0)+ c += size;+ if (cmp(basep + r, basep + c, opaque) > 0)+ break;+ swap(basep + r, basep + c, size);+ }+ }+ for (i = n - size; i > 0; i -= size) {+ swap(basep, basep + i, size);++ for (r = 0; (c = r * 2 + size) < i; r = c) {+ if (c < i - size && cmp(basep + c, basep + c + size, opaque) <= 0)+ c += size;+ if (cmp(basep + r, basep + c, opaque) > 0)+ break;+ swap(basep + r, basep + c, size);+ }+ }+ }+}++static inline void *med3(void *a, void *b, void *c, cmp_f cmp, void *opaque)+{+ return cmp(a, b, opaque) < 0 ?+ (cmp(b, c, opaque) < 0 ? b : (cmp(a, c, opaque) < 0 ? c : a )) :+ (cmp(b, c, opaque) > 0 ? b : (cmp(a, c, opaque) < 0 ? a : c ));+}++/* pointer based version with local stack and insertion sort threshhold */+void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)+{+ struct { uint8_t *base; size_t count; int depth; } stack[50], *sp = stack;+ uint8_t *ptr, *pi, *pj, *plt, *pgt, *top, *m;+ size_t m4, i, lt, gt, span, span2;+ int c, depth;+ exchange_f swap = exchange_func(base, size);+ exchange_f swap_block = exchange_func(base, size | 128);++ if (nmemb < 2 || size <= 0)+ return;++ sp->base = (uint8_t *)base;+ sp->count = nmemb;+ sp->depth = 0;+ sp++;++ while (sp > stack) {+ sp--;+ ptr = sp->base;+ nmemb = sp->count;+ depth = sp->depth;++ while (nmemb > 6) {+ if (++depth > 50) {+ /* depth check to ensure worst case logarithmic time */+ heapsortx(ptr, nmemb, size, cmp, opaque);+ nmemb = 0;+ break;+ }+ /* select median of 3 from 1/4, 1/2, 3/4 positions */+ /* should use median of 5 or 9? */+ m4 = (nmemb >> 2) * size;+ m = med3(ptr + m4, ptr + 2 * m4, ptr + 3 * m4, cmp, opaque);+ swap(ptr, m, size); /* move the pivot to the start or the array */+ i = lt = 1;+ pi = plt = ptr + size;+ gt = nmemb;+ pj = pgt = top = ptr + nmemb * size;+ for (;;) {+ while (pi < pj && (c = cmp(ptr, pi, opaque)) >= 0) {+ if (c == 0) {+ swap(plt, pi, size);+ lt++;+ plt += size;+ }+ i++;+ pi += size;+ }+ while (pi < (pj -= size) && (c = cmp(ptr, pj, opaque)) <= 0) {+ if (c == 0) {+ gt--;+ pgt -= size;+ swap(pgt, pj, size);+ }+ }+ if (pi >= pj)+ break;+ swap(pi, pj, size);+ i++;+ pi += size;+ }+ /* array has 4 parts:+ * from 0 to lt excluded: elements identical to pivot+ * from lt to pi excluded: elements smaller than pivot+ * from pi to gt excluded: elements greater than pivot+ * from gt to n excluded: elements identical to pivot+ */+ /* move elements identical to pivot in the middle of the array: */+ /* swap values in ranges [0..lt[ and [i-lt..i[+ swapping the smallest span between lt and i-lt is sufficient+ */+ span = plt - ptr;+ span2 = pi - plt;+ lt = i - lt;+ if (span > span2)+ span = span2;+ swap_block(ptr, pi - span, span);+ /* swap values in ranges [gt..top[ and [i..top-(top-gt)[+ swapping the smallest span between top-gt and gt-i is sufficient+ */+ span = top - pgt;+ span2 = pgt - pi;+ pgt = top - span2;+ gt = nmemb - (gt - i);+ if (span > span2)+ span = span2;+ swap_block(pi, top - span, span);++ /* now array has 3 parts:+ * from 0 to lt excluded: elements smaller than pivot+ * from lt to gt excluded: elements identical to pivot+ * from gt to n excluded: elements greater than pivot+ */+ /* stack the larger segment and keep processing the smaller one+ to minimize stack use for pathological distributions */+ if (lt > nmemb - gt) {+ sp->base = ptr;+ sp->count = lt;+ sp->depth = depth;+ sp++;+ ptr = pgt;+ nmemb -= gt;+ } else {+ sp->base = pgt;+ sp->count = nmemb - gt;+ sp->depth = depth;+ sp++;+ nmemb = lt;+ }+ }+ /* Use insertion sort for small fragments */+ for (pi = ptr + size, top = ptr + nmemb * size; pi < top; pi += size) {+ for (pj = pi; pj > ptr && cmp(pj - size, pj, opaque) > 0; pj -= size)+ swap(pj, pj - size, size);+ }+ }+}++#endif
+ libbf-quickjs-2021-03-27/cutils.h view
@@ -0,0 +1,297 @@+/*+ * C utilities+ * + * Copyright (c) 2017 Fabrice Bellard+ * Copyright (c) 2018 Charlie Gordon+ *+ * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ *+ * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+ * THE SOFTWARE.+ */+#ifndef CUTILS_H+#define CUTILS_H++#include <stdlib.h>+#include <inttypes.h>++/* set if CPU is big endian */+#undef WORDS_BIGENDIAN++#define likely(x) __builtin_expect(!!(x), 1)+#define unlikely(x) __builtin_expect(!!(x), 0)+#define force_inline inline __attribute__((always_inline))+#define no_inline __attribute__((noinline))+#define __maybe_unused __attribute__((unused))++#define xglue(x, y) x ## y+#define glue(x, y) xglue(x, y)+#define stringify(s) tostring(s)+#define tostring(s) #s++#ifndef offsetof+#define offsetof(type, field) ((size_t) &((type *)0)->field)+#endif+#ifndef countof+#define countof(x) (sizeof(x) / sizeof((x)[0]))+#endif++typedef int BOOL;++#ifndef FALSE+enum {+ FALSE = 0,+ TRUE = 1,+};+#endif++void pstrcpy(char *buf, int buf_size, const char *str);+char *pstrcat(char *buf, int buf_size, const char *s);+int strstart(const char *str, const char *val, const char **ptr);+int has_suffix(const char *str, const char *suffix);++static inline int max_int(int a, int b)+{+ if (a > b)+ return a;+ else+ return b;+}++static inline int min_int(int a, int b)+{+ if (a < b)+ return a;+ else+ return b;+}++static inline uint32_t max_uint32(uint32_t a, uint32_t b)+{+ if (a > b)+ return a;+ else+ return b;+}++static inline uint32_t min_uint32(uint32_t a, uint32_t b)+{+ if (a < b)+ return a;+ else+ return b;+}++static inline int64_t max_int64(int64_t a, int64_t b)+{+ if (a > b)+ return a;+ else+ return b;+}++static inline int64_t min_int64(int64_t a, int64_t b)+{+ if (a < b)+ return a;+ else+ return b;+}++/* WARNING: undefined if a = 0 */+static inline int clz32(unsigned int a)+{+ return __builtin_clz(a);+}++/* WARNING: undefined if a = 0 */+static inline int clz64(uint64_t a)+{+ return __builtin_clzll(a);+}++/* WARNING: undefined if a = 0 */+static inline int ctz32(unsigned int a)+{+ return __builtin_ctz(a);+}++/* WARNING: undefined if a = 0 */+static inline int ctz64(uint64_t a)+{+ return __builtin_ctzll(a);+}++struct __attribute__((packed)) packed_u64 {+ uint64_t v;+};++struct __attribute__((packed)) packed_u32 {+ uint32_t v;+};++struct __attribute__((packed)) packed_u16 {+ uint16_t v;+};++static inline uint64_t get_u64(const uint8_t *tab)+{+ return ((const struct packed_u64 *)tab)->v;+}++static inline int64_t get_i64(const uint8_t *tab)+{+ return (int64_t)((const struct packed_u64 *)tab)->v;+}++static inline void put_u64(uint8_t *tab, uint64_t val)+{+ ((struct packed_u64 *)tab)->v = val;+}++static inline uint32_t get_u32(const uint8_t *tab)+{+ return ((const struct packed_u32 *)tab)->v;+}++static inline int32_t get_i32(const uint8_t *tab)+{+ return (int32_t)((const struct packed_u32 *)tab)->v;+}++static inline void put_u32(uint8_t *tab, uint32_t val)+{+ ((struct packed_u32 *)tab)->v = val;+}++static inline uint32_t get_u16(const uint8_t *tab)+{+ return ((const struct packed_u16 *)tab)->v;+}++static inline int32_t get_i16(const uint8_t *tab)+{+ return (int16_t)((const struct packed_u16 *)tab)->v;+}++static inline void put_u16(uint8_t *tab, uint16_t val)+{+ ((struct packed_u16 *)tab)->v = val;+}++static inline uint32_t get_u8(const uint8_t *tab)+{+ return *tab;+}++static inline int32_t get_i8(const uint8_t *tab)+{+ return (int8_t)*tab;+}++static inline void put_u8(uint8_t *tab, uint8_t val)+{+ *tab = val;+}++static inline uint16_t bswap16(uint16_t x)+{+ return (x >> 8) | (x << 8);+}++static inline uint32_t bswap32(uint32_t v)+{+ return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) |+ ((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24);+}++static inline uint64_t bswap64(uint64_t v)+{+ return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) | + ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) | + ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) | + ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) | + ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) | + ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) | + ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) | + ((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8));+}++/* XXX: should take an extra argument to pass slack information to the caller */+typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size);++typedef struct DynBuf {+ uint8_t *buf;+ size_t size;+ size_t allocated_size;+ BOOL error; /* true if a memory allocation error occurred */+ DynBufReallocFunc *realloc_func;+ void *opaque; /* for realloc_func */+} DynBuf;++void dbuf_init(DynBuf *s);+void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func);+int dbuf_realloc(DynBuf *s, size_t new_size);+int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len);+int dbuf_put(DynBuf *s, const uint8_t *data, size_t len);+int dbuf_put_self(DynBuf *s, size_t offset, size_t len);+int dbuf_putc(DynBuf *s, uint8_t c);+int dbuf_putstr(DynBuf *s, const char *str);+static inline int dbuf_put_u16(DynBuf *s, uint16_t val)+{+ return dbuf_put(s, (uint8_t *)&val, 2);+}+static inline int dbuf_put_u32(DynBuf *s, uint32_t val)+{+ return dbuf_put(s, (uint8_t *)&val, 4);+}+static inline int dbuf_put_u64(DynBuf *s, uint64_t val)+{+ return dbuf_put(s, (uint8_t *)&val, 8);+}+int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,+ const char *fmt, ...);+void dbuf_free(DynBuf *s);+static inline BOOL dbuf_error(DynBuf *s) {+ return s->error;+}+static inline void dbuf_set_error(DynBuf *s)+{+ s->error = TRUE;+}++#define UTF8_CHAR_LEN_MAX 6++int unicode_to_utf8(uint8_t *buf, unsigned int c);+int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp);++static inline int from_hex(int c)+{+ if (c >= '0' && c <= '9')+ return c - '0';+ else if (c >= 'A' && c <= 'F')+ return c - 'A' + 10;+ else if (c >= 'a' && c <= 'f')+ return c - 'a' + 10;+ else+ return -1;+}++void rqsort(void *base, size_t nmemb, size_t size,+ int (*cmp)(const void *, const void *, void *),+ void *arg);++#endif /* CUTILS_H */
+ libbf-quickjs-2021-03-27/libbf.c view
@@ -0,0 +1,8466 @@+/*+ * Tiny arbitrary precision floating point library+ * + * Copyright (c) 2017-2021 Fabrice Bellard+ *+ * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ *+ * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+ * THE SOFTWARE.+ */+#include <stdlib.h>+#include <stdio.h>+#include <inttypes.h>+#include <math.h>+#include <string.h>+#include <assert.h>++#ifdef __AVX2__+#include <immintrin.h>+#endif++#include "cutils.h"+#include "libbf.h"++/* enable it to check the multiplication result */+//#define USE_MUL_CHECK+/* enable it to use FFT/NTT multiplication */+#define USE_FFT_MUL+/* enable decimal floating point support */+#define USE_BF_DEC++//#define inline __attribute__((always_inline))++#ifdef __AVX2__+#define FFT_MUL_THRESHOLD 100 /* in limbs of the smallest factor */+#else+#define FFT_MUL_THRESHOLD 100 /* in limbs of the smallest factor */+#endif++/* XXX: adjust */+#define DIVNORM_LARGE_THRESHOLD 50+#define UDIV1NORM_THRESHOLD 3++#if LIMB_BITS == 64+#define FMT_LIMB1 "%" PRIx64 +#define FMT_LIMB "%016" PRIx64 +#define PRId_LIMB PRId64+#define PRIu_LIMB PRIu64++#else++#define FMT_LIMB1 "%x"+#define FMT_LIMB "%08x"+#define PRId_LIMB "d"+#define PRIu_LIMB "u"++#endif++typedef intptr_t mp_size_t;++typedef int bf_op2_func_t(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,+ bf_flags_t flags);++#ifdef USE_FFT_MUL++#define FFT_MUL_R_OVERLAP_A (1 << 0)+#define FFT_MUL_R_OVERLAP_B (1 << 1)+#define FFT_MUL_R_NORESIZE (1 << 2)++static no_inline int fft_mul(bf_context_t *s,+ bf_t *res, limb_t *a_tab, limb_t a_len,+ limb_t *b_tab, limb_t b_len, int mul_flags);+static void fft_clear_cache(bf_context_t *s);+#endif+#ifdef USE_BF_DEC+static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos);+#endif+++/* could leading zeros */+static inline int clz(limb_t a)+{+ if (a == 0) {+ return LIMB_BITS;+ } else {+#if LIMB_BITS == 64+ return clz64(a);+#else+ return clz32(a);+#endif+ }+}++static inline int ctz(limb_t a)+{+ if (a == 0) {+ return LIMB_BITS;+ } else {+#if LIMB_BITS == 64+ return ctz64(a);+#else+ return ctz32(a);+#endif+ }+}++static inline int ceil_log2(limb_t a)+{+ if (a <= 1)+ return 0;+ else+ return LIMB_BITS - clz(a - 1);+}++/* b must be >= 1 */+static inline slimb_t ceil_div(slimb_t a, slimb_t b)+{+ if (a >= 0)+ return (a + b - 1) / b;+ else+ return a / b;+}++/* b must be >= 1 */+static inline slimb_t floor_div(slimb_t a, slimb_t b)+{+ if (a >= 0) {+ return a / b;+ } else {+ return (a - b + 1) / b;+ }+}++/* return r = a modulo b (0 <= r <= b - 1. b must be >= 1 */+static inline limb_t smod(slimb_t a, slimb_t b)+{+ a = a % (slimb_t)b;+ if (a < 0)+ a += b;+ return a;+}++/* signed addition with saturation */+static inline slimb_t sat_add(slimb_t a, slimb_t b)+{+ slimb_t r;+ r = a + b;+ /* overflow ? */+ if (((a ^ r) & (b ^ r)) < 0)+ r = (a >> (LIMB_BITS - 1)) ^ (((limb_t)1 << (LIMB_BITS - 1)) - 1);+ return r;+}++#define malloc(s) malloc_is_forbidden(s)+#define free(p) free_is_forbidden(p)+#define realloc(p, s) realloc_is_forbidden(p, s)++void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func,+ void *realloc_opaque)+{+ memset(s, 0, sizeof(*s));+ s->realloc_func = realloc_func;+ s->realloc_opaque = realloc_opaque;+}++void bf_context_end(bf_context_t *s)+{+ bf_clear_cache(s);+}++void bf_init(bf_context_t *s, bf_t *r)+{+ r->ctx = s;+ r->sign = 0;+ r->expn = BF_EXP_ZERO;+ r->len = 0;+ r->tab = NULL;+}++/* return 0 if OK, -1 if alloc error */+int bf_resize(bf_t *r, limb_t len)+{+ limb_t *tab;+ + if (len != r->len) {+ tab = bf_realloc(r->ctx, r->tab, len * sizeof(limb_t));+ if (!tab && len != 0)+ return -1;+ r->tab = tab;+ r->len = len;+ }+ return 0;+}++/* return 0 or BF_ST_MEM_ERROR */+int bf_set_ui(bf_t *r, uint64_t a)+{+ r->sign = 0;+ if (a == 0) {+ r->expn = BF_EXP_ZERO;+ bf_resize(r, 0); /* cannot fail */+ } +#if LIMB_BITS == 32+ else if (a <= 0xffffffff)+#else+ else+#endif+ {+ int shift;+ if (bf_resize(r, 1))+ goto fail;+ shift = clz(a);+ r->tab[0] = a << shift;+ r->expn = LIMB_BITS - shift;+ }+#if LIMB_BITS == 32+ else {+ uint32_t a1, a0;+ int shift;+ if (bf_resize(r, 2))+ goto fail;+ a0 = a;+ a1 = a >> 32;+ shift = clz(a1);+ r->tab[0] = a0 << shift;+ r->tab[1] = (a1 << shift) | (a0 >> (LIMB_BITS - shift));+ r->expn = 2 * LIMB_BITS - shift;+ }+#endif+ return 0;+ fail:+ bf_set_nan(r);+ return BF_ST_MEM_ERROR;+}++/* return 0 or BF_ST_MEM_ERROR */+int bf_set_si(bf_t *r, int64_t a)+{+ int ret;++ if (a < 0) {+ ret = bf_set_ui(r, -a);+ r->sign = 1;+ } else {+ ret = bf_set_ui(r, a);+ }+ return ret;+}++void bf_set_nan(bf_t *r)+{+ bf_resize(r, 0); /* cannot fail */+ r->expn = BF_EXP_NAN;+ r->sign = 0;+}++void bf_set_zero(bf_t *r, int is_neg)+{+ bf_resize(r, 0); /* cannot fail */+ r->expn = BF_EXP_ZERO;+ r->sign = is_neg;+}++void bf_set_inf(bf_t *r, int is_neg)+{+ bf_resize(r, 0); /* cannot fail */+ r->expn = BF_EXP_INF;+ r->sign = is_neg;+}++/* return 0 or BF_ST_MEM_ERROR */+int bf_set(bf_t *r, const bf_t *a)+{+ if (r == a)+ return 0;+ if (bf_resize(r, a->len)) {+ bf_set_nan(r);+ return BF_ST_MEM_ERROR;+ }+ r->sign = a->sign;+ r->expn = a->expn;+ memcpy(r->tab, a->tab, a->len * sizeof(limb_t));+ return 0;+}++/* equivalent to bf_set(r, a); bf_delete(a) */+void bf_move(bf_t *r, bf_t *a)+{+ bf_context_t *s = r->ctx;+ if (r == a)+ return;+ bf_free(s, r->tab);+ *r = *a;+}++static limb_t get_limbz(const bf_t *a, limb_t idx)+{+ if (idx >= a->len)+ return 0;+ else+ return a->tab[idx];+}++/* get LIMB_BITS at bit position 'pos' in tab */+static inline limb_t get_bits(const limb_t *tab, limb_t len, slimb_t pos)+{+ limb_t i, a0, a1;+ int p;++ i = pos >> LIMB_LOG2_BITS;+ p = pos & (LIMB_BITS - 1);+ if (i < len)+ a0 = tab[i];+ else+ a0 = 0;+ if (p == 0) {+ return a0;+ } else {+ i++;+ if (i < len)+ a1 = tab[i];+ else+ a1 = 0;+ return (a0 >> p) | (a1 << (LIMB_BITS - p));+ }+}++static inline limb_t get_bit(const limb_t *tab, limb_t len, slimb_t pos)+{+ slimb_t i;+ i = pos >> LIMB_LOG2_BITS;+ if (i < 0 || i >= len)+ return 0;+ return (tab[i] >> (pos & (LIMB_BITS - 1))) & 1;+}++static inline limb_t limb_mask(int start, int last)+{+ limb_t v;+ int n;+ n = last - start + 1;+ if (n == LIMB_BITS)+ v = -1;+ else+ v = (((limb_t)1 << n) - 1) << start;+ return v;+}++static limb_t mp_scan_nz(const limb_t *tab, mp_size_t n)+{+ mp_size_t i;+ for(i = 0; i < n; i++) {+ if (tab[i] != 0)+ return 1;+ }+ return 0;+}++/* return != 0 if one bit between 0 and bit_pos inclusive is not zero. */+static inline limb_t scan_bit_nz(const bf_t *r, slimb_t bit_pos)+{+ slimb_t pos;+ limb_t v;+ + pos = bit_pos >> LIMB_LOG2_BITS;+ if (pos < 0)+ return 0;+ v = r->tab[pos] & limb_mask(0, bit_pos & (LIMB_BITS - 1));+ if (v != 0)+ return 1;+ pos--;+ while (pos >= 0) {+ if (r->tab[pos] != 0)+ return 1;+ pos--;+ }+ return 0;+}++/* return the addend for rounding. Note that prec can be <= 0 (for+ BF_FLAG_RADPNT_PREC) */+static int bf_get_rnd_add(int *pret, const bf_t *r, limb_t l,+ slimb_t prec, int rnd_mode)+{+ int add_one, inexact;+ limb_t bit1, bit0;+ + if (rnd_mode == BF_RNDF) {+ bit0 = 1; /* faithful rounding does not honor the INEXACT flag */+ } else {+ /* starting limb for bit 'prec + 1' */+ bit0 = scan_bit_nz(r, l * LIMB_BITS - 1 - bf_max(0, prec + 1));+ }++ /* get the bit at 'prec' */+ bit1 = get_bit(r->tab, l, l * LIMB_BITS - 1 - prec);+ inexact = (bit1 | bit0) != 0;+ + add_one = 0;+ switch(rnd_mode) {+ case BF_RNDZ:+ break;+ case BF_RNDN:+ if (bit1) {+ if (bit0) {+ add_one = 1;+ } else {+ /* round to even */+ add_one =+ get_bit(r->tab, l, l * LIMB_BITS - 1 - (prec - 1));+ }+ }+ break;+ case BF_RNDD:+ case BF_RNDU:+ if (r->sign == (rnd_mode == BF_RNDD))+ add_one = inexact;+ break;+ case BF_RNDA:+ add_one = inexact;+ break;+ case BF_RNDNA:+ case BF_RNDF:+ add_one = bit1;+ break;+ default:+ abort();+ }+ + if (inexact)+ *pret |= BF_ST_INEXACT;+ return add_one;+}++static int bf_set_overflow(bf_t *r, int sign, limb_t prec, bf_flags_t flags)+{+ slimb_t i, l, e_max;+ int rnd_mode;+ + rnd_mode = flags & BF_RND_MASK;+ if (prec == BF_PREC_INF ||+ rnd_mode == BF_RNDN ||+ rnd_mode == BF_RNDNA ||+ rnd_mode == BF_RNDA ||+ (rnd_mode == BF_RNDD && sign == 1) ||+ (rnd_mode == BF_RNDU && sign == 0)) {+ bf_set_inf(r, sign);+ } else {+ /* set to maximum finite number */+ l = (prec + LIMB_BITS - 1) / LIMB_BITS;+ if (bf_resize(r, l)) {+ bf_set_nan(r);+ return BF_ST_MEM_ERROR;+ }+ r->tab[0] = limb_mask((-prec) & (LIMB_BITS - 1),+ LIMB_BITS - 1);+ for(i = 1; i < l; i++)+ r->tab[i] = (limb_t)-1;+ e_max = (limb_t)1 << (bf_get_exp_bits(flags) - 1);+ r->expn = e_max;+ r->sign = sign;+ }+ return BF_ST_OVERFLOW | BF_ST_INEXACT;+}++/* round to prec1 bits assuming 'r' is non zero and finite. 'r' is+ assumed to have length 'l' (1 <= l <= r->len). Note: 'prec1' can be+ infinite (BF_PREC_INF). 'ret' is 0 or BF_ST_INEXACT if the result+ is known to be inexact. Can fail with BF_ST_MEM_ERROR in case of+ overflow not returning infinity. */+static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l,+ int ret)+{+ limb_t v, a;+ int shift, add_one, rnd_mode;+ slimb_t i, bit_pos, pos, e_min, e_max, e_range, prec;++ /* e_min and e_max are computed to match the IEEE 754 conventions */+ e_range = (limb_t)1 << (bf_get_exp_bits(flags) - 1);+ e_min = -e_range + 3;+ e_max = e_range;+ + if (flags & BF_FLAG_RADPNT_PREC) {+ /* 'prec' is the precision after the radix point */+ if (prec1 != BF_PREC_INF)+ prec = r->expn + prec1;+ else+ prec = prec1;+ } else if (unlikely(r->expn < e_min) && (flags & BF_FLAG_SUBNORMAL)) {+ /* restrict the precision in case of potentially subnormal+ result */+ assert(prec1 != BF_PREC_INF);+ prec = prec1 - (e_min - r->expn);+ } else {+ prec = prec1;+ }++ /* round to prec bits */+ rnd_mode = flags & BF_RND_MASK;+ add_one = bf_get_rnd_add(&ret, r, l, prec, rnd_mode);+ + if (prec <= 0) {+ if (add_one) {+ bf_resize(r, 1); /* cannot fail */+ r->tab[0] = (limb_t)1 << (LIMB_BITS - 1);+ r->expn += 1 - prec;+ ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;+ return ret;+ } else {+ goto underflow;+ }+ } else if (add_one) {+ limb_t carry;+ + /* add one starting at digit 'prec - 1' */+ bit_pos = l * LIMB_BITS - 1 - (prec - 1);+ pos = bit_pos >> LIMB_LOG2_BITS;+ carry = (limb_t)1 << (bit_pos & (LIMB_BITS - 1));+ + for(i = pos; i < l; i++) {+ v = r->tab[i] + carry;+ carry = (v < carry);+ r->tab[i] = v;+ if (carry == 0)+ break;+ }+ if (carry) {+ /* shift right by one digit */+ v = 1;+ for(i = l - 1; i >= pos; i--) {+ a = r->tab[i];+ r->tab[i] = (a >> 1) | (v << (LIMB_BITS - 1));+ v = a;+ }+ r->expn++;+ }+ }+ + /* check underflow */+ if (unlikely(r->expn < e_min)) {+ if (flags & BF_FLAG_SUBNORMAL) {+ /* if inexact, also set the underflow flag */+ if (ret & BF_ST_INEXACT)+ ret |= BF_ST_UNDERFLOW;+ } else {+ underflow:+ ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;+ bf_set_zero(r, r->sign);+ return ret;+ }+ }+ + /* check overflow */+ if (unlikely(r->expn > e_max))+ return bf_set_overflow(r, r->sign, prec1, flags);+ + /* keep the bits starting at 'prec - 1' */+ bit_pos = l * LIMB_BITS - 1 - (prec - 1);+ i = bit_pos >> LIMB_LOG2_BITS;+ if (i >= 0) {+ shift = bit_pos & (LIMB_BITS - 1);+ if (shift != 0)+ r->tab[i] &= limb_mask(shift, LIMB_BITS - 1);+ } else {+ i = 0;+ }+ /* remove trailing zeros */+ while (r->tab[i] == 0)+ i++;+ if (i > 0) {+ l -= i;+ memmove(r->tab, r->tab + i, l * sizeof(limb_t));+ }+ bf_resize(r, l); /* cannot fail */+ return ret;+}++/* 'r' must be a finite number. */+int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags)+{+ limb_t l, v, a;+ int shift, ret;+ slimb_t i;+ + // bf_print_str("bf_renorm", r);+ l = r->len;+ while (l > 0 && r->tab[l - 1] == 0)+ l--;+ if (l == 0) {+ /* zero */+ r->expn = BF_EXP_ZERO;+ bf_resize(r, 0); /* cannot fail */+ ret = 0;+ } else {+ r->expn -= (r->len - l) * LIMB_BITS;+ /* shift to have the MSB set to '1' */+ v = r->tab[l - 1];+ shift = clz(v);+ if (shift != 0) {+ v = 0;+ for(i = 0; i < l; i++) {+ a = r->tab[i];+ r->tab[i] = (a << shift) | (v >> (LIMB_BITS - shift));+ v = a;+ }+ r->expn -= shift;+ }+ ret = __bf_round(r, prec1, flags, l, 0);+ }+ // bf_print_str("r_final", r);+ return ret;+}++/* return true if rounding can be done at precision 'prec' assuming+ the exact result r is such that |r-a| <= 2^(EXP(a)-k). */+/* XXX: check the case where the exponent would be incremented by the+ rounding */+int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k)+{+ BOOL is_rndn;+ slimb_t bit_pos, n;+ limb_t bit;+ + if (a->expn == BF_EXP_INF || a->expn == BF_EXP_NAN)+ return FALSE;+ if (rnd_mode == BF_RNDF) {+ return (k >= (prec + 1));+ }+ if (a->expn == BF_EXP_ZERO)+ return FALSE;+ is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);+ if (k < (prec + 2))+ return FALSE;+ bit_pos = a->len * LIMB_BITS - 1 - prec;+ n = k - prec;+ /* bit pattern for RNDN or RNDNA: 0111.. or 1000...+ for other rounding modes: 000... or 111... + */+ bit = get_bit(a->tab, a->len, bit_pos);+ bit_pos--;+ n--;+ bit ^= is_rndn;+ /* XXX: slow, but a few iterations on average */+ while (n != 0) {+ if (get_bit(a->tab, a->len, bit_pos) != bit)+ return TRUE;+ bit_pos--;+ n--;+ }+ return FALSE;+}++/* Cannot fail with BF_ST_MEM_ERROR. */+int bf_round(bf_t *r, limb_t prec, bf_flags_t flags)+{+ if (r->len == 0)+ return 0;+ return __bf_round(r, prec, flags, r->len, 0);+}++/* for debugging */+static __maybe_unused void dump_limbs(const char *str, const limb_t *tab, limb_t n)+{+ limb_t i;+ printf("%s: len=%" PRId_LIMB "\n", str, n);+ for(i = 0; i < n; i++) {+ printf("%" PRId_LIMB ": " FMT_LIMB "\n",+ i, tab[i]);+ }+}++void mp_print_str(const char *str, const limb_t *tab, limb_t n)+{+ slimb_t i;+ printf("%s= 0x", str);+ for(i = n - 1; i >= 0; i--) {+ if (i != (n - 1))+ printf("_");+ printf(FMT_LIMB, tab[i]);+ }+ printf("\n");+}++static __maybe_unused void mp_print_str_h(const char *str,+ const limb_t *tab, limb_t n,+ limb_t high)+{+ slimb_t i;+ printf("%s= 0x", str);+ printf(FMT_LIMB, high);+ for(i = n - 1; i >= 0; i--) {+ printf("_");+ printf(FMT_LIMB, tab[i]);+ }+ printf("\n");+}++/* for debugging */+void bf_print_str(const char *str, const bf_t *a)+{+ slimb_t i;+ printf("%s=", str);++ if (a->expn == BF_EXP_NAN) {+ printf("NaN");+ } else {+ if (a->sign)+ putchar('-');+ if (a->expn == BF_EXP_ZERO) {+ putchar('0');+ } else if (a->expn == BF_EXP_INF) {+ printf("Inf");+ } else {+ printf("0x0.");+ for(i = a->len - 1; i >= 0; i--)+ printf(FMT_LIMB, a->tab[i]);+ printf("p%" PRId_LIMB, a->expn);+ }+ }+ printf("\n");+}++/* compare the absolute value of 'a' and 'b'. Return < 0 if a < b, 0+ if a = b and > 0 otherwise. */+int bf_cmpu(const bf_t *a, const bf_t *b)+{+ slimb_t i;+ limb_t len, v1, v2;+ + if (a->expn != b->expn) {+ if (a->expn < b->expn)+ return -1;+ else+ return 1;+ }+ len = bf_max(a->len, b->len);+ for(i = len - 1; i >= 0; i--) {+ v1 = get_limbz(a, a->len - len + i);+ v2 = get_limbz(b, b->len - len + i);+ if (v1 != v2) {+ if (v1 < v2)+ return -1;+ else+ return 1;+ }+ }+ return 0;+}++/* Full order: -0 < 0, NaN == NaN and NaN is larger than all other numbers */+int bf_cmp_full(const bf_t *a, const bf_t *b)+{+ int res;+ + if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {+ if (a->expn == b->expn)+ res = 0;+ else if (a->expn == BF_EXP_NAN)+ res = 1;+ else+ res = -1;+ } else if (a->sign != b->sign) {+ res = 1 - 2 * a->sign;+ } else {+ res = bf_cmpu(a, b);+ if (a->sign)+ res = -res;+ }+ return res;+}++/* Standard floating point comparison: return 2 if one of the operands+ is NaN (unordered) or -1, 0, 1 depending on the ordering assuming+ -0 == +0 */+int bf_cmp(const bf_t *a, const bf_t *b)+{+ int res;+ + if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {+ res = 2;+ } else if (a->sign != b->sign) {+ if (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO)+ res = 0;+ else+ res = 1 - 2 * a->sign;+ } else {+ res = bf_cmpu(a, b);+ if (a->sign)+ res = -res;+ }+ return res;+}++/* Compute the number of bits 'n' matching the pattern:+ a= X1000..0+ b= X0111..1+ + When computing a-b, the result will have at least n leading zero+ bits.++ Precondition: a > b and a.expn - b.expn = 0 or 1+*/+static limb_t count_cancelled_bits(const bf_t *a, const bf_t *b)+{+ slimb_t bit_offset, b_offset, n;+ int p, p1;+ limb_t v1, v2, mask;++ bit_offset = a->len * LIMB_BITS - 1;+ b_offset = (b->len - a->len) * LIMB_BITS - (LIMB_BITS - 1) ++ a->expn - b->expn;+ n = 0;++ /* first search the equals bits */+ for(;;) {+ v1 = get_limbz(a, bit_offset >> LIMB_LOG2_BITS);+ v2 = get_bits(b->tab, b->len, bit_offset + b_offset);+ // printf("v1=" FMT_LIMB " v2=" FMT_LIMB "\n", v1, v2);+ if (v1 != v2)+ break;+ n += LIMB_BITS;+ bit_offset -= LIMB_BITS;+ }+ /* find the position of the first different bit */+ p = clz(v1 ^ v2) + 1;+ n += p;+ /* then search for '0' in a and '1' in b */+ p = LIMB_BITS - p;+ if (p > 0) {+ /* search in the trailing p bits of v1 and v2 */+ mask = limb_mask(0, p - 1);+ p1 = bf_min(clz(v1 & mask), clz((~v2) & mask)) - (LIMB_BITS - p);+ n += p1;+ if (p1 != p)+ goto done;+ }+ bit_offset -= LIMB_BITS;+ for(;;) {+ v1 = get_limbz(a, bit_offset >> LIMB_LOG2_BITS);+ v2 = get_bits(b->tab, b->len, bit_offset + b_offset);+ // printf("v1=" FMT_LIMB " v2=" FMT_LIMB "\n", v1, v2);+ if (v1 != 0 || v2 != -1) {+ /* different: count the matching bits */+ p1 = bf_min(clz(v1), clz(~v2));+ n += p1;+ break;+ }+ n += LIMB_BITS;+ bit_offset -= LIMB_BITS;+ }+ done:+ return n;+}++static int bf_add_internal(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,+ bf_flags_t flags, int b_neg)+{+ const bf_t *tmp;+ int is_sub, ret, cmp_res, a_sign, b_sign;++ a_sign = a->sign;+ b_sign = b->sign ^ b_neg;+ is_sub = a_sign ^ b_sign;+ cmp_res = bf_cmpu(a, b);+ if (cmp_res < 0) {+ tmp = a;+ a = b;+ b = tmp;+ a_sign = b_sign; /* b_sign is never used later */+ }+ /* abs(a) >= abs(b) */+ if (cmp_res == 0 && is_sub && a->expn < BF_EXP_INF) {+ /* zero result */+ bf_set_zero(r, (flags & BF_RND_MASK) == BF_RNDD);+ ret = 0;+ } else if (a->len == 0 || b->len == 0) {+ ret = 0;+ if (a->expn >= BF_EXP_INF) {+ if (a->expn == BF_EXP_NAN) {+ /* at least one operand is NaN */+ bf_set_nan(r);+ } else if (b->expn == BF_EXP_INF && is_sub) {+ /* infinities with different signs */+ bf_set_nan(r);+ ret = BF_ST_INVALID_OP;+ } else {+ bf_set_inf(r, a_sign);+ }+ } else {+ /* at least one zero and not subtract */+ bf_set(r, a);+ r->sign = a_sign;+ goto renorm;+ }+ } else {+ slimb_t d, a_offset, b_bit_offset, i, cancelled_bits;+ limb_t carry, v1, v2, u, r_len, carry1, precl, tot_len, z, sub_mask;++ r->sign = a_sign;+ r->expn = a->expn;+ d = a->expn - b->expn;+ /* must add more precision for the leading cancelled bits in+ subtraction */+ if (is_sub) {+ if (d <= 1)+ cancelled_bits = count_cancelled_bits(a, b);+ else+ cancelled_bits = 1;+ } else {+ cancelled_bits = 0;+ }+ + /* add two extra bits for rounding */+ precl = (cancelled_bits + prec + 2 + LIMB_BITS - 1) / LIMB_BITS;+ tot_len = bf_max(a->len, b->len + (d + LIMB_BITS - 1) / LIMB_BITS);+ r_len = bf_min(precl, tot_len);+ if (bf_resize(r, r_len))+ goto fail;+ a_offset = a->len - r_len;+ b_bit_offset = (b->len - r_len) * LIMB_BITS + d;++ /* compute the bits before for the rounding */+ carry = is_sub;+ z = 0;+ sub_mask = -is_sub;+ i = r_len - tot_len;+ while (i < 0) {+ slimb_t ap, bp;+ BOOL inflag;+ + ap = a_offset + i;+ bp = b_bit_offset + i * LIMB_BITS;+ inflag = FALSE;+ if (ap >= 0 && ap < a->len) {+ v1 = a->tab[ap];+ inflag = TRUE;+ } else {+ v1 = 0;+ }+ if (bp + LIMB_BITS > 0 && bp < (slimb_t)(b->len * LIMB_BITS)) {+ v2 = get_bits(b->tab, b->len, bp);+ inflag = TRUE;+ } else {+ v2 = 0;+ }+ if (!inflag) {+ /* outside 'a' and 'b': go directly to the next value+ inside a or b so that the running time does not+ depend on the exponent difference */+ i = 0;+ if (ap < 0)+ i = bf_min(i, -a_offset);+ /* b_bit_offset + i * LIMB_BITS + LIMB_BITS >= 1+ equivalent to + i >= ceil(-b_bit_offset + 1 - LIMB_BITS) / LIMB_BITS)+ */+ if (bp + LIMB_BITS <= 0)+ i = bf_min(i, (-b_bit_offset) >> LIMB_LOG2_BITS);+ } else {+ i++;+ }+ v2 ^= sub_mask;+ u = v1 + v2;+ carry1 = u < v1;+ u += carry;+ carry = (u < carry) | carry1;+ z |= u;+ }+ /* and the result */+ for(i = 0; i < r_len; i++) {+ v1 = get_limbz(a, a_offset + i);+ v2 = get_bits(b->tab, b->len, b_bit_offset + i * LIMB_BITS);+ v2 ^= sub_mask;+ u = v1 + v2;+ carry1 = u < v1;+ u += carry;+ carry = (u < carry) | carry1;+ r->tab[i] = u;+ }+ /* set the extra bits for the rounding */+ r->tab[0] |= (z != 0);++ /* carry is only possible in add case */+ if (!is_sub && carry) {+ if (bf_resize(r, r_len + 1))+ goto fail;+ r->tab[r_len] = 1;+ r->expn += LIMB_BITS;+ }+ renorm:+ ret = bf_normalize_and_round(r, prec, flags);+ }+ return ret;+ fail:+ bf_set_nan(r);+ return BF_ST_MEM_ERROR;+}++static int __bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,+ bf_flags_t flags)+{+ return bf_add_internal(r, a, b, prec, flags, 0);+}++static int __bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,+ bf_flags_t flags)+{+ return bf_add_internal(r, a, b, prec, flags, 1);+}++limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2, + limb_t n, limb_t carry)+{+ slimb_t i;+ limb_t k, a, v, k1;+ + k = carry;+ for(i=0;i<n;i++) {+ v = op1[i];+ a = v + op2[i];+ k1 = a < v;+ a = a + k;+ k = (a < k) | k1;+ res[i] = a;+ }+ return k;+}++limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n)+{+ size_t i;+ limb_t k, a;++ k=b;+ for(i=0;i<n;i++) {+ if (k == 0)+ break;+ a = tab[i] + k;+ k = (a < k);+ tab[i] = a;+ }+ return k;+}++limb_t mp_sub(limb_t *res, const limb_t *op1, const limb_t *op2, + mp_size_t n, limb_t carry)+{+ int i;+ limb_t k, a, v, k1;+ + k = carry;+ for(i=0;i<n;i++) {+ v = op1[i];+ a = v - op2[i];+ k1 = a > v;+ v = a - k;+ k = (v > a) | k1;+ res[i] = v;+ }+ return k;+}++/* compute 0 - op2 */+static limb_t mp_neg(limb_t *res, const limb_t *op2, mp_size_t n, limb_t carry)+{+ int i;+ limb_t k, a, v, k1;+ + k = carry;+ for(i=0;i<n;i++) {+ v = 0;+ a = v - op2[i];+ k1 = a > v;+ v = a - k;+ k = (v > a) | k1;+ res[i] = v;+ }+ return k;+}++limb_t mp_sub_ui(limb_t *tab, limb_t b, mp_size_t n)+{+ mp_size_t i;+ limb_t k, a, v;+ + k=b;+ for(i=0;i<n;i++) {+ v = tab[i];+ a = v - k;+ k = a > v;+ tab[i] = a;+ if (k == 0)+ break;+ }+ return k;+}++/* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift). + 1 <= shift <= LIMB_BITS - 1 */+static limb_t mp_shr(limb_t *tab_r, const limb_t *tab, mp_size_t n, + int shift, limb_t high)+{+ mp_size_t i;+ limb_t l, a;++ assert(shift >= 1 && shift < LIMB_BITS);+ l = high;+ for(i = n - 1; i >= 0; i--) {+ a = tab[i];+ tab_r[i] = (a >> shift) | (l << (LIMB_BITS - shift));+ l = a;+ }+ return l & (((limb_t)1 << shift) - 1);+}++/* tabr[] = taba[] * b + l. Return the high carry */+static limb_t mp_mul1(limb_t *tabr, const limb_t *taba, limb_t n, + limb_t b, limb_t l)+{+ limb_t i;+ dlimb_t t;++ for(i = 0; i < n; i++) {+ t = (dlimb_t)taba[i] * (dlimb_t)b + l;+ tabr[i] = t;+ l = t >> LIMB_BITS;+ }+ return l;+}++/* tabr[] += taba[] * b, return the high word. */+static limb_t mp_add_mul1(limb_t *tabr, const limb_t *taba, limb_t n,+ limb_t b)+{+ limb_t i, l;+ dlimb_t t;+ + l = 0;+ for(i = 0; i < n; i++) {+ t = (dlimb_t)taba[i] * (dlimb_t)b + l + tabr[i];+ tabr[i] = t;+ l = t >> LIMB_BITS;+ }+ return l;+}++/* size of the result : op1_size + op2_size. */+static void mp_mul_basecase(limb_t *result, + const limb_t *op1, limb_t op1_size, + const limb_t *op2, limb_t op2_size) +{+ limb_t i, r;+ + result[op1_size] = mp_mul1(result, op1, op1_size, op2[0], 0);+ for(i=1;i<op2_size;i++) {+ r = mp_add_mul1(result + i, op1, op1_size, op2[i]);+ result[i + op1_size] = r;+ }+}++/* return 0 if OK, -1 if memory error */+/* XXX: change API so that result can be allocated */+int mp_mul(bf_context_t *s, limb_t *result, + const limb_t *op1, limb_t op1_size, + const limb_t *op2, limb_t op2_size) +{+#ifdef USE_FFT_MUL+ if (unlikely(bf_min(op1_size, op2_size) >= FFT_MUL_THRESHOLD)) {+ bf_t r_s, *r = &r_s;+ r->tab = result;+ /* XXX: optimize memory usage in API */+ if (fft_mul(s, r, (limb_t *)op1, op1_size,+ (limb_t *)op2, op2_size, FFT_MUL_R_NORESIZE))+ return -1;+ } else+#endif+ {+ mp_mul_basecase(result, op1, op1_size, op2, op2_size);+ }+ return 0;+}++/* tabr[] -= taba[] * b. Return the value to substract to the high+ word. */+static limb_t mp_sub_mul1(limb_t *tabr, const limb_t *taba, limb_t n,+ limb_t b)+{+ limb_t i, l;+ dlimb_t t;+ + l = 0;+ for(i = 0; i < n; i++) {+ t = tabr[i] - (dlimb_t)taba[i] * (dlimb_t)b - l;+ tabr[i] = t;+ l = -(t >> LIMB_BITS);+ }+ return l;+}++/* WARNING: d must be >= 2^(LIMB_BITS-1) */+static inline limb_t udiv1norm_init(limb_t d)+{+ limb_t a0, a1;+ a1 = -d - 1;+ a0 = -1;+ return (((dlimb_t)a1 << LIMB_BITS) | a0) / d;+}++/* return the quotient and the remainder in '*pr'of 'a1*2^LIMB_BITS+a0+ / d' with 0 <= a1 < d. */+static inline limb_t udiv1norm(limb_t *pr, limb_t a1, limb_t a0,+ limb_t d, limb_t d_inv)+{+ limb_t n1m, n_adj, q, r, ah;+ dlimb_t a;+ n1m = ((slimb_t)a0 >> (LIMB_BITS - 1));+ n_adj = a0 + (n1m & d);+ a = (dlimb_t)d_inv * (a1 - n1m) + n_adj;+ q = (a >> LIMB_BITS) + a1;+ /* compute a - q * r and update q so that the remainder is\+ between 0 and d - 1 */+ a = ((dlimb_t)a1 << LIMB_BITS) | a0;+ a = a - (dlimb_t)q * d - d;+ ah = a >> LIMB_BITS;+ q += 1 + ah;+ r = (limb_t)a + (ah & d);+ *pr = r;+ return q;+}++/* b must be >= 1 << (LIMB_BITS - 1) */+static limb_t mp_div1norm(limb_t *tabr, const limb_t *taba, limb_t n,+ limb_t b, limb_t r)+{+ slimb_t i;++ if (n >= UDIV1NORM_THRESHOLD) {+ limb_t b_inv;+ b_inv = udiv1norm_init(b);+ for(i = n - 1; i >= 0; i--) {+ tabr[i] = udiv1norm(&r, r, taba[i], b, b_inv);+ }+ } else {+ dlimb_t a1;+ for(i = n - 1; i >= 0; i--) {+ a1 = ((dlimb_t)r << LIMB_BITS) | taba[i];+ tabr[i] = a1 / b;+ r = a1 % b;+ }+ }+ return r;+}++static int mp_divnorm_large(bf_context_t *s, + limb_t *tabq, limb_t *taba, limb_t na, + const limb_t *tabb, limb_t nb);++/* base case division: divides taba[0..na-1] by tabb[0..nb-1]. tabb[nb+ - 1] must be >= 1 << (LIMB_BITS - 1). na - nb must be >= 0. 'taba'+ is modified and contains the remainder (nb limbs). tabq[0..na-nb]+ contains the quotient with tabq[na - nb] <= 1. */+static int mp_divnorm(bf_context_t *s, limb_t *tabq, limb_t *taba, limb_t na, + const limb_t *tabb, limb_t nb)+{+ limb_t r, a, c, q, v, b1, b1_inv, n, dummy_r;+ slimb_t i, j;++ b1 = tabb[nb - 1];+ if (nb == 1) {+ taba[0] = mp_div1norm(tabq, taba, na, b1, 0);+ return 0;+ }+ n = na - nb;+ if (bf_min(n, nb) >= DIVNORM_LARGE_THRESHOLD) {+ return mp_divnorm_large(s, tabq, taba, na, tabb, nb);+ }+ + if (n >= UDIV1NORM_THRESHOLD)+ b1_inv = udiv1norm_init(b1);+ else+ b1_inv = 0;++ /* first iteration: the quotient is only 0 or 1 */+ q = 1;+ for(j = nb - 1; j >= 0; j--) {+ if (taba[n + j] != tabb[j]) {+ if (taba[n + j] < tabb[j])+ q = 0;+ break;+ }+ }+ tabq[n] = q;+ if (q) {+ mp_sub(taba + n, taba + n, tabb, nb, 0);+ }+ + for(i = n - 1; i >= 0; i--) {+ if (unlikely(taba[i + nb] >= b1)) {+ q = -1;+ } else if (b1_inv) {+ q = udiv1norm(&dummy_r, taba[i + nb], taba[i + nb - 1], b1, b1_inv);+ } else {+ dlimb_t al;+ al = ((dlimb_t)taba[i + nb] << LIMB_BITS) | taba[i + nb - 1];+ q = al / b1;+ r = al % b1;+ }+ r = mp_sub_mul1(taba + i, tabb, nb, q);++ v = taba[i + nb];+ a = v - r;+ c = (a > v);+ taba[i + nb] = a;++ if (c != 0) {+ /* negative result */+ for(;;) {+ q--;+ c = mp_add(taba + i, taba + i, tabb, nb, 0);+ /* propagate carry and test if positive result */+ if (c != 0) {+ if (++taba[i + nb] == 0) {+ break;+ }+ }+ }+ }+ tabq[i] = q;+ }+ return 0;+}++/* compute r=B^(2*n)/a such as a*r < B^(2*n) < a*r + 2 with n >= 1. 'a'+ has n limbs with a[n-1] >= B/2 and 'r' has n+1 limbs with r[n] = 1.+ + See Modern Computer Arithmetic by Richard P. Brent and Paul+ Zimmermann, algorithm 3.5 */+int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n)+{+ mp_size_t l, h, k, i;+ limb_t *tabxh, *tabt, c, *tabu;+ + if (n <= 2) {+ /* return ceil(B^(2*n)/a) - 1 */+ /* XXX: could avoid allocation */+ tabu = bf_malloc(s, sizeof(limb_t) * (2 * n + 1));+ tabt = bf_malloc(s, sizeof(limb_t) * (n + 2));+ if (!tabt || !tabu)+ goto fail;+ for(i = 0; i < 2 * n; i++)+ tabu[i] = 0;+ tabu[2 * n] = 1;+ if (mp_divnorm(s, tabt, tabu, 2 * n + 1, taba, n))+ goto fail;+ for(i = 0; i < n + 1; i++)+ tabr[i] = tabt[i];+ if (mp_scan_nz(tabu, n) == 0) {+ /* only happens for a=B^n/2 */+ mp_sub_ui(tabr, 1, n + 1);+ }+ } else {+ l = (n - 1) / 2;+ h = n - l;+ /* n=2p -> l=p-1, h = p + 1, k = p + 3+ n=2p+1-> l=p, h = p + 1; k = p + 2+ */+ tabt = bf_malloc(s, sizeof(limb_t) * (n + h + 1));+ tabu = bf_malloc(s, sizeof(limb_t) * (n + 2 * h - l + 2));+ if (!tabt || !tabu)+ goto fail;+ tabxh = tabr + l;+ if (mp_recip(s, tabxh, taba + l, h))+ goto fail;+ if (mp_mul(s, tabt, taba, n, tabxh, h + 1)) /* n + h + 1 limbs */+ goto fail;+ while (tabt[n + h] != 0) {+ mp_sub_ui(tabxh, 1, h + 1);+ c = mp_sub(tabt, tabt, taba, n, 0);+ mp_sub_ui(tabt + n, c, h + 1);+ }+ /* T = B^(n+h) - T */+ mp_neg(tabt, tabt, n + h + 1, 0);+ tabt[n + h]++;+ if (mp_mul(s, tabu, tabt + l, n + h + 1 - l, tabxh, h + 1))+ goto fail;+ /* n + 2*h - l + 2 limbs */+ k = 2 * h - l;+ for(i = 0; i < l; i++)+ tabr[i] = tabu[i + k];+ mp_add(tabr + l, tabr + l, tabu + 2 * h, h, 0);+ }+ bf_free(s, tabt);+ bf_free(s, tabu);+ return 0;+ fail:+ bf_free(s, tabt);+ bf_free(s, tabu);+ return -1;+}++/* return -1, 0 or 1 */+static int mp_cmp(const limb_t *taba, const limb_t *tabb, mp_size_t n)+{+ mp_size_t i;+ for(i = n - 1; i >= 0; i--) {+ if (taba[i] != tabb[i]) {+ if (taba[i] < tabb[i])+ return -1;+ else+ return 1;+ }+ }+ return 0;+}++//#define DEBUG_DIVNORM_LARGE+//#define DEBUG_DIVNORM_LARGE2++/* subquadratic divnorm */+static int mp_divnorm_large(bf_context_t *s, + limb_t *tabq, limb_t *taba, limb_t na, + const limb_t *tabb, limb_t nb)+{+ limb_t *tabb_inv, nq, *tabt, i, n;+ nq = na - nb;+#ifdef DEBUG_DIVNORM_LARGE+ printf("na=%d nb=%d nq=%d\n", (int)na, (int)nb, (int)nq);+ mp_print_str("a", taba, na);+ mp_print_str("b", tabb, nb);+#endif+ assert(nq >= 1);+ n = nq;+ if (nq < nb)+ n++; + tabb_inv = bf_malloc(s, sizeof(limb_t) * (n + 1));+ tabt = bf_malloc(s, sizeof(limb_t) * 2 * (n + 1));+ if (!tabb_inv || !tabt)+ goto fail;++ if (n >= nb) {+ for(i = 0; i < n - nb; i++)+ tabt[i] = 0;+ for(i = 0; i < nb; i++)+ tabt[i + n - nb] = tabb[i];+ } else {+ /* truncate B: need to increment it so that the approximate+ inverse is smaller that the exact inverse */+ for(i = 0; i < n; i++)+ tabt[i] = tabb[i + nb - n];+ if (mp_add_ui(tabt, 1, n)) {+ /* tabt = B^n : tabb_inv = B^n */+ memset(tabb_inv, 0, n * sizeof(limb_t));+ tabb_inv[n] = 1;+ goto recip_done;+ }+ }+ if (mp_recip(s, tabb_inv, tabt, n))+ goto fail;+ recip_done:+ /* Q=A*B^-1 */+ if (mp_mul(s, tabt, tabb_inv, n + 1, taba + na - (n + 1), n + 1))+ goto fail;+ + for(i = 0; i < nq + 1; i++)+ tabq[i] = tabt[i + 2 * (n + 1) - (nq + 1)];+#ifdef DEBUG_DIVNORM_LARGE+ mp_print_str("q", tabq, nq + 1);+#endif++ bf_free(s, tabt);+ bf_free(s, tabb_inv);+ tabb_inv = NULL;+ + /* R=A-B*Q */+ tabt = bf_malloc(s, sizeof(limb_t) * (na + 1));+ if (!tabt)+ goto fail;+ if (mp_mul(s, tabt, tabq, nq + 1, tabb, nb))+ goto fail;+ /* we add one more limb for the result */+ mp_sub(taba, taba, tabt, nb + 1, 0);+ bf_free(s, tabt);+ /* the approximated quotient is smaller than than the exact one,+ hence we may have to increment it */+#ifdef DEBUG_DIVNORM_LARGE2+ int cnt = 0;+ static int cnt_max;+#endif+ for(;;) {+ if (taba[nb] == 0 && mp_cmp(taba, tabb, nb) < 0)+ break;+ taba[nb] -= mp_sub(taba, taba, tabb, nb, 0);+ mp_add_ui(tabq, 1, nq + 1);+#ifdef DEBUG_DIVNORM_LARGE2+ cnt++;+#endif+ }+#ifdef DEBUG_DIVNORM_LARGE2+ if (cnt > cnt_max) {+ cnt_max = cnt;+ printf("\ncnt=%d nq=%d nb=%d\n", cnt_max, (int)nq, (int)nb);+ }+#endif+ return 0;+ fail:+ bf_free(s, tabb_inv);+ bf_free(s, tabt);+ return -1;+}++int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,+ bf_flags_t flags)+{+ int ret, r_sign;++ if (a->len < b->len) {+ const bf_t *tmp = a;+ a = b;+ b = tmp;+ }+ r_sign = a->sign ^ b->sign;+ /* here b->len <= a->len */+ if (b->len == 0) {+ if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {+ bf_set_nan(r);+ ret = 0;+ } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_INF) {+ if ((a->expn == BF_EXP_INF && b->expn == BF_EXP_ZERO) ||+ (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_INF)) {+ bf_set_nan(r);+ ret = BF_ST_INVALID_OP;+ } else {+ bf_set_inf(r, r_sign);+ ret = 0;+ }+ } else {+ bf_set_zero(r, r_sign);+ ret = 0;+ }+ } else {+ bf_t tmp, *r1 = NULL;+ limb_t a_len, b_len, precl;+ limb_t *a_tab, *b_tab;+ + a_len = a->len;+ b_len = b->len;+ + if ((flags & BF_RND_MASK) == BF_RNDF) {+ /* faithful rounding does not require using the full inputs */+ precl = (prec + 2 + LIMB_BITS - 1) / LIMB_BITS;+ a_len = bf_min(a_len, precl);+ b_len = bf_min(b_len, precl);+ }+ a_tab = a->tab + a->len - a_len;+ b_tab = b->tab + b->len - b_len;+ +#ifdef USE_FFT_MUL+ if (b_len >= FFT_MUL_THRESHOLD) {+ int mul_flags = 0;+ if (r == a)+ mul_flags |= FFT_MUL_R_OVERLAP_A;+ if (r == b)+ mul_flags |= FFT_MUL_R_OVERLAP_B;+ if (fft_mul(r->ctx, r, a_tab, a_len, b_tab, b_len, mul_flags))+ goto fail;+ } else+#endif+ {+ if (r == a || r == b) {+ bf_init(r->ctx, &tmp);+ r1 = r;+ r = &tmp;+ }+ if (bf_resize(r, a_len + b_len)) {+ fail:+ bf_set_nan(r);+ ret = BF_ST_MEM_ERROR;+ goto done;+ }+ mp_mul_basecase(r->tab, a_tab, a_len, b_tab, b_len);+ }+ r->sign = r_sign;+ r->expn = a->expn + b->expn;+ ret = bf_normalize_and_round(r, prec, flags);+ done:+ if (r == &tmp)+ bf_move(r1, &tmp);+ }+ return ret;+}++/* multiply 'r' by 2^e */+int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags)+{+ slimb_t e_max;+ if (r->len == 0)+ return 0;+ e_max = ((limb_t)1 << BF_EXT_EXP_BITS_MAX) - 1;+ e = bf_max(e, -e_max);+ e = bf_min(e, e_max);+ r->expn += e;+ return __bf_round(r, prec, flags, r->len, 0);+}++/* Return e such as a=m*2^e with m odd integer. return 0 if a is zero,+ Infinite or Nan. */+slimb_t bf_get_exp_min(const bf_t *a)+{+ slimb_t i;+ limb_t v;+ int k;+ + for(i = 0; i < a->len; i++) {+ v = a->tab[i];+ if (v != 0) {+ k = ctz(v);+ return a->expn - (a->len - i) * LIMB_BITS + k;+ }+ }+ return 0;+}++/* a and b must be finite numbers with a >= 0 and b > 0. 'q' is the+ integer defined as floor(a/b) and r = a - q * b. */+static void bf_tdivremu(bf_t *q, bf_t *r,+ const bf_t *a, const bf_t *b)+{+ if (bf_cmpu(a, b) < 0) {+ bf_set_ui(q, 0);+ bf_set(r, a);+ } else {+ bf_div(q, a, b, bf_max(a->expn - b->expn + 1, 2), BF_RNDZ);+ bf_rint(q, BF_RNDZ);+ bf_mul(r, q, b, BF_PREC_INF, BF_RNDZ);+ bf_sub(r, a, r, BF_PREC_INF, BF_RNDZ);+ }+}++static int __bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,+ bf_flags_t flags)+{+ bf_context_t *s = r->ctx;+ int ret, r_sign;+ limb_t n, nb, precl;+ + r_sign = a->sign ^ b->sign;+ if (a->expn >= BF_EXP_INF || b->expn >= BF_EXP_INF) {+ if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {+ bf_set_nan(r);+ return 0;+ } else if (a->expn == BF_EXP_INF && b->expn == BF_EXP_INF) {+ bf_set_nan(r);+ return BF_ST_INVALID_OP;+ } else if (a->expn == BF_EXP_INF) {+ bf_set_inf(r, r_sign);+ return 0;+ } else {+ bf_set_zero(r, r_sign);+ return 0;+ }+ } else if (a->expn == BF_EXP_ZERO) {+ if (b->expn == BF_EXP_ZERO) {+ bf_set_nan(r);+ return BF_ST_INVALID_OP;+ } else {+ bf_set_zero(r, r_sign);+ return 0;+ }+ } else if (b->expn == BF_EXP_ZERO) {+ bf_set_inf(r, r_sign);+ return BF_ST_DIVIDE_ZERO;+ }++ /* number of limbs of the quotient (2 extra bits for rounding) */+ precl = (prec + 2 + LIMB_BITS - 1) / LIMB_BITS;+ nb = b->len;+ n = bf_max(a->len, precl);+ + {+ limb_t *taba, na;+ slimb_t d;+ + na = n + nb;+ taba = bf_malloc(s, (na + 1) * sizeof(limb_t));+ if (!taba)+ goto fail;+ d = na - a->len;+ memset(taba, 0, d * sizeof(limb_t));+ memcpy(taba + d, a->tab, a->len * sizeof(limb_t));+ if (bf_resize(r, n + 1))+ goto fail1;+ if (mp_divnorm(s, r->tab, taba, na, b->tab, nb)) {+ fail1:+ bf_free(s, taba);+ goto fail;+ }+ /* see if non zero remainder */+ if (mp_scan_nz(taba, nb))+ r->tab[0] |= 1;+ bf_free(r->ctx, taba);+ r->expn = a->expn - b->expn + LIMB_BITS;+ r->sign = r_sign;+ ret = bf_normalize_and_round(r, prec, flags);+ }+ return ret;+ fail:+ bf_set_nan(r);+ return BF_ST_MEM_ERROR;+}++/* division and remainder. + + rnd_mode is the rounding mode for the quotient. The additional+ rounding mode BF_RND_EUCLIDIAN is supported.++ 'q' is an integer. 'r' is rounded with prec and flags (prec can be+ BF_PREC_INF).+*/+int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,+ limb_t prec, bf_flags_t flags, int rnd_mode)+{+ bf_t a1_s, *a1 = &a1_s;+ bf_t b1_s, *b1 = &b1_s;+ int q_sign, ret;+ BOOL is_ceil, is_rndn;+ + assert(q != a && q != b);+ assert(r != a && r != b);+ assert(q != r);+ + if (a->len == 0 || b->len == 0) {+ bf_set_zero(q, 0);+ if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {+ bf_set_nan(r);+ return 0;+ } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_ZERO) {+ bf_set_nan(r);+ return BF_ST_INVALID_OP;+ } else {+ bf_set(r, a);+ return bf_round(r, prec, flags);+ }+ }++ q_sign = a->sign ^ b->sign;+ is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);+ switch(rnd_mode) {+ default:+ case BF_RNDZ:+ case BF_RNDN:+ case BF_RNDNA:+ is_ceil = FALSE;+ break;+ case BF_RNDD:+ is_ceil = q_sign;+ break;+ case BF_RNDU:+ is_ceil = q_sign ^ 1;+ break;+ case BF_RNDA:+ is_ceil = TRUE;+ break;+ case BF_DIVREM_EUCLIDIAN:+ is_ceil = a->sign;+ break;+ }++ a1->expn = a->expn;+ a1->tab = a->tab;+ a1->len = a->len;+ a1->sign = 0;+ + b1->expn = b->expn;+ b1->tab = b->tab;+ b1->len = b->len;+ b1->sign = 0;++ /* XXX: could improve to avoid having a large 'q' */+ bf_tdivremu(q, r, a1, b1);+ if (bf_is_nan(q) || bf_is_nan(r))+ goto fail;++ if (r->len != 0) {+ if (is_rndn) {+ int res;+ b1->expn--;+ res = bf_cmpu(r, b1);+ b1->expn++;+ if (res > 0 ||+ (res == 0 &&+ (rnd_mode == BF_RNDNA ||+ get_bit(q->tab, q->len, q->len * LIMB_BITS - q->expn)))) {+ goto do_sub_r;+ }+ } else if (is_ceil) {+ do_sub_r:+ ret = bf_add_si(q, q, 1, BF_PREC_INF, BF_RNDZ);+ ret |= bf_sub(r, r, b1, BF_PREC_INF, BF_RNDZ);+ if (ret & BF_ST_MEM_ERROR)+ goto fail;+ }+ }++ r->sign ^= a->sign;+ q->sign = q_sign;+ return bf_round(r, prec, flags);+ fail:+ bf_set_nan(q);+ bf_set_nan(r);+ return BF_ST_MEM_ERROR;+}++int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,+ bf_flags_t flags, int rnd_mode)+{+ bf_t q_s, *q = &q_s;+ int ret;+ + bf_init(r->ctx, q);+ ret = bf_divrem(q, r, a, b, prec, flags, rnd_mode);+ bf_delete(q);+ return ret;+}++static inline int bf_get_limb(slimb_t *pres, const bf_t *a, int flags)+{+#if LIMB_BITS == 32+ return bf_get_int32(pres, a, flags);+#else+ return bf_get_int64(pres, a, flags);+#endif+}++int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,+ bf_flags_t flags, int rnd_mode)+{+ bf_t q_s, *q = &q_s;+ int ret;+ + bf_init(r->ctx, q);+ ret = bf_divrem(q, r, a, b, prec, flags, rnd_mode);+ bf_get_limb(pq, q, BF_GET_INT_MOD);+ bf_delete(q);+ return ret;+}++static __maybe_unused inline limb_t mul_mod(limb_t a, limb_t b, limb_t m)+{+ dlimb_t t;+ t = (dlimb_t)a * (dlimb_t)b;+ return t % m;+}++#if defined(USE_MUL_CHECK)+static limb_t mp_mod1(const limb_t *tab, limb_t n, limb_t m, limb_t r)+{+ slimb_t i;+ dlimb_t t;++ for(i = n - 1; i >= 0; i--) {+ t = ((dlimb_t)r << LIMB_BITS) | tab[i];+ r = t % m;+ }+ return r;+}+#endif++static const uint16_t sqrt_table[192] = {+128,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,144,145,146,147,148,149,150,150,151,152,153,154,155,155,156,157,158,159,160,160,161,162,163,163,164,165,166,167,167,168,169,170,170,171,172,173,173,174,175,176,176,177,178,178,179,180,181,181,182,183,183,184,185,185,186,187,187,188,189,189,190,191,192,192,193,193,194,195,195,196,197,197,198,199,199,200,201,201,202,203,203,204,204,205,206,206,207,208,208,209,209,210,211,211,212,212,213,214,214,215,215,216,217,217,218,218,219,219,220,221,221,222,222,223,224,224,225,225,226,226,227,227,228,229,229,230,230,231,231,232,232,233,234,234,235,235,236,236,237,237,238,238,239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252,252,253,253,254,254,255,+};++/* a >= 2^(LIMB_BITS - 2). Return (s, r) with s=floor(sqrt(a)) and+ r=a-s^2. 0 <= r <= 2 * s */+static limb_t mp_sqrtrem1(limb_t *pr, limb_t a)+{+ limb_t s1, r1, s, r, q, u, num;+ + /* use a table for the 16 -> 8 bit sqrt */+ s1 = sqrt_table[(a >> (LIMB_BITS - 8)) - 64];+ r1 = (a >> (LIMB_BITS - 16)) - s1 * s1;+ if (r1 > 2 * s1) {+ r1 -= 2 * s1 + 1;+ s1++;+ }+ + /* one iteration to get a 32 -> 16 bit sqrt */+ num = (r1 << 8) | ((a >> (LIMB_BITS - 32 + 8)) & 0xff);+ q = num / (2 * s1); /* q <= 2^8 */+ u = num % (2 * s1);+ s = (s1 << 8) + q;+ r = (u << 8) | ((a >> (LIMB_BITS - 32)) & 0xff);+ r -= q * q;+ if ((slimb_t)r < 0) {+ s--;+ r += 2 * s + 1;+ }++#if LIMB_BITS == 64+ s1 = s;+ r1 = r;+ /* one more iteration for 64 -> 32 bit sqrt */+ num = (r1 << 16) | ((a >> (LIMB_BITS - 64 + 16)) & 0xffff);+ q = num / (2 * s1); /* q <= 2^16 */+ u = num % (2 * s1);+ s = (s1 << 16) + q;+ r = (u << 16) | ((a >> (LIMB_BITS - 64)) & 0xffff);+ r -= q * q;+ if ((slimb_t)r < 0) {+ s--;+ r += 2 * s + 1;+ }+#endif+ *pr = r;+ return s;+}++/* return floor(sqrt(a)) */+limb_t bf_isqrt(limb_t a)+{+ limb_t s, r;+ int k;++ if (a == 0)+ return 0;+ k = clz(a) & ~1;+ s = mp_sqrtrem1(&r, a << k);+ s >>= (k >> 1);+ return s;+}++static limb_t mp_sqrtrem2(limb_t *tabs, limb_t *taba)+{+ limb_t s1, r1, s, q, u, a0, a1;+ dlimb_t r, num;+ int l;++ a0 = taba[0];+ a1 = taba[1];+ s1 = mp_sqrtrem1(&r1, a1);+ l = LIMB_BITS / 2;+ num = ((dlimb_t)r1 << l) | (a0 >> l);+ q = num / (2 * s1);+ u = num % (2 * s1);+ s = (s1 << l) + q;+ r = ((dlimb_t)u << l) | (a0 & (((limb_t)1 << l) - 1));+ if (unlikely((q >> l) != 0))+ r -= (dlimb_t)1 << LIMB_BITS; /* special case when q=2^l */+ else+ r -= q * q;+ if ((slimb_t)(r >> LIMB_BITS) < 0) {+ s--;+ r += 2 * (dlimb_t)s + 1;+ }+ tabs[0] = s;+ taba[0] = r;+ return r >> LIMB_BITS;+}++//#define DEBUG_SQRTREM++/* tmp_buf must contain (n / 2 + 1 limbs). *prh contains the highest+ limb of the remainder. */+static int mp_sqrtrem_rec(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n,+ limb_t *tmp_buf, limb_t *prh)+{+ limb_t l, h, rh, ql, qh, c, i;+ + if (n == 1) {+ *prh = mp_sqrtrem2(tabs, taba);+ return 0;+ }+#ifdef DEBUG_SQRTREM+ mp_print_str("a", taba, 2 * n);+#endif+ l = n / 2;+ h = n - l;+ if (mp_sqrtrem_rec(s, tabs + l, taba + 2 * l, h, tmp_buf, &qh))+ return -1;+#ifdef DEBUG_SQRTREM+ mp_print_str("s1", tabs + l, h);+ mp_print_str_h("r1", taba + 2 * l, h, qh);+ mp_print_str_h("r2", taba + l, n, qh);+#endif+ + /* the remainder is in taba + 2 * l. Its high bit is in qh */+ if (qh) {+ mp_sub(taba + 2 * l, taba + 2 * l, tabs + l, h, 0);+ }+ /* instead of dividing by 2*s, divide by s (which is normalized)+ and update q and r */+ if (mp_divnorm(s, tmp_buf, taba + l, n, tabs + l, h))+ return -1;+ qh += tmp_buf[l];+ for(i = 0; i < l; i++)+ tabs[i] = tmp_buf[i];+ ql = mp_shr(tabs, tabs, l, 1, qh & 1);+ qh = qh >> 1; /* 0 or 1 */+ if (ql)+ rh = mp_add(taba + l, taba + l, tabs + l, h, 0);+ else+ rh = 0;+#ifdef DEBUG_SQRTREM+ mp_print_str_h("q", tabs, l, qh);+ mp_print_str_h("u", taba + l, h, rh);+#endif+ + mp_add_ui(tabs + l, qh, h);+#ifdef DEBUG_SQRTREM+ mp_print_str_h("s2", tabs, n, sh);+#endif+ + /* q = qh, tabs[l - 1 ... 0], r = taba[n - 1 ... l] */+ /* subtract q^2. if qh = 1 then q = B^l, so we can take shortcuts */+ if (qh) {+ c = qh;+ } else {+ if (mp_mul(s, taba + n, tabs, l, tabs, l))+ return -1;+ c = mp_sub(taba, taba, taba + n, 2 * l, 0);+ }+ rh -= mp_sub_ui(taba + 2 * l, c, n - 2 * l);+ if ((slimb_t)rh < 0) {+ mp_sub_ui(tabs, 1, n);+ rh += mp_add_mul1(taba, tabs, n, 2);+ rh += mp_add_ui(taba, 1, n);+ }+ *prh = rh;+ return 0;+}++/* 'taba' has 2*n limbs with n >= 1 and taba[2*n-1] >= 2 ^ (LIMB_BITS+ - 2). Return (s, r) with s=floor(sqrt(a)) and r=a-s^2. 0 <= r <= 2+ * s. tabs has n limbs. r is returned in the lower n limbs of+ taba. Its r[n] is the returned value of the function. */+/* Algorithm from the article "Karatsuba Square Root" by Paul Zimmermann and+ inspirated from its GMP implementation */+int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n)+{+ limb_t tmp_buf1[8];+ limb_t *tmp_buf;+ mp_size_t n2;+ int ret;+ n2 = n / 2 + 1;+ if (n2 <= countof(tmp_buf1)) {+ tmp_buf = tmp_buf1;+ } else {+ tmp_buf = bf_malloc(s, sizeof(limb_t) * n2);+ if (!tmp_buf)+ return -1;+ }+ ret = mp_sqrtrem_rec(s, tabs, taba, n, tmp_buf, taba + n);+ if (tmp_buf != tmp_buf1)+ bf_free(s, tmp_buf);+ return ret;+}++/* Integer square root with remainder. 'a' must be an integer. r =+ floor(sqrt(a)) and rem = a - r^2. BF_ST_INEXACT is set if the result+ is inexact. 'rem' can be NULL if the remainder is not needed. */+int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a)+{+ int ret;+ + if (a->len == 0) {+ if (a->expn == BF_EXP_NAN) {+ bf_set_nan(r);+ } else if (a->expn == BF_EXP_INF && a->sign) {+ goto invalid_op;+ } else {+ bf_set(r, a);+ }+ if (rem1)+ bf_set_ui(rem1, 0);+ ret = 0;+ } else if (a->sign) {+ invalid_op:+ bf_set_nan(r);+ if (rem1)+ bf_set_ui(rem1, 0);+ ret = BF_ST_INVALID_OP;+ } else {+ bf_t rem_s, *rem;+ + bf_sqrt(r, a, (a->expn + 1) / 2, BF_RNDZ);+ bf_rint(r, BF_RNDZ);+ /* see if the result is exact by computing the remainder */+ if (rem1) {+ rem = rem1;+ } else {+ rem = &rem_s;+ bf_init(r->ctx, rem);+ }+ /* XXX: could avoid recomputing the remainder */+ bf_mul(rem, r, r, BF_PREC_INF, BF_RNDZ);+ bf_neg(rem);+ bf_add(rem, rem, a, BF_PREC_INF, BF_RNDZ);+ if (bf_is_nan(rem)) {+ ret = BF_ST_MEM_ERROR;+ goto done;+ }+ if (rem->len != 0) {+ ret = BF_ST_INEXACT;+ } else {+ ret = 0;+ }+ done:+ if (!rem1)+ bf_delete(rem);+ }+ return ret;+}++int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)+{+ bf_context_t *s = a->ctx;+ int ret;++ assert(r != a);++ if (a->len == 0) {+ if (a->expn == BF_EXP_NAN) {+ bf_set_nan(r);+ } else if (a->expn == BF_EXP_INF && a->sign) {+ goto invalid_op;+ } else {+ bf_set(r, a);+ }+ ret = 0;+ } else if (a->sign) {+ invalid_op:+ bf_set_nan(r);+ ret = BF_ST_INVALID_OP;+ } else {+ limb_t *a1;+ slimb_t n, n1;+ limb_t res;+ + /* convert the mantissa to an integer with at least 2 *+ prec + 4 bits */+ n = (2 * (prec + 2) + 2 * LIMB_BITS - 1) / (2 * LIMB_BITS);+ if (bf_resize(r, n))+ goto fail;+ a1 = bf_malloc(s, sizeof(limb_t) * 2 * n);+ if (!a1)+ goto fail;+ n1 = bf_min(2 * n, a->len);+ memset(a1, 0, (2 * n - n1) * sizeof(limb_t));+ memcpy(a1 + 2 * n - n1, a->tab + a->len - n1, n1 * sizeof(limb_t));+ if (a->expn & 1) {+ res = mp_shr(a1, a1, 2 * n, 1, 0);+ } else {+ res = 0;+ }+ if (mp_sqrtrem(s, r->tab, a1, n)) {+ bf_free(s, a1);+ goto fail;+ }+ if (!res) {+ res = mp_scan_nz(a1, n + 1);+ }+ bf_free(s, a1);+ if (!res) {+ res = mp_scan_nz(a->tab, a->len - n1);+ }+ if (res != 0)+ r->tab[0] |= 1;+ r->sign = 0;+ r->expn = (a->expn + 1) >> 1;+ ret = bf_round(r, prec, flags);+ }+ return ret;+ fail:+ bf_set_nan(r);+ return BF_ST_MEM_ERROR;+}++static no_inline int bf_op2(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,+ bf_flags_t flags, bf_op2_func_t *func)+{+ bf_t tmp;+ int ret;+ + if (r == a || r == b) {+ bf_init(r->ctx, &tmp);+ ret = func(&tmp, a, b, prec, flags);+ bf_move(r, &tmp);+ } else {+ ret = func(r, a, b, prec, flags);+ }+ return ret;+}++int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,+ bf_flags_t flags)+{+ return bf_op2(r, a, b, prec, flags, __bf_add);+}++int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,+ bf_flags_t flags)+{+ return bf_op2(r, a, b, prec, flags, __bf_sub);+}++int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,+ bf_flags_t flags)+{+ return bf_op2(r, a, b, prec, flags, __bf_div);+}++int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec,+ bf_flags_t flags)+{+ bf_t b;+ int ret;+ bf_init(r->ctx, &b);+ ret = bf_set_ui(&b, b1);+ ret |= bf_mul(r, a, &b, prec, flags);+ bf_delete(&b);+ return ret;+}++int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec,+ bf_flags_t flags)+{+ bf_t b;+ int ret;+ bf_init(r->ctx, &b);+ ret = bf_set_si(&b, b1);+ ret |= bf_mul(r, a, &b, prec, flags);+ bf_delete(&b);+ return ret;+}++int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec,+ bf_flags_t flags)+{+ bf_t b;+ int ret;+ + bf_init(r->ctx, &b);+ ret = bf_set_si(&b, b1);+ ret |= bf_add(r, a, &b, prec, flags);+ bf_delete(&b);+ return ret;+}++static int bf_pow_ui(bf_t *r, const bf_t *a, limb_t b, limb_t prec,+ bf_flags_t flags)+{+ int ret, n_bits, i;+ + assert(r != a);+ if (b == 0)+ return bf_set_ui(r, 1);+ ret = bf_set(r, a);+ n_bits = LIMB_BITS - clz(b);+ for(i = n_bits - 2; i >= 0; i--) {+ ret |= bf_mul(r, r, r, prec, flags);+ if ((b >> i) & 1)+ ret |= bf_mul(r, r, a, prec, flags);+ }+ return ret;+}++static int bf_pow_ui_ui(bf_t *r, limb_t a1, limb_t b,+ limb_t prec, bf_flags_t flags)+{+ bf_t a;+ int ret;+ + if (a1 == 10 && b <= LIMB_DIGITS) {+ /* use precomputed powers. We do not round at this point+ because we expect the caller to do it */+ ret = bf_set_ui(r, mp_pow_dec[b]);+ } else {+ bf_init(r->ctx, &a);+ ret = bf_set_ui(&a, a1);+ ret |= bf_pow_ui(r, &a, b, prec, flags);+ bf_delete(&a);+ }+ return ret;+}++/* convert to integer (infinite precision) */+int bf_rint(bf_t *r, int rnd_mode)+{+ return bf_round(r, 0, rnd_mode | BF_FLAG_RADPNT_PREC);+}++/* logical operations */+#define BF_LOGIC_OR 0+#define BF_LOGIC_XOR 1+#define BF_LOGIC_AND 2++static inline limb_t bf_logic_op1(limb_t a, limb_t b, int op)+{+ switch(op) {+ case BF_LOGIC_OR:+ return a | b;+ case BF_LOGIC_XOR:+ return a ^ b;+ default:+ case BF_LOGIC_AND:+ return a & b;+ }+}++static int bf_logic_op(bf_t *r, const bf_t *a1, const bf_t *b1, int op)+{+ bf_t b1_s, a1_s, *a, *b;+ limb_t a_sign, b_sign, r_sign;+ slimb_t l, i, a_bit_offset, b_bit_offset;+ limb_t v1, v2, v1_mask, v2_mask, r_mask;+ int ret;+ + assert(r != a1 && r != b1);++ if (a1->expn <= 0)+ a_sign = 0; /* minus zero is considered as positive */+ else+ a_sign = a1->sign;++ if (b1->expn <= 0)+ b_sign = 0; /* minus zero is considered as positive */+ else+ b_sign = b1->sign;+ + if (a_sign) {+ a = &a1_s;+ bf_init(r->ctx, a);+ if (bf_add_si(a, a1, 1, BF_PREC_INF, BF_RNDZ)) {+ b = NULL;+ goto fail;+ }+ } else {+ a = (bf_t *)a1;+ }++ if (b_sign) {+ b = &b1_s;+ bf_init(r->ctx, b);+ if (bf_add_si(b, b1, 1, BF_PREC_INF, BF_RNDZ))+ goto fail;+ } else {+ b = (bf_t *)b1;+ }+ + r_sign = bf_logic_op1(a_sign, b_sign, op);+ if (op == BF_LOGIC_AND && r_sign == 0) {+ /* no need to compute extra zeros for and */+ if (a_sign == 0 && b_sign == 0)+ l = bf_min(a->expn, b->expn);+ else if (a_sign == 0)+ l = a->expn;+ else+ l = b->expn;+ } else {+ l = bf_max(a->expn, b->expn);+ }+ /* Note: a or b can be zero */+ l = (bf_max(l, 1) + LIMB_BITS - 1) / LIMB_BITS;+ if (bf_resize(r, l))+ goto fail;+ a_bit_offset = a->len * LIMB_BITS - a->expn;+ b_bit_offset = b->len * LIMB_BITS - b->expn;+ v1_mask = -a_sign;+ v2_mask = -b_sign;+ r_mask = -r_sign;+ for(i = 0; i < l; i++) {+ v1 = get_bits(a->tab, a->len, a_bit_offset + i * LIMB_BITS) ^ v1_mask;+ v2 = get_bits(b->tab, b->len, b_bit_offset + i * LIMB_BITS) ^ v2_mask;+ r->tab[i] = bf_logic_op1(v1, v2, op) ^ r_mask;+ }+ r->expn = l * LIMB_BITS;+ r->sign = r_sign;+ bf_normalize_and_round(r, BF_PREC_INF, BF_RNDZ); /* cannot fail */+ if (r_sign) {+ if (bf_add_si(r, r, -1, BF_PREC_INF, BF_RNDZ))+ goto fail;+ }+ ret = 0;+ done:+ if (a == &a1_s)+ bf_delete(a);+ if (b == &b1_s)+ bf_delete(b);+ return ret;+ fail:+ bf_set_nan(r);+ ret = BF_ST_MEM_ERROR;+ goto done;+}++/* 'a' and 'b' must be integers. Return 0 or BF_ST_MEM_ERROR. */+int bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b)+{+ return bf_logic_op(r, a, b, BF_LOGIC_OR);+}++/* 'a' and 'b' must be integers. Return 0 or BF_ST_MEM_ERROR. */+int bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b)+{+ return bf_logic_op(r, a, b, BF_LOGIC_XOR);+}++/* 'a' and 'b' must be integers. Return 0 or BF_ST_MEM_ERROR. */+int bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b)+{+ return bf_logic_op(r, a, b, BF_LOGIC_AND);+}++/* conversion between fixed size types */++typedef union {+ double d;+ uint64_t u;+} Float64Union;++int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode)+{+ Float64Union u;+ int e, ret;+ uint64_t m;+ + ret = 0;+ if (a->expn == BF_EXP_NAN) {+ u.u = 0x7ff8000000000000; /* quiet nan */+ } else {+ bf_t b_s, *b = &b_s;+ + bf_init(a->ctx, b);+ bf_set(b, a);+ if (bf_is_finite(b)) {+ ret = bf_round(b, 53, rnd_mode | BF_FLAG_SUBNORMAL | bf_set_exp_bits(11));+ }+ if (b->expn == BF_EXP_INF) {+ e = (1 << 11) - 1;+ m = 0;+ } else if (b->expn == BF_EXP_ZERO) {+ e = 0;+ m = 0;+ } else {+ e = b->expn + 1023 - 1;+#if LIMB_BITS == 32+ if (b->len == 2) {+ m = ((uint64_t)b->tab[1] << 32) | b->tab[0];+ } else {+ m = ((uint64_t)b->tab[0] << 32);+ }+#else+ m = b->tab[0];+#endif+ if (e <= 0) {+ /* subnormal */+ m = m >> (12 - e);+ e = 0;+ } else {+ m = (m << 1) >> 12;+ }+ }+ u.u = m | ((uint64_t)e << 52) | ((uint64_t)b->sign << 63);+ bf_delete(b);+ }+ *pres = u.d;+ return ret;+}++int bf_set_float64(bf_t *a, double d)+{+ Float64Union u;+ uint64_t m;+ int shift, e, sgn;+ + u.d = d;+ sgn = u.u >> 63;+ e = (u.u >> 52) & ((1 << 11) - 1);+ m = u.u & (((uint64_t)1 << 52) - 1);+ if (e == ((1 << 11) - 1)) {+ if (m != 0) {+ bf_set_nan(a);+ } else {+ bf_set_inf(a, sgn);+ }+ } else if (e == 0) {+ if (m == 0) {+ bf_set_zero(a, sgn);+ } else {+ /* subnormal number */+ m <<= 12;+ shift = clz64(m);+ m <<= shift;+ e = -shift;+ goto norm;+ }+ } else {+ m = (m << 11) | ((uint64_t)1 << 63);+ norm:+ a->expn = e - 1023 + 1;+#if LIMB_BITS == 32+ if (bf_resize(a, 2))+ goto fail;+ a->tab[0] = m;+ a->tab[1] = m >> 32;+#else+ if (bf_resize(a, 1))+ goto fail;+ a->tab[0] = m;+#endif+ a->sign = sgn;+ }+ return 0;+fail:+ bf_set_nan(a);+ return BF_ST_MEM_ERROR;+}++/* The rounding mode is always BF_RNDZ. Return BF_ST_INVALID_OP if there+ is an overflow and 0 otherwise. */+int bf_get_int32(int *pres, const bf_t *a, int flags)+{+ uint32_t v;+ int ret;+ if (a->expn >= BF_EXP_INF) {+ ret = BF_ST_INVALID_OP;+ if (flags & BF_GET_INT_MOD) {+ v = 0;+ } else if (a->expn == BF_EXP_INF) {+ v = (uint32_t)INT32_MAX + a->sign;+ } else {+ v = INT32_MAX;+ }+ } else if (a->expn <= 0) {+ v = 0;+ ret = 0;+ } else if (a->expn <= 31) {+ v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);+ if (a->sign)+ v = -v;+ ret = 0;+ } else if (!(flags & BF_GET_INT_MOD)) {+ ret = BF_ST_INVALID_OP;+ if (a->sign) {+ v = (uint32_t)INT32_MAX + 1;+ if (a->expn == 32 && + (a->tab[a->len - 1] >> (LIMB_BITS - 32)) == v) {+ ret = 0;+ }+ } else {+ v = INT32_MAX;+ }+ } else {+ v = get_bits(a->tab, a->len, a->len * LIMB_BITS - a->expn); + if (a->sign)+ v = -v;+ ret = 0;+ }+ *pres = v;+ return ret;+}++/* The rounding mode is always BF_RNDZ. Return BF_ST_INVALID_OP if there+ is an overflow and 0 otherwise. */+int bf_get_int64(int64_t *pres, const bf_t *a, int flags)+{+ uint64_t v;+ int ret;+ if (a->expn >= BF_EXP_INF) {+ ret = BF_ST_INVALID_OP;+ if (flags & BF_GET_INT_MOD) {+ v = 0;+ } else if (a->expn == BF_EXP_INF) {+ v = (uint64_t)INT64_MAX + a->sign;+ } else {+ v = INT64_MAX;+ }+ } else if (a->expn <= 0) {+ v = 0;+ ret = 0;+ } else if (a->expn <= 63) {+#if LIMB_BITS == 32+ if (a->expn <= 32)+ v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);+ else+ v = (((uint64_t)a->tab[a->len - 1] << 32) |+ get_limbz(a, a->len - 2)) >> (64 - a->expn);+#else+ v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);+#endif+ if (a->sign)+ v = -v;+ ret = 0;+ } else if (!(flags & BF_GET_INT_MOD)) {+ ret = BF_ST_INVALID_OP;+ if (a->sign) {+ uint64_t v1;+ v = (uint64_t)INT64_MAX + 1;+ if (a->expn == 64) {+ v1 = a->tab[a->len - 1];+#if LIMB_BITS == 32+ v1 = (v1 << 32) | get_limbz(a, a->len - 2);+#endif+ if (v1 == v)+ ret = 0;+ }+ } else {+ v = INT64_MAX;+ }+ } else {+ slimb_t bit_pos = a->len * LIMB_BITS - a->expn;+ v = get_bits(a->tab, a->len, bit_pos); +#if LIMB_BITS == 32+ v |= (uint64_t)get_bits(a->tab, a->len, bit_pos + 32) << 32;+#endif+ if (a->sign)+ v = -v;+ ret = 0;+ }+ *pres = v;+ return ret;+}++/* The rounding mode is always BF_RNDZ. Return BF_ST_INVALID_OP if there+ is an overflow and 0 otherwise. */+int bf_get_uint64(uint64_t *pres, const bf_t *a)+{+ uint64_t v;+ int ret;+ if (a->expn == BF_EXP_NAN) {+ goto overflow;+ } else if (a->expn <= 0) {+ v = 0;+ ret = 0;+ } else if (a->sign) {+ v = 0;+ ret = BF_ST_INVALID_OP;+ } else if (a->expn <= 64) {+#if LIMB_BITS == 32+ if (a->expn <= 32)+ v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);+ else+ v = (((uint64_t)a->tab[a->len - 1] << 32) |+ get_limbz(a, a->len - 2)) >> (64 - a->expn);+#else+ v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);+#endif+ ret = 0;+ } else {+ overflow:+ v = UINT64_MAX;+ ret = BF_ST_INVALID_OP;+ }+ *pres = v;+ return ret;+}++/* base conversion from radix */++static const uint8_t digits_per_limb_table[BF_RADIX_MAX - 1] = {+#if LIMB_BITS == 32+32,20,16,13,12,11,10,10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,+#else+64,40,32,27,24,22,21,20,19,18,17,17,16,16,16,15,15,15,14,14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12,+#endif+};++static limb_t get_limb_radix(int radix)+{+ int i, k;+ limb_t radixl;+ + k = digits_per_limb_table[radix - 2];+ radixl = radix;+ for(i = 1; i < k; i++)+ radixl *= radix;+ return radixl;+}++/* return != 0 if error */+static int bf_integer_from_radix_rec(bf_t *r, const limb_t *tab,+ limb_t n, int level, limb_t n0,+ limb_t radix, bf_t *pow_tab)+{+ int ret;+ if (n == 1) {+ ret = bf_set_ui(r, tab[0]);+ } else {+ bf_t T_s, *T = &T_s, *B;+ limb_t n1, n2;+ + n2 = (((n0 * 2) >> (level + 1)) + 1) / 2;+ n1 = n - n2;+ // printf("level=%d n0=%ld n1=%ld n2=%ld\n", level, n0, n1, n2);+ B = &pow_tab[level];+ if (B->len == 0) {+ ret = bf_pow_ui_ui(B, radix, n2, BF_PREC_INF, BF_RNDZ);+ if (ret)+ return ret;+ }+ ret = bf_integer_from_radix_rec(r, tab + n2, n1, level + 1, n0,+ radix, pow_tab);+ if (ret)+ return ret;+ ret = bf_mul(r, r, B, BF_PREC_INF, BF_RNDZ);+ if (ret)+ return ret;+ bf_init(r->ctx, T);+ ret = bf_integer_from_radix_rec(T, tab, n2, level + 1, n0,+ radix, pow_tab);+ if (!ret)+ ret = bf_add(r, r, T, BF_PREC_INF, BF_RNDZ);+ bf_delete(T);+ }+ return ret;+ // bf_print_str(" r=", r);+}++/* return 0 if OK != 0 if memory error */+static int bf_integer_from_radix(bf_t *r, const limb_t *tab,+ limb_t n, limb_t radix)+{+ bf_context_t *s = r->ctx;+ int pow_tab_len, i, ret;+ limb_t radixl;+ bf_t *pow_tab;+ + radixl = get_limb_radix(radix);+ pow_tab_len = ceil_log2(n) + 2; /* XXX: check */+ pow_tab = bf_malloc(s, sizeof(pow_tab[0]) * pow_tab_len);+ if (!pow_tab)+ return -1;+ for(i = 0; i < pow_tab_len; i++)+ bf_init(r->ctx, &pow_tab[i]);+ ret = bf_integer_from_radix_rec(r, tab, n, 0, n, radixl, pow_tab);+ for(i = 0; i < pow_tab_len; i++) {+ bf_delete(&pow_tab[i]);+ }+ bf_free(s, pow_tab);+ return ret;+}++/* compute and round T * radix^expn. */+int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,+ slimb_t expn, limb_t prec, bf_flags_t flags)+{+ int ret, expn_sign, overflow;+ slimb_t e, extra_bits, prec1, ziv_extra_bits;+ bf_t B_s, *B = &B_s;++ if (T->len == 0) {+ return bf_set(r, T);+ } else if (expn == 0) {+ ret = bf_set(r, T);+ ret |= bf_round(r, prec, flags);+ return ret;+ }++ e = expn;+ expn_sign = 0;+ if (e < 0) {+ e = -e;+ expn_sign = 1;+ }+ bf_init(r->ctx, B);+ if (prec == BF_PREC_INF) {+ /* infinite precision: only used if the result is known to be exact */+ ret = bf_pow_ui_ui(B, radix, e, BF_PREC_INF, BF_RNDN);+ if (expn_sign) {+ ret |= bf_div(r, T, B, T->len * LIMB_BITS, BF_RNDN);+ } else {+ ret |= bf_mul(r, T, B, BF_PREC_INF, BF_RNDN);+ }+ } else {+ ziv_extra_bits = 16;+ for(;;) {+ prec1 = prec + ziv_extra_bits;+ /* XXX: correct overflow/underflow handling */+ /* XXX: rigorous error analysis needed */+ extra_bits = ceil_log2(e) * 2 + 1;+ ret = bf_pow_ui_ui(B, radix, e, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);+ overflow = !bf_is_finite(B);+ /* XXX: if bf_pow_ui_ui returns an exact result, can stop+ after the next operation */+ if (expn_sign)+ ret |= bf_div(r, T, B, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);+ else+ ret |= bf_mul(r, T, B, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);+ if (ret & BF_ST_MEM_ERROR)+ break;+ if ((ret & BF_ST_INEXACT) &&+ !bf_can_round(r, prec, flags & BF_RND_MASK, prec1) &&+ !overflow) {+ /* and more precision and retry */+ ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);+ } else {+ /* XXX: need to use __bf_round() to pass the inexact+ flag for the subnormal case */+ ret = bf_round(r, prec, flags) | (ret & BF_ST_INEXACT);+ break;+ }+ }+ }+ bf_delete(B);+ return ret;+}++static inline int to_digit(int c)+{+ if (c >= '0' && c <= '9')+ return c - '0';+ else if (c >= 'A' && c <= 'Z')+ return c - 'A' + 10;+ else if (c >= 'a' && c <= 'z')+ return c - 'a' + 10;+ else+ return 36;+}++/* add a limb at 'pos' and decrement pos. new space is created if+ needed. Return 0 if OK, -1 if memory error */+static int bf_add_limb(bf_t *a, slimb_t *ppos, limb_t v)+{+ slimb_t pos;+ pos = *ppos;+ if (unlikely(pos < 0)) {+ limb_t new_size, d, *new_tab;+ new_size = bf_max(a->len + 1, a->len * 3 / 2);+ new_tab = bf_realloc(a->ctx, a->tab, sizeof(limb_t) * new_size);+ if (!new_tab)+ return -1;+ a->tab = new_tab;+ d = new_size - a->len;+ memmove(a->tab + d, a->tab, a->len * sizeof(limb_t));+ a->len = new_size;+ pos += d;+ }+ a->tab[pos--] = v;+ *ppos = pos;+ return 0;+}++static int bf_tolower(int c)+{+ if (c >= 'A' && c <= 'Z')+ c = c - 'A' + 'a';+ return c;+}++static int strcasestart(const char *str, const char *val, const char **ptr)+{+ const char *p, *q;+ p = str;+ q = val;+ while (*q != '\0') {+ if (bf_tolower(*p) != *q)+ return 0;+ p++;+ q++;+ }+ if (ptr)+ *ptr = p;+ return 1;+}++static int bf_atof_internal(bf_t *r, slimb_t *pexponent,+ const char *str, const char **pnext, int radix,+ limb_t prec, bf_flags_t flags, BOOL is_dec)+{+ const char *p, *p_start;+ int is_neg, radix_bits, exp_is_neg, ret, digits_per_limb, shift;+ limb_t cur_limb;+ slimb_t pos, expn, int_len, digit_count;+ BOOL has_decpt, is_bin_exp;+ bf_t a_s, *a;+ + *pexponent = 0;+ p = str;+ if (!(flags & BF_ATOF_NO_NAN_INF) && radix <= 16 &&+ strcasestart(p, "nan", &p)) {+ bf_set_nan(r);+ ret = 0;+ goto done;+ }+ is_neg = 0;+ + if (p[0] == '+') {+ p++;+ p_start = p;+ } else if (p[0] == '-') {+ is_neg = 1;+ p++;+ p_start = p;+ } else {+ p_start = p;+ }+ if (p[0] == '0') {+ if ((p[1] == 'x' || p[1] == 'X') &&+ (radix == 0 || radix == 16) &&+ !(flags & BF_ATOF_NO_HEX)) {+ radix = 16;+ p += 2;+ } else if ((p[1] == 'o' || p[1] == 'O') &&+ radix == 0 && (flags & BF_ATOF_BIN_OCT)) {+ p += 2;+ radix = 8;+ } else if ((p[1] == 'b' || p[1] == 'B') &&+ radix == 0 && (flags & BF_ATOF_BIN_OCT)) {+ p += 2;+ radix = 2;+ } else {+ goto no_prefix;+ }+ /* there must be a digit after the prefix */+ if (to_digit((uint8_t)*p) >= radix) {+ bf_set_nan(r);+ ret = 0;+ goto done;+ }+ no_prefix: ;+ } else {+ if (!(flags & BF_ATOF_NO_NAN_INF) && radix <= 16 &&+ strcasestart(p, "inf", &p)) {+ bf_set_inf(r, is_neg);+ ret = 0;+ goto done;+ }+ }+ + if (radix == 0)+ radix = 10;+ if (is_dec) {+ assert(radix == 10);+ radix_bits = 0;+ a = r;+ } else if ((radix & (radix - 1)) != 0) {+ radix_bits = 0; /* base is not a power of two */+ a = &a_s;+ bf_init(r->ctx, a);+ } else {+ radix_bits = ceil_log2(radix);+ a = r;+ }++ /* skip leading zeros */+ /* XXX: could also skip zeros after the decimal point */+ while (*p == '0')+ p++;++ if (radix_bits) {+ shift = digits_per_limb = LIMB_BITS;+ } else {+ radix_bits = 0;+ shift = digits_per_limb = digits_per_limb_table[radix - 2];+ }+ cur_limb = 0;+ bf_resize(a, 1);+ pos = 0;+ has_decpt = FALSE;+ int_len = digit_count = 0;+ for(;;) {+ limb_t c;+ if (*p == '.' && (p > p_start || to_digit(p[1]) < radix)) {+ if (has_decpt)+ break;+ has_decpt = TRUE;+ int_len = digit_count;+ p++;+ }+ c = to_digit(*p);+ if (c >= radix)+ break;+ digit_count++;+ p++;+ if (radix_bits) {+ shift -= radix_bits;+ if (shift <= 0) {+ cur_limb |= c >> (-shift);+ if (bf_add_limb(a, &pos, cur_limb))+ goto mem_error;+ if (shift < 0)+ cur_limb = c << (LIMB_BITS + shift);+ else+ cur_limb = 0;+ shift += LIMB_BITS;+ } else {+ cur_limb |= c << shift;+ }+ } else {+ cur_limb = cur_limb * radix + c;+ shift--;+ if (shift == 0) {+ if (bf_add_limb(a, &pos, cur_limb))+ goto mem_error;+ shift = digits_per_limb;+ cur_limb = 0;+ }+ }+ }+ if (!has_decpt)+ int_len = digit_count;++ /* add the last limb and pad with zeros */+ if (shift != digits_per_limb) {+ if (radix_bits == 0) {+ while (shift != 0) {+ cur_limb *= radix;+ shift--;+ }+ }+ if (bf_add_limb(a, &pos, cur_limb)) {+ mem_error:+ ret = BF_ST_MEM_ERROR;+ if (!radix_bits)+ bf_delete(a);+ bf_set_nan(r);+ goto done;+ }+ }+ + /* reset the next limbs to zero (we prefer to reallocate in the+ renormalization) */+ memset(a->tab, 0, (pos + 1) * sizeof(limb_t));++ if (p == p_start) {+ ret = 0;+ if (!radix_bits)+ bf_delete(a);+ bf_set_nan(r);+ goto done;+ }++ /* parse the exponent, if any */+ expn = 0;+ is_bin_exp = FALSE;+ if (((radix == 10 && (*p == 'e' || *p == 'E')) ||+ (radix != 10 && (*p == '@' ||+ (radix_bits && (*p == 'p' || *p == 'P'))))) &&+ p > p_start) {+ is_bin_exp = (*p == 'p' || *p == 'P');+ p++;+ exp_is_neg = 0;+ if (*p == '+') {+ p++;+ } else if (*p == '-') {+ exp_is_neg = 1;+ p++;+ }+ for(;;) {+ int c;+ c = to_digit(*p);+ if (c >= 10)+ break;+ if (unlikely(expn > ((BF_RAW_EXP_MAX - 2 - 9) / 10))) {+ /* exponent overflow */+ if (exp_is_neg) {+ bf_set_zero(r, is_neg);+ ret = BF_ST_UNDERFLOW | BF_ST_INEXACT;+ } else {+ bf_set_inf(r, is_neg);+ ret = BF_ST_OVERFLOW | BF_ST_INEXACT;+ }+ goto done;+ }+ p++;+ expn = expn * 10 + c;+ }+ if (exp_is_neg)+ expn = -expn;+ }+ if (is_dec) {+ a->expn = expn + int_len;+ a->sign = is_neg;+ ret = bfdec_normalize_and_round((bfdec_t *)a, prec, flags);+ } else if (radix_bits) {+ /* XXX: may overflow */+ if (!is_bin_exp)+ expn *= radix_bits; + a->expn = expn + (int_len * radix_bits);+ a->sign = is_neg;+ ret = bf_normalize_and_round(a, prec, flags);+ } else {+ limb_t l;+ pos++;+ l = a->len - pos; /* number of limbs */+ if (l == 0) {+ bf_set_zero(r, is_neg);+ ret = 0;+ } else {+ bf_t T_s, *T = &T_s;++ expn -= l * digits_per_limb - int_len;+ bf_init(r->ctx, T);+ if (bf_integer_from_radix(T, a->tab + pos, l, radix)) {+ bf_set_nan(r);+ ret = BF_ST_MEM_ERROR;+ } else {+ T->sign = is_neg;+ if (flags & BF_ATOF_EXPONENT) {+ /* return the exponent */+ *pexponent = expn;+ ret = bf_set(r, T);+ } else {+ ret = bf_mul_pow_radix(r, T, radix, expn, prec, flags);+ }+ }+ bf_delete(T);+ }+ bf_delete(a);+ }+ done:+ if (pnext)+ *pnext = p;+ return ret;+}++/* + Return (status, n, exp). 'status' is the floating point status. 'n'+ is the parsed number. ++ If (flags & BF_ATOF_EXPONENT) and if the radix is not a power of+ two, the parsed number is equal to r *+ (*pexponent)^radix. Otherwise *pexponent = 0.+*/+int bf_atof2(bf_t *r, slimb_t *pexponent,+ const char *str, const char **pnext, int radix,+ limb_t prec, bf_flags_t flags)+{+ return bf_atof_internal(r, pexponent, str, pnext, radix, prec, flags,+ FALSE);+}++int bf_atof(bf_t *r, const char *str, const char **pnext, int radix,+ limb_t prec, bf_flags_t flags)+{+ slimb_t dummy_exp;+ return bf_atof_internal(r, &dummy_exp, str, pnext, radix, prec, flags, FALSE);+}++/* base conversion to radix */++#if LIMB_BITS == 64+#define RADIXL_10 UINT64_C(10000000000000000000)+#else+#define RADIXL_10 UINT64_C(1000000000)+#endif++static const uint32_t inv_log2_radix[BF_RADIX_MAX - 1][LIMB_BITS / 32 + 1] = {+#if LIMB_BITS == 32+{ 0x80000000, 0x00000000,},+{ 0x50c24e60, 0xd4d4f4a7,},+{ 0x40000000, 0x00000000,},+{ 0x372068d2, 0x0a1ee5ca,},+{ 0x3184648d, 0xb8153e7a,},+{ 0x2d983275, 0x9d5369c4,},+{ 0x2aaaaaaa, 0xaaaaaaab,},+{ 0x28612730, 0x6a6a7a54,},+{ 0x268826a1, 0x3ef3fde6,},+{ 0x25001383, 0xbac8a744,},+{ 0x23b46706, 0x82c0c709,},+{ 0x229729f1, 0xb2c83ded,},+{ 0x219e7ffd, 0xa5ad572b,},+{ 0x20c33b88, 0xda7c29ab,},+{ 0x20000000, 0x00000000,},+{ 0x1f50b57e, 0xac5884b3,},+{ 0x1eb22cc6, 0x8aa6e26f,},+{ 0x1e21e118, 0x0c5daab2,},+{ 0x1d9dcd21, 0x439834e4,},+{ 0x1d244c78, 0x367a0d65,},+{ 0x1cb40589, 0xac173e0c,},+{ 0x1c4bd95b, 0xa8d72b0d,},+{ 0x1bead768, 0x98f8ce4c,},+{ 0x1b903469, 0x050f72e5,},+{ 0x1b3b433f, 0x2eb06f15,},+{ 0x1aeb6f75, 0x9c46fc38,},+{ 0x1aa038eb, 0x0e3bfd17,},+{ 0x1a593062, 0xb38d8c56,},+{ 0x1a15f4c3, 0x2b95a2e6,},+{ 0x19d630dc, 0xcc7ddef9,},+{ 0x19999999, 0x9999999a,},+{ 0x195fec80, 0x8a609431,},+{ 0x1928ee7b, 0x0b4f22f9,},+{ 0x18f46acf, 0x8c06e318,},+{ 0x18c23246, 0xdc0a9f3d,},+#else+{ 0x80000000, 0x00000000, 0x00000000,},+{ 0x50c24e60, 0xd4d4f4a7, 0x021f57bc,},+{ 0x40000000, 0x00000000, 0x00000000,},+{ 0x372068d2, 0x0a1ee5ca, 0x19ea911b,},+{ 0x3184648d, 0xb8153e7a, 0x7fc2d2e1,},+{ 0x2d983275, 0x9d5369c4, 0x4dec1661,},+{ 0x2aaaaaaa, 0xaaaaaaaa, 0xaaaaaaab,},+{ 0x28612730, 0x6a6a7a53, 0x810fabde,},+{ 0x268826a1, 0x3ef3fde6, 0x23e2566b,},+{ 0x25001383, 0xbac8a744, 0x385a3349,},+{ 0x23b46706, 0x82c0c709, 0x3f891718,},+{ 0x229729f1, 0xb2c83ded, 0x15fba800,},+{ 0x219e7ffd, 0xa5ad572a, 0xe169744b,},+{ 0x20c33b88, 0xda7c29aa, 0x9bddee52,},+{ 0x20000000, 0x00000000, 0x00000000,},+{ 0x1f50b57e, 0xac5884b3, 0x70e28eee,},+{ 0x1eb22cc6, 0x8aa6e26f, 0x06d1a2a2,},+{ 0x1e21e118, 0x0c5daab1, 0x81b4f4bf,},+{ 0x1d9dcd21, 0x439834e3, 0x81667575,},+{ 0x1d244c78, 0x367a0d64, 0xc8204d6d,},+{ 0x1cb40589, 0xac173e0c, 0x3b7b16ba,},+{ 0x1c4bd95b, 0xa8d72b0d, 0x5879f25a,},+{ 0x1bead768, 0x98f8ce4c, 0x66cc2858,},+{ 0x1b903469, 0x050f72e5, 0x0cf5488e,},+{ 0x1b3b433f, 0x2eb06f14, 0x8c89719c,},+{ 0x1aeb6f75, 0x9c46fc37, 0xab5fc7e9,},+{ 0x1aa038eb, 0x0e3bfd17, 0x1bd62080,},+{ 0x1a593062, 0xb38d8c56, 0x7998ab45,},+{ 0x1a15f4c3, 0x2b95a2e6, 0x46aed6a0,},+{ 0x19d630dc, 0xcc7ddef9, 0x5aadd61b,},+{ 0x19999999, 0x99999999, 0x9999999a,},+{ 0x195fec80, 0x8a609430, 0xe1106014,},+{ 0x1928ee7b, 0x0b4f22f9, 0x5f69791d,},+{ 0x18f46acf, 0x8c06e318, 0x4d2aeb2c,},+{ 0x18c23246, 0xdc0a9f3d, 0x3fe16970,},+#endif+};++static const limb_t log2_radix[BF_RADIX_MAX - 1] = {+#if LIMB_BITS == 32+0x20000000,+0x32b80347,+0x40000000,+0x4a4d3c26,+0x52b80347,+0x59d5d9fd,+0x60000000,+0x6570068e,+0x6a4d3c26,+0x6eb3a9f0,+0x72b80347,+0x766a008e,+0x79d5d9fd,+0x7d053f6d,+0x80000000,+0x82cc7edf,+0x8570068e,+0x87ef05ae,+0x8a4d3c26,+0x8c8ddd45,+0x8eb3a9f0,+0x90c10501,+0x92b80347,+0x949a784c,+0x966a008e,+0x982809d6,+0x99d5d9fd,+0x9b74948f,+0x9d053f6d,+0x9e88c6b3,+0xa0000000,+0xa16bad37,+0xa2cc7edf,+0xa4231623,+0xa570068e,+#else+0x2000000000000000,+0x32b803473f7ad0f4,+0x4000000000000000,+0x4a4d3c25e68dc57f,+0x52b803473f7ad0f4,+0x59d5d9fd5010b366,+0x6000000000000000,+0x6570068e7ef5a1e8,+0x6a4d3c25e68dc57f,+0x6eb3a9f01975077f,+0x72b803473f7ad0f4,+0x766a008e4788cbcd,+0x79d5d9fd5010b366,+0x7d053f6d26089673,+0x8000000000000000,+0x82cc7edf592262d0,+0x8570068e7ef5a1e8,+0x87ef05ae409a0289,+0x8a4d3c25e68dc57f,+0x8c8ddd448f8b845a,+0x8eb3a9f01975077f,+0x90c10500d63aa659,+0x92b803473f7ad0f4,+0x949a784bcd1b8afe,+0x966a008e4788cbcd,+0x982809d5be7072dc,+0x99d5d9fd5010b366,+0x9b74948f5532da4b,+0x9d053f6d26089673,+0x9e88c6b3626a72aa,+0xa000000000000000,+0xa16bad3758efd873,+0xa2cc7edf592262d0,+0xa4231623369e78e6,+0xa570068e7ef5a1e8,+#endif+};++/* compute floor(a*b) or ceil(a*b) with b = log2(radix) or+ b=1/log2(radix). For is_inv = 0, strict accuracy is not guaranteed+ when radix is not a power of two. */+slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv,+ int is_ceil1)+{+ int is_neg;+ limb_t a;+ BOOL is_ceil;++ is_ceil = is_ceil1;+ a = a1;+ if (a1 < 0) {+ a = -a;+ is_neg = 1;+ } else {+ is_neg = 0;+ }+ is_ceil ^= is_neg;+ if ((radix & (radix - 1)) == 0) {+ int radix_bits;+ /* radix is a power of two */+ radix_bits = ceil_log2(radix);+ if (is_inv) {+ if (is_ceil)+ a += radix_bits - 1;+ a = a / radix_bits;+ } else {+ a = a * radix_bits;+ }+ } else {+ const uint32_t *tab;+ limb_t b0, b1;+ dlimb_t t;+ + if (is_inv) {+ tab = inv_log2_radix[radix - 2];+#if LIMB_BITS == 32+ b1 = tab[0];+ b0 = tab[1];+#else+ b1 = ((limb_t)tab[0] << 32) | tab[1];+ b0 = (limb_t)tab[2] << 32;+#endif+ t = (dlimb_t)b0 * (dlimb_t)a;+ t = (dlimb_t)b1 * (dlimb_t)a + (t >> LIMB_BITS);+ a = t >> (LIMB_BITS - 1);+ } else {+ b0 = log2_radix[radix - 2];+ t = (dlimb_t)b0 * (dlimb_t)a;+ a = t >> (LIMB_BITS - 3);+ }+ /* a = floor(result) and 'result' cannot be an integer */+ a += is_ceil;+ }+ if (is_neg)+ a = -a;+ return a;+}++/* 'n' is the number of output limbs */+static int bf_integer_to_radix_rec(bf_t *pow_tab,+ limb_t *out, const bf_t *a, limb_t n,+ int level, limb_t n0, limb_t radixl,+ unsigned int radixl_bits)+{+ limb_t n1, n2, q_prec;+ int ret;+ + assert(n >= 1);+ if (n == 1) {+ out[0] = get_bits(a->tab, a->len, a->len * LIMB_BITS - a->expn);+ } else if (n == 2) {+ dlimb_t t;+ slimb_t pos;+ pos = a->len * LIMB_BITS - a->expn;+ t = ((dlimb_t)get_bits(a->tab, a->len, pos + LIMB_BITS) << LIMB_BITS) |+ get_bits(a->tab, a->len, pos);+ if (likely(radixl == RADIXL_10)) {+ /* use division by a constant when possible */+ out[0] = t % RADIXL_10;+ out[1] = t / RADIXL_10;+ } else {+ out[0] = t % radixl;+ out[1] = t / radixl;+ }+ } else {+ bf_t Q, R, *B, *B_inv;+ int q_add;+ bf_init(a->ctx, &Q);+ bf_init(a->ctx, &R);+ n2 = (((n0 * 2) >> (level + 1)) + 1) / 2;+ n1 = n - n2;+ B = &pow_tab[2 * level];+ B_inv = &pow_tab[2 * level + 1];+ ret = 0;+ if (B->len == 0) {+ /* compute BASE^n2 */+ ret |= bf_pow_ui_ui(B, radixl, n2, BF_PREC_INF, BF_RNDZ);+ /* we use enough bits for the maximum possible 'n1' value,+ i.e. n2 + 1 */+ ret |= bf_set_ui(&R, 1);+ ret |= bf_div(B_inv, &R, B, (n2 + 1) * radixl_bits + 2, BF_RNDN);+ }+ // printf("%d: n1=% " PRId64 " n2=%" PRId64 "\n", level, n1, n2);+ q_prec = n1 * radixl_bits;+ ret |= bf_mul(&Q, a, B_inv, q_prec, BF_RNDN);+ ret |= bf_rint(&Q, BF_RNDZ);+ + ret |= bf_mul(&R, &Q, B, BF_PREC_INF, BF_RNDZ);+ ret |= bf_sub(&R, a, &R, BF_PREC_INF, BF_RNDZ);++ if (ret & BF_ST_MEM_ERROR)+ goto fail;+ /* adjust if necessary */+ q_add = 0;+ while (R.sign && R.len != 0) {+ if (bf_add(&R, &R, B, BF_PREC_INF, BF_RNDZ))+ goto fail;+ q_add--;+ }+ while (bf_cmpu(&R, B) >= 0) {+ if (bf_sub(&R, &R, B, BF_PREC_INF, BF_RNDZ))+ goto fail;+ q_add++;+ }+ if (q_add != 0) {+ if (bf_add_si(&Q, &Q, q_add, BF_PREC_INF, BF_RNDZ))+ goto fail;+ }+ if (bf_integer_to_radix_rec(pow_tab, out + n2, &Q, n1, level + 1, n0,+ radixl, radixl_bits))+ goto fail;+ if (bf_integer_to_radix_rec(pow_tab, out, &R, n2, level + 1, n0,+ radixl, radixl_bits)) {+ fail:+ bf_delete(&Q);+ bf_delete(&R);+ return -1;+ }+ bf_delete(&Q);+ bf_delete(&R);+ }+ return 0;+}++/* return 0 if OK != 0 if memory error */+static int bf_integer_to_radix(bf_t *r, const bf_t *a, limb_t radixl)+{+ bf_context_t *s = r->ctx;+ limb_t r_len;+ bf_t *pow_tab;+ int i, pow_tab_len, ret;+ + r_len = r->len;+ pow_tab_len = (ceil_log2(r_len) + 2) * 2; /* XXX: check */+ pow_tab = bf_malloc(s, sizeof(pow_tab[0]) * pow_tab_len);+ if (!pow_tab)+ return -1;+ for(i = 0; i < pow_tab_len; i++)+ bf_init(r->ctx, &pow_tab[i]);++ ret = bf_integer_to_radix_rec(pow_tab, r->tab, a, r_len, 0, r_len, radixl,+ ceil_log2(radixl));++ for(i = 0; i < pow_tab_len; i++) {+ bf_delete(&pow_tab[i]);+ }+ bf_free(s, pow_tab);+ return ret;+}++/* a must be >= 0. 'P' is the wanted number of digits in radix+ 'radix'. 'r' is the mantissa represented as an integer. *pE+ contains the exponent. Return != 0 if memory error. */+static int bf_convert_to_radix(bf_t *r, slimb_t *pE,+ const bf_t *a, int radix,+ limb_t P, bf_rnd_t rnd_mode,+ BOOL is_fixed_exponent)+{+ slimb_t E, e, prec, extra_bits, ziv_extra_bits, prec0;+ bf_t B_s, *B = &B_s;+ int e_sign, ret, res;+ + if (a->len == 0) {+ /* zero case */+ *pE = 0;+ return bf_set(r, a);+ }++ if (is_fixed_exponent) {+ E = *pE;+ } else {+ /* compute the new exponent */+ E = 1 + bf_mul_log2_radix(a->expn - 1, radix, TRUE, FALSE);+ }+ // bf_print_str("a", a);+ // printf("E=%ld P=%ld radix=%d\n", E, P, radix);+ + for(;;) {+ e = P - E;+ e_sign = 0;+ if (e < 0) {+ e = -e;+ e_sign = 1;+ }+ /* Note: precision for log2(radix) is not critical here */+ prec0 = bf_mul_log2_radix(P, radix, FALSE, TRUE);+ ziv_extra_bits = 16;+ for(;;) {+ prec = prec0 + ziv_extra_bits;+ /* XXX: rigorous error analysis needed */+ extra_bits = ceil_log2(e) * 2 + 1;+ ret = bf_pow_ui_ui(r, radix, e, prec + extra_bits,+ BF_RNDN | BF_FLAG_EXT_EXP);+ if (!e_sign)+ ret |= bf_mul(r, r, a, prec + extra_bits,+ BF_RNDN | BF_FLAG_EXT_EXP);+ else+ ret |= bf_div(r, a, r, prec + extra_bits,+ BF_RNDN | BF_FLAG_EXT_EXP);+ if (ret & BF_ST_MEM_ERROR)+ return BF_ST_MEM_ERROR;+ /* if the result is not exact, check that it can be safely+ rounded to an integer */+ if ((ret & BF_ST_INEXACT) &&+ !bf_can_round(r, r->expn, rnd_mode, prec)) {+ /* and more precision and retry */+ ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);+ continue;+ } else {+ ret = bf_rint(r, rnd_mode);+ if (ret & BF_ST_MEM_ERROR)+ return BF_ST_MEM_ERROR;+ break;+ }+ }+ if (is_fixed_exponent)+ break;+ /* check that the result is < B^P */+ /* XXX: do a fast approximate test first ? */+ bf_init(r->ctx, B);+ ret = bf_pow_ui_ui(B, radix, P, BF_PREC_INF, BF_RNDZ);+ if (ret) {+ bf_delete(B);+ return ret;+ }+ res = bf_cmpu(r, B);+ bf_delete(B);+ if (res < 0)+ break;+ /* try a larger exponent */+ E++;+ }+ *pE = E;+ return 0;+}++static void limb_to_a(char *buf, limb_t n, unsigned int radix, int len)+{+ int digit, i;++ if (radix == 10) {+ /* specific case with constant divisor */+ for(i = len - 1; i >= 0; i--) {+ digit = (limb_t)n % 10;+ n = (limb_t)n / 10;+ buf[i] = digit + '0';+ }+ } else {+ for(i = len - 1; i >= 0; i--) {+ digit = (limb_t)n % radix;+ n = (limb_t)n / radix;+ if (digit < 10)+ digit += '0';+ else+ digit += 'a' - 10;+ buf[i] = digit;+ }+ }+}++/* for power of 2 radixes */+static void limb_to_a2(char *buf, limb_t n, unsigned int radix_bits, int len)+{+ int digit, i;+ unsigned int mask;++ mask = (1 << radix_bits) - 1;+ for(i = len - 1; i >= 0; i--) {+ digit = n & mask;+ n >>= radix_bits;+ if (digit < 10)+ digit += '0';+ else+ digit += 'a' - 10;+ buf[i] = digit;+ }+}++/* 'a' must be an integer if the is_dec = FALSE or if the radix is not+ a power of two. A dot is added before the 'dot_pos' digit. dot_pos+ = n_digits does not display the dot. 0 <= dot_pos <=+ n_digits. n_digits >= 1. */+static void output_digits(DynBuf *s, const bf_t *a1, int radix, limb_t n_digits,+ limb_t dot_pos, BOOL is_dec)+{+ limb_t i, v, l;+ slimb_t pos, pos_incr;+ int digits_per_limb, buf_pos, radix_bits, first_buf_pos;+ char buf[65];+ bf_t a_s, *a;++ if (is_dec) {+ digits_per_limb = LIMB_DIGITS;+ a = (bf_t *)a1;+ radix_bits = 0;+ pos = a->len;+ pos_incr = 1;+ first_buf_pos = 0;+ } else if ((radix & (radix - 1)) == 0) {+ a = (bf_t *)a1;+ radix_bits = ceil_log2(radix);+ digits_per_limb = LIMB_BITS / radix_bits;+ pos_incr = digits_per_limb * radix_bits;+ /* digits are aligned relative to the radix point */+ pos = a->len * LIMB_BITS + smod(-a->expn, radix_bits);+ first_buf_pos = 0;+ } else {+ limb_t n, radixl;++ digits_per_limb = digits_per_limb_table[radix - 2];+ radixl = get_limb_radix(radix);+ a = &a_s;+ bf_init(a1->ctx, a);+ n = (n_digits + digits_per_limb - 1) / digits_per_limb;+ if (bf_resize(a, n)) {+ dbuf_set_error(s);+ goto done;+ }+ if (bf_integer_to_radix(a, a1, radixl)) {+ dbuf_set_error(s);+ goto done;+ }+ radix_bits = 0;+ pos = n;+ pos_incr = 1;+ first_buf_pos = pos * digits_per_limb - n_digits;+ }+ buf_pos = digits_per_limb;+ i = 0;+ while (i < n_digits) {+ if (buf_pos == digits_per_limb) {+ pos -= pos_incr;+ if (radix_bits == 0) {+ v = get_limbz(a, pos);+ limb_to_a(buf, v, radix, digits_per_limb);+ } else {+ v = get_bits(a->tab, a->len, pos);+ limb_to_a2(buf, v, radix_bits, digits_per_limb);+ }+ buf_pos = first_buf_pos;+ first_buf_pos = 0;+ }+ if (i < dot_pos) {+ l = dot_pos;+ } else {+ if (i == dot_pos)+ dbuf_putc(s, '.');+ l = n_digits;+ }+ l = bf_min(digits_per_limb - buf_pos, l - i);+ dbuf_put(s, (uint8_t *)(buf + buf_pos), l);+ buf_pos += l;+ i += l;+ }+ done:+ if (a != a1)+ bf_delete(a);+}++static void *bf_dbuf_realloc(void *opaque, void *ptr, size_t size)+{+ bf_context_t *s = opaque;+ return bf_realloc(s, ptr, size);+}++/* return the length in bytes. A trailing '\0' is added */+static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix,+ limb_t prec, bf_flags_t flags, BOOL is_dec)+{+ bf_context_t *ctx = a2->ctx;+ DynBuf s_s, *s = &s_s;+ int radix_bits;+ + // bf_print_str("ftoa", a2);+ // printf("radix=%d\n", radix);+ dbuf_init2(s, ctx, bf_dbuf_realloc);+ if (a2->expn == BF_EXP_NAN) {+ dbuf_putstr(s, "NaN");+ } else {+ if (a2->sign)+ dbuf_putc(s, '-');+ if (a2->expn == BF_EXP_INF) {+ if (flags & BF_FTOA_JS_QUIRKS)+ dbuf_putstr(s, "Infinity");+ else+ dbuf_putstr(s, "Inf");+ } else {+ int fmt, ret;+ slimb_t n_digits, n, i, n_max, n1;+ bf_t a1_s, *a1 = &a1_s;++ if ((radix & (radix - 1)) != 0)+ radix_bits = 0;+ else+ radix_bits = ceil_log2(radix);++ fmt = flags & BF_FTOA_FORMAT_MASK;+ bf_init(ctx, a1);+ if (fmt == BF_FTOA_FORMAT_FRAC) {+ if (is_dec || radix_bits != 0) {+ if (bf_set(a1, a2))+ goto fail1;+#ifdef USE_BF_DEC+ if (is_dec) {+ if (bfdec_round((bfdec_t *)a1, prec, (flags & BF_RND_MASK) | BF_FLAG_RADPNT_PREC) & BF_ST_MEM_ERROR)+ goto fail1;+ n = a1->expn;+ } else+#endif+ {+ if (bf_round(a1, prec * radix_bits, (flags & BF_RND_MASK) | BF_FLAG_RADPNT_PREC) & BF_ST_MEM_ERROR)+ goto fail1;+ n = ceil_div(a1->expn, radix_bits);+ }+ if (flags & BF_FTOA_ADD_PREFIX) {+ if (radix == 16)+ dbuf_putstr(s, "0x");+ else if (radix == 8)+ dbuf_putstr(s, "0o");+ else if (radix == 2)+ dbuf_putstr(s, "0b");+ }+ if (a1->expn == BF_EXP_ZERO) {+ dbuf_putstr(s, "0");+ if (prec > 0) {+ dbuf_putstr(s, ".");+ for(i = 0; i < prec; i++) {+ dbuf_putc(s, '0');+ }+ }+ } else {+ n_digits = prec + n;+ if (n <= 0) {+ /* 0.x */+ dbuf_putstr(s, "0.");+ for(i = 0; i < -n; i++) {+ dbuf_putc(s, '0');+ }+ if (n_digits > 0) {+ output_digits(s, a1, radix, n_digits, n_digits, is_dec);+ }+ } else {+ output_digits(s, a1, radix, n_digits, n, is_dec);+ }+ }+ } else {+ size_t pos, start;+ bf_t a_s, *a = &a_s;++ /* make a positive number */+ a->tab = a2->tab;+ a->len = a2->len;+ a->expn = a2->expn;+ a->sign = 0;+ + /* one more digit for the rounding */+ n = 1 + bf_mul_log2_radix(bf_max(a->expn, 0), radix, TRUE, TRUE);+ n_digits = n + prec;+ n1 = n;+ if (bf_convert_to_radix(a1, &n1, a, radix, n_digits,+ flags & BF_RND_MASK, TRUE))+ goto fail1;+ start = s->size;+ output_digits(s, a1, radix, n_digits, n, is_dec);+ /* remove leading zeros because we allocated one more digit */+ pos = start;+ while ((pos + 1) < s->size && s->buf[pos] == '0' &&+ s->buf[pos + 1] != '.')+ pos++;+ if (pos > start) {+ memmove(s->buf + start, s->buf + pos, s->size - pos);+ s->size -= (pos - start);+ }+ }+ } else {+#ifdef USE_BF_DEC+ if (is_dec) {+ if (bf_set(a1, a2))+ goto fail1;+ if (fmt == BF_FTOA_FORMAT_FIXED) {+ n_digits = prec;+ n_max = n_digits;+ if (bfdec_round((bfdec_t *)a1, prec, (flags & BF_RND_MASK)) & BF_ST_MEM_ERROR)+ goto fail1;+ } else {+ /* prec is ignored */+ prec = n_digits = a1->len * LIMB_DIGITS;+ /* remove the trailing zero digits */+ while (n_digits > 1 &&+ get_digit(a1->tab, a1->len, prec - n_digits) == 0) {+ n_digits--;+ }+ n_max = n_digits + 4;+ }+ n = a1->expn;+ } else+#endif+ if (radix_bits != 0) {+ if (bf_set(a1, a2))+ goto fail1;+ if (fmt == BF_FTOA_FORMAT_FIXED) {+ slimb_t prec_bits;+ n_digits = prec;+ n_max = n_digits;+ /* align to the radix point */+ prec_bits = prec * radix_bits -+ smod(-a1->expn, radix_bits);+ if (bf_round(a1, prec_bits,+ (flags & BF_RND_MASK)) & BF_ST_MEM_ERROR)+ goto fail1;+ } else {+ limb_t digit_mask;+ slimb_t pos;+ /* position of the digit before the most+ significant digit in bits */+ pos = a1->len * LIMB_BITS ++ smod(-a1->expn, radix_bits);+ n_digits = ceil_div(pos, radix_bits);+ /* remove the trailing zero digits */+ digit_mask = ((limb_t)1 << radix_bits) - 1;+ while (n_digits > 1 &&+ (get_bits(a1->tab, a1->len, pos - n_digits * radix_bits) & digit_mask) == 0) {+ n_digits--;+ }+ n_max = n_digits + 4;+ }+ n = ceil_div(a1->expn, radix_bits);+ } else {+ bf_t a_s, *a = &a_s;+ + /* make a positive number */+ a->tab = a2->tab;+ a->len = a2->len;+ a->expn = a2->expn;+ a->sign = 0;+ + if (fmt == BF_FTOA_FORMAT_FIXED) {+ n_digits = prec;+ n_max = n_digits;+ } else {+ slimb_t n_digits_max, n_digits_min;+ + assert(prec != BF_PREC_INF);+ n_digits = 1 + bf_mul_log2_radix(prec, radix, TRUE, TRUE);+ /* max number of digits for non exponential+ notation. The rational is to have the same rule+ as JS i.e. n_max = 21 for 64 bit float in base 10. */+ n_max = n_digits + 4;+ if (fmt == BF_FTOA_FORMAT_FREE_MIN) {+ bf_t b_s, *b = &b_s;+ + /* find the minimum number of digits by+ dichotomy. */+ /* XXX: inefficient */+ n_digits_max = n_digits;+ n_digits_min = 1;+ bf_init(ctx, b);+ while (n_digits_min < n_digits_max) {+ n_digits = (n_digits_min + n_digits_max) / 2;+ if (bf_convert_to_radix(a1, &n, a, radix, n_digits,+ flags & BF_RND_MASK, FALSE)) {+ bf_delete(b);+ goto fail1;+ }+ /* convert back to a number and compare */+ ret = bf_mul_pow_radix(b, a1, radix, n - n_digits,+ prec,+ (flags & ~BF_RND_MASK) |+ BF_RNDN);+ if (ret & BF_ST_MEM_ERROR) {+ bf_delete(b);+ goto fail1;+ }+ if (bf_cmpu(b, a) == 0) {+ n_digits_max = n_digits;+ } else {+ n_digits_min = n_digits + 1;+ }+ }+ bf_delete(b);+ n_digits = n_digits_max;+ }+ }+ if (bf_convert_to_radix(a1, &n, a, radix, n_digits,+ flags & BF_RND_MASK, FALSE)) {+ fail1:+ bf_delete(a1);+ goto fail;+ }+ }+ if (a1->expn == BF_EXP_ZERO &&+ fmt != BF_FTOA_FORMAT_FIXED &&+ !(flags & BF_FTOA_FORCE_EXP)) {+ /* just output zero */+ dbuf_putstr(s, "0");+ } else {+ if (flags & BF_FTOA_ADD_PREFIX) {+ if (radix == 16)+ dbuf_putstr(s, "0x");+ else if (radix == 8)+ dbuf_putstr(s, "0o");+ else if (radix == 2)+ dbuf_putstr(s, "0b");+ }+ if (a1->expn == BF_EXP_ZERO)+ n = 1;+ if ((flags & BF_FTOA_FORCE_EXP) ||+ n <= -6 || n > n_max) {+ const char *fmt;+ /* exponential notation */+ output_digits(s, a1, radix, n_digits, 1, is_dec);+ if (radix_bits != 0 && radix <= 16) {+ if (flags & BF_FTOA_JS_QUIRKS)+ fmt = "p%+" PRId_LIMB;+ else+ fmt = "p%" PRId_LIMB;+ dbuf_printf(s, fmt, (n - 1) * radix_bits);+ } else {+ if (flags & BF_FTOA_JS_QUIRKS)+ fmt = "%c%+" PRId_LIMB;+ else+ fmt = "%c%" PRId_LIMB;+ dbuf_printf(s, fmt,+ radix <= 10 ? 'e' : '@', n - 1);+ }+ } else if (n <= 0) {+ /* 0.x */+ dbuf_putstr(s, "0.");+ for(i = 0; i < -n; i++) {+ dbuf_putc(s, '0');+ }+ output_digits(s, a1, radix, n_digits, n_digits, is_dec);+ } else {+ if (n_digits <= n) {+ /* no dot */+ output_digits(s, a1, radix, n_digits, n_digits, is_dec);+ for(i = 0; i < (n - n_digits); i++)+ dbuf_putc(s, '0');+ } else {+ output_digits(s, a1, radix, n_digits, n, is_dec);+ }+ }+ }+ }+ bf_delete(a1);+ }+ }+ dbuf_putc(s, '\0');+ if (dbuf_error(s))+ goto fail;+ if (plen)+ *plen = s->size - 1;+ return (char *)s->buf;+ fail:+ bf_free(ctx, s->buf);+ if (plen)+ *plen = 0;+ return NULL;+}++char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec,+ bf_flags_t flags)+{+ return bf_ftoa_internal(plen, a, radix, prec, flags, FALSE);+}++/***************************************************************/+/* transcendental functions */++/* Note: the algorithm is from MPFR */+static void bf_const_log2_rec(bf_t *T, bf_t *P, bf_t *Q, limb_t n1,+ limb_t n2, BOOL need_P)+{+ bf_context_t *s = T->ctx;+ if ((n2 - n1) == 1) {+ if (n1 == 0) {+ bf_set_ui(P, 3);+ } else {+ bf_set_ui(P, n1);+ P->sign = 1;+ }+ bf_set_ui(Q, 2 * n1 + 1);+ Q->expn += 2;+ bf_set(T, P);+ } else {+ limb_t m;+ bf_t T1_s, *T1 = &T1_s;+ bf_t P1_s, *P1 = &P1_s;+ bf_t Q1_s, *Q1 = &Q1_s;+ + m = n1 + ((n2 - n1) >> 1);+ bf_const_log2_rec(T, P, Q, n1, m, TRUE);+ bf_init(s, T1);+ bf_init(s, P1);+ bf_init(s, Q1);+ bf_const_log2_rec(T1, P1, Q1, m, n2, need_P);+ bf_mul(T, T, Q1, BF_PREC_INF, BF_RNDZ);+ bf_mul(T1, T1, P, BF_PREC_INF, BF_RNDZ);+ bf_add(T, T, T1, BF_PREC_INF, BF_RNDZ);+ if (need_P)+ bf_mul(P, P, P1, BF_PREC_INF, BF_RNDZ);+ bf_mul(Q, Q, Q1, BF_PREC_INF, BF_RNDZ);+ bf_delete(T1);+ bf_delete(P1);+ bf_delete(Q1);+ }+}++/* compute log(2) with faithful rounding at precision 'prec' */+static void bf_const_log2_internal(bf_t *T, limb_t prec)+{+ limb_t w, N;+ bf_t P_s, *P = &P_s;+ bf_t Q_s, *Q = &Q_s;++ w = prec + 15;+ N = w / 3 + 1;+ bf_init(T->ctx, P);+ bf_init(T->ctx, Q);+ bf_const_log2_rec(T, P, Q, 0, N, FALSE);+ bf_div(T, T, Q, prec, BF_RNDN);+ bf_delete(P);+ bf_delete(Q);+}++/* PI constant */++#define CHUD_A 13591409+#define CHUD_B 545140134+#define CHUD_C 640320+#define CHUD_BITS_PER_TERM 47++static void chud_bs(bf_t *P, bf_t *Q, bf_t *G, int64_t a, int64_t b, int need_g,+ limb_t prec)+{+ bf_context_t *s = P->ctx;+ int64_t c;++ if (a == (b - 1)) {+ bf_t T0, T1;+ + bf_init(s, &T0);+ bf_init(s, &T1);+ bf_set_ui(G, 2 * b - 1);+ bf_mul_ui(G, G, 6 * b - 1, prec, BF_RNDN);+ bf_mul_ui(G, G, 6 * b - 5, prec, BF_RNDN);+ bf_set_ui(&T0, CHUD_B);+ bf_mul_ui(&T0, &T0, b, prec, BF_RNDN);+ bf_set_ui(&T1, CHUD_A);+ bf_add(&T0, &T0, &T1, prec, BF_RNDN);+ bf_mul(P, G, &T0, prec, BF_RNDN);+ P->sign = b & 1;++ bf_set_ui(Q, b);+ bf_mul_ui(Q, Q, b, prec, BF_RNDN);+ bf_mul_ui(Q, Q, b, prec, BF_RNDN);+ bf_mul_ui(Q, Q, (uint64_t)CHUD_C * CHUD_C * CHUD_C / 24, prec, BF_RNDN);+ bf_delete(&T0);+ bf_delete(&T1);+ } else {+ bf_t P2, Q2, G2;+ + bf_init(s, &P2);+ bf_init(s, &Q2);+ bf_init(s, &G2);++ c = (a + b) / 2;+ chud_bs(P, Q, G, a, c, 1, prec);+ chud_bs(&P2, &Q2, &G2, c, b, need_g, prec);+ + /* Q = Q1 * Q2 */+ /* G = G1 * G2 */+ /* P = P1 * Q2 + P2 * G1 */+ bf_mul(&P2, &P2, G, prec, BF_RNDN);+ if (!need_g)+ bf_set_ui(G, 0);+ bf_mul(P, P, &Q2, prec, BF_RNDN);+ bf_add(P, P, &P2, prec, BF_RNDN);+ bf_delete(&P2);++ bf_mul(Q, Q, &Q2, prec, BF_RNDN);+ bf_delete(&Q2);+ if (need_g)+ bf_mul(G, G, &G2, prec, BF_RNDN);+ bf_delete(&G2);+ }+}++/* compute Pi with faithful rounding at precision 'prec' using the+ Chudnovsky formula */+static void bf_const_pi_internal(bf_t *Q, limb_t prec)+{+ bf_context_t *s = Q->ctx;+ int64_t n, prec1;+ bf_t P, G;++ /* number of serie terms */+ n = prec / CHUD_BITS_PER_TERM + 1;+ /* XXX: precision analysis */+ prec1 = prec + 32;++ bf_init(s, &P);+ bf_init(s, &G);++ chud_bs(&P, Q, &G, 0, n, 0, BF_PREC_INF);+ + bf_mul_ui(&G, Q, CHUD_A, prec1, BF_RNDN);+ bf_add(&P, &G, &P, prec1, BF_RNDN);+ bf_div(Q, Q, &P, prec1, BF_RNDF);+ + bf_set_ui(&P, CHUD_C);+ bf_sqrt(&G, &P, prec1, BF_RNDF);+ bf_mul_ui(&G, &G, (uint64_t)CHUD_C / 12, prec1, BF_RNDF);+ bf_mul(Q, Q, &G, prec, BF_RNDN);+ bf_delete(&P);+ bf_delete(&G);+}++static int bf_const_get(bf_t *T, limb_t prec, bf_flags_t flags,+ BFConstCache *c,+ void (*func)(bf_t *res, limb_t prec), int sign)+{+ limb_t ziv_extra_bits, prec1;++ ziv_extra_bits = 32;+ for(;;) {+ prec1 = prec + ziv_extra_bits;+ if (c->prec < prec1) {+ if (c->val.len == 0)+ bf_init(T->ctx, &c->val);+ func(&c->val, prec1);+ c->prec = prec1;+ } else {+ prec1 = c->prec;+ }+ bf_set(T, &c->val);+ T->sign = sign;+ if (!bf_can_round(T, prec, flags & BF_RND_MASK, prec1)) {+ /* and more precision and retry */+ ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);+ } else {+ break;+ }+ }+ return bf_round(T, prec, flags);+}++static void bf_const_free(BFConstCache *c)+{+ bf_delete(&c->val);+ memset(c, 0, sizeof(*c));+}++int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags)+{+ bf_context_t *s = T->ctx;+ return bf_const_get(T, prec, flags, &s->log2_cache, bf_const_log2_internal, 0);+}++/* return rounded pi * (1 - 2 * sign) */+static int bf_const_pi_signed(bf_t *T, int sign, limb_t prec, bf_flags_t flags)+{+ bf_context_t *s = T->ctx;+ return bf_const_get(T, prec, flags, &s->pi_cache, bf_const_pi_internal,+ sign);+}++int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags)+{+ return bf_const_pi_signed(T, 0, prec, flags);+}++void bf_clear_cache(bf_context_t *s)+{+#ifdef USE_FFT_MUL+ fft_clear_cache(s);+#endif+ bf_const_free(&s->log2_cache);+ bf_const_free(&s->pi_cache);+}++/* ZivFunc should compute the result 'r' with faithful rounding at+ precision 'prec'. For efficiency purposes, the final bf_round()+ does not need to be done in the function. */+typedef int ZivFunc(bf_t *r, const bf_t *a, limb_t prec, void *opaque);++static int bf_ziv_rounding(bf_t *r, const bf_t *a,+ limb_t prec, bf_flags_t flags,+ ZivFunc *f, void *opaque)+{+ int rnd_mode, ret;+ slimb_t prec1, ziv_extra_bits;+ + rnd_mode = flags & BF_RND_MASK;+ if (rnd_mode == BF_RNDF) {+ /* no need to iterate */+ f(r, a, prec, opaque);+ ret = 0;+ } else {+ ziv_extra_bits = 32;+ for(;;) {+ prec1 = prec + ziv_extra_bits;+ ret = f(r, a, prec1, opaque);+ if (ret & (BF_ST_OVERFLOW | BF_ST_UNDERFLOW | BF_ST_MEM_ERROR)) {+ /* overflow or underflow should never happen because+ it indicates the rounding cannot be done correctly,+ but we do not catch all the cases */+ return ret;+ }+ /* if the result is exact, we can stop */+ if (!(ret & BF_ST_INEXACT)) {+ ret = 0;+ break;+ }+ if (bf_can_round(r, prec, rnd_mode, prec1)) {+ ret = BF_ST_INEXACT;+ break;+ }+ ziv_extra_bits = ziv_extra_bits * 2;+ // printf("ziv_extra_bits=%" PRId64 "\n", (int64_t)ziv_extra_bits);+ }+ }+ if (r->len == 0)+ return ret;+ else+ return __bf_round(r, prec, flags, r->len, ret);+}++/* add (1 - 2*e_sign) * 2^e */+static int bf_add_epsilon(bf_t *r, const bf_t *a, slimb_t e, int e_sign,+ limb_t prec, int flags)+{+ bf_t T_s, *T = &T_s;+ int ret;+ /* small argument case: result = 1 + epsilon * sign(x) */+ bf_init(a->ctx, T);+ bf_set_ui(T, 1);+ T->sign = e_sign;+ T->expn += e;+ ret = bf_add(r, r, T, prec, flags);+ bf_delete(T);+ return ret;+}++/* Compute the exponential using faithful rounding at precision 'prec'.+ Note: the algorithm is from MPFR */+static int bf_exp_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)+{+ bf_context_t *s = r->ctx;+ bf_t T_s, *T = &T_s;+ slimb_t n, K, l, i, prec1;+ + assert(r != a);++ /* argument reduction:+ T = a - n*log(2) with 0 <= T < log(2) and n integer.+ */+ bf_init(s, T);+ if (a->expn <= -1) {+ /* 0 <= abs(a) <= 0.5 */+ if (a->sign)+ n = -1;+ else+ n = 0;+ } else {+ bf_const_log2(T, LIMB_BITS, BF_RNDZ);+ bf_div(T, a, T, LIMB_BITS, BF_RNDD);+ bf_get_limb(&n, T, 0);+ }++ K = bf_isqrt((prec + 1) / 2);+ l = (prec - 1) / K + 1;+ /* XXX: precision analysis ? */+ prec1 = prec + (K + 2 * l + 18) + K + 8;+ if (a->expn > 0)+ prec1 += a->expn;+ // printf("n=%ld K=%ld prec1=%ld\n", n, K, prec1);++ bf_const_log2(T, prec1, BF_RNDF);+ bf_mul_si(T, T, n, prec1, BF_RNDN);+ bf_sub(T, a, T, prec1, BF_RNDN);++ /* reduce the range of T */+ bf_mul_2exp(T, -K, BF_PREC_INF, BF_RNDZ);+ + /* Taylor expansion around zero :+ 1 + x + x^2/2 + ... + x^n/n! + = (1 + x * (1 + x/2 * (1 + ... (x/n))))+ */+ {+ bf_t U_s, *U = &U_s;+ + bf_init(s, U);+ bf_set_ui(r, 1);+ for(i = l ; i >= 1; i--) {+ bf_set_ui(U, i);+ bf_div(U, T, U, prec1, BF_RNDN);+ bf_mul(r, r, U, prec1, BF_RNDN);+ bf_add_si(r, r, 1, prec1, BF_RNDN);+ }+ bf_delete(U);+ }+ bf_delete(T);+ + /* undo the range reduction */+ for(i = 0; i < K; i++) {+ bf_mul(r, r, r, prec1, BF_RNDN | BF_FLAG_EXT_EXP);+ }++ /* undo the argument reduction */+ bf_mul_2exp(r, n, BF_PREC_INF, BF_RNDZ | BF_FLAG_EXT_EXP);++ return BF_ST_INEXACT;+}++/* crude overflow and underflow tests for exp(a). a_low <= a <= a_high */+static int check_exp_underflow_overflow(bf_context_t *s, bf_t *r,+ const bf_t *a_low, const bf_t *a_high,+ limb_t prec, bf_flags_t flags)+{+ bf_t T_s, *T = &T_s;+ bf_t log2_s, *log2 = &log2_s;+ slimb_t e_min, e_max;+ + if (a_high->expn <= 0)+ return 0;++ e_max = (limb_t)1 << (bf_get_exp_bits(flags) - 1);+ e_min = -e_max + 3;+ if (flags & BF_FLAG_SUBNORMAL)+ e_min -= (prec - 1);+ + bf_init(s, T);+ bf_init(s, log2);+ bf_const_log2(log2, LIMB_BITS, BF_RNDU);+ bf_mul_ui(T, log2, e_max, LIMB_BITS, BF_RNDU);+ /* a_low > e_max * log(2) implies exp(a) > e_max */+ if (bf_cmp_lt(T, a_low) > 0) {+ /* overflow */+ bf_delete(T);+ bf_delete(log2);+ return bf_set_overflow(r, 0, prec, flags);+ }+ /* a_high < (e_min - 2) * log(2) implies exp(a) < (e_min - 2) */+ bf_const_log2(log2, LIMB_BITS, BF_RNDD);+ bf_mul_si(T, log2, e_min - 2, LIMB_BITS, BF_RNDD);+ if (bf_cmp_lt(a_high, T)) {+ int rnd_mode = flags & BF_RND_MASK;+ + /* underflow */+ bf_delete(T);+ bf_delete(log2);+ if (rnd_mode == BF_RNDU) {+ /* set the smallest value */+ bf_set_ui(r, 1);+ r->expn = e_min;+ } else {+ bf_set_zero(r, 0);+ }+ return BF_ST_UNDERFLOW | BF_ST_INEXACT;+ }+ bf_delete(log2);+ bf_delete(T);+ return 0;+}++int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)+{+ bf_context_t *s = r->ctx;+ int ret;+ assert(r != a);+ if (a->len == 0) {+ if (a->expn == BF_EXP_NAN) {+ bf_set_nan(r);+ } else if (a->expn == BF_EXP_INF) {+ if (a->sign)+ bf_set_zero(r, 0);+ else+ bf_set_inf(r, 0);+ } else {+ bf_set_ui(r, 1);+ }+ return 0;+ }++ ret = check_exp_underflow_overflow(s, r, a, a, prec, flags);+ if (ret)+ return ret;+ if (a->expn < 0 && (-a->expn) >= (prec + 2)) { + /* small argument case: result = 1 + epsilon * sign(x) */+ bf_set_ui(r, 1);+ return bf_add_epsilon(r, r, -(prec + 2), a->sign, prec, flags);+ }+ + return bf_ziv_rounding(r, a, prec, flags, bf_exp_internal, NULL);+}++static int bf_log_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)+{+ bf_context_t *s = r->ctx;+ bf_t T_s, *T = &T_s;+ bf_t U_s, *U = &U_s;+ bf_t V_s, *V = &V_s;+ slimb_t n, prec1, l, i, K;+ + assert(r != a);++ bf_init(s, T);+ /* argument reduction 1 */+ /* T=a*2^n with 2/3 <= T <= 4/3 */+ {+ bf_t U_s, *U = &U_s;+ bf_set(T, a);+ n = T->expn;+ T->expn = 0;+ /* U= ~ 2/3 */+ bf_init(s, U);+ bf_set_ui(U, 0xaaaaaaaa); + U->expn = 0;+ if (bf_cmp_lt(T, U)) {+ T->expn++;+ n--;+ }+ bf_delete(U);+ }+ // printf("n=%ld\n", n);+ // bf_print_str("T", T);++ /* XXX: precision analysis */+ /* number of iterations for argument reduction 2 */+ K = bf_isqrt((prec + 1) / 2); + /* order of Taylor expansion */+ l = prec / (2 * K) + 1; + /* precision of the intermediate computations */+ prec1 = prec + K + 2 * l + 32;++ bf_init(s, U);+ bf_init(s, V);+ + /* Note: cancellation occurs here, so we use more precision (XXX:+ reduce the precision by computing the exact cancellation) */+ bf_add_si(T, T, -1, BF_PREC_INF, BF_RNDN); ++ /* argument reduction 2 */+ for(i = 0; i < K; i++) {+ /* T = T / (1 + sqrt(1 + T)) */+ bf_add_si(U, T, 1, prec1, BF_RNDN);+ bf_sqrt(V, U, prec1, BF_RNDF);+ bf_add_si(U, V, 1, prec1, BF_RNDN);+ bf_div(T, T, U, prec1, BF_RNDN);+ }++ {+ bf_t Y_s, *Y = &Y_s;+ bf_t Y2_s, *Y2 = &Y2_s;+ bf_init(s, Y);+ bf_init(s, Y2);++ /* compute ln(1+x) = ln((1+y)/(1-y)) with y=x/(2+x)+ = y + y^3/3 + ... + y^(2*l + 1) / (2*l+1) + with Y=Y^2+ = y*(1+Y/3+Y^2/5+...) = y*(1+Y*(1/3+Y*(1/5 + ...)))+ */+ bf_add_si(Y, T, 2, prec1, BF_RNDN);+ bf_div(Y, T, Y, prec1, BF_RNDN);++ bf_mul(Y2, Y, Y, prec1, BF_RNDN);+ bf_set_ui(r, 0);+ for(i = l; i >= 1; i--) {+ bf_set_ui(U, 1);+ bf_set_ui(V, 2 * i + 1);+ bf_div(U, U, V, prec1, BF_RNDN);+ bf_add(r, r, U, prec1, BF_RNDN);+ bf_mul(r, r, Y2, prec1, BF_RNDN);+ }+ bf_add_si(r, r, 1, prec1, BF_RNDN);+ bf_mul(r, r, Y, prec1, BF_RNDN);+ bf_delete(Y);+ bf_delete(Y2);+ }+ bf_delete(V);+ bf_delete(U);++ /* multiplication by 2 for the Taylor expansion and undo the+ argument reduction 2*/+ bf_mul_2exp(r, K + 1, BF_PREC_INF, BF_RNDZ);+ + /* undo the argument reduction 1 */+ bf_const_log2(T, prec1, BF_RNDF);+ bf_mul_si(T, T, n, prec1, BF_RNDN);+ bf_add(r, r, T, prec1, BF_RNDN);+ + bf_delete(T);+ return BF_ST_INEXACT;+}++int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)+{+ bf_context_t *s = r->ctx;+ bf_t T_s, *T = &T_s;+ + assert(r != a);+ if (a->len == 0) {+ if (a->expn == BF_EXP_NAN) {+ bf_set_nan(r);+ return 0;+ } else if (a->expn == BF_EXP_INF) {+ if (a->sign) {+ bf_set_nan(r);+ return BF_ST_INVALID_OP;+ } else {+ bf_set_inf(r, 0);+ return 0;+ }+ } else {+ bf_set_inf(r, 1);+ return 0;+ }+ }+ if (a->sign) {+ bf_set_nan(r);+ return BF_ST_INVALID_OP;+ }+ bf_init(s, T);+ bf_set_ui(T, 1);+ if (bf_cmp_eq(a, T)) {+ bf_set_zero(r, 0);+ bf_delete(T);+ return 0;+ }+ bf_delete(T);++ return bf_ziv_rounding(r, a, prec, flags, bf_log_internal, NULL);+}++/* x and y finite and x > 0 */+static int bf_pow_generic(bf_t *r, const bf_t *x, limb_t prec, void *opaque)+{+ bf_context_t *s = r->ctx;+ const bf_t *y = opaque;+ bf_t T_s, *T = &T_s;+ limb_t prec1;++ bf_init(s, T);+ /* XXX: proof for the added precision */+ prec1 = prec + 32;+ bf_log(T, x, prec1, BF_RNDF | BF_FLAG_EXT_EXP);+ bf_mul(T, T, y, prec1, BF_RNDF | BF_FLAG_EXT_EXP);+ if (bf_is_nan(T))+ bf_set_nan(r);+ else+ bf_exp_internal(r, T, prec1, NULL); /* no overflow/underlow test needed */+ bf_delete(T);+ return BF_ST_INEXACT;+}++/* x and y finite, x > 0, y integer and y fits on one limb */+static int bf_pow_int(bf_t *r, const bf_t *x, limb_t prec, void *opaque)+{+ bf_context_t *s = r->ctx;+ const bf_t *y = opaque;+ bf_t T_s, *T = &T_s;+ limb_t prec1;+ int ret;+ slimb_t y1;+ + bf_get_limb(&y1, y, 0);+ if (y1 < 0)+ y1 = -y1;+ /* XXX: proof for the added precision */+ prec1 = prec + ceil_log2(y1) * 2 + 8;+ ret = bf_pow_ui(r, x, y1 < 0 ? -y1 : y1, prec1, BF_RNDN | BF_FLAG_EXT_EXP);+ if (y->sign) {+ bf_init(s, T);+ bf_set_ui(T, 1);+ ret |= bf_div(r, T, r, prec1, BF_RNDN | BF_FLAG_EXT_EXP);+ bf_delete(T);+ }+ return ret;+}++/* x must be a finite non zero float. Return TRUE if there is a+ floating point number r such as x=r^(2^n) and return this floating+ point number 'r'. Otherwise return FALSE and r is undefined. */+static BOOL check_exact_power2n(bf_t *r, const bf_t *x, slimb_t n)+{+ bf_context_t *s = r->ctx;+ bf_t T_s, *T = &T_s;+ slimb_t e, i, er;+ limb_t v;+ + /* x = m*2^e with m odd integer */+ e = bf_get_exp_min(x);+ /* fast check on the exponent */+ if (n > (LIMB_BITS - 1)) {+ if (e != 0)+ return FALSE;+ er = 0;+ } else {+ if ((e & (((limb_t)1 << n) - 1)) != 0)+ return FALSE;+ er = e >> n;+ }+ /* every perfect odd square = 1 modulo 8 */+ v = get_bits(x->tab, x->len, x->len * LIMB_BITS - x->expn + e);+ if ((v & 7) != 1)+ return FALSE;++ bf_init(s, T);+ bf_set(T, x);+ T->expn -= e;+ for(i = 0; i < n; i++) {+ if (i != 0)+ bf_set(T, r);+ if (bf_sqrtrem(r, NULL, T) != 0)+ return FALSE;+ }+ r->expn += er;+ return TRUE;+}++/* prec = BF_PREC_INF is accepted for x and y integers and y >= 0 */+int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags)+{+ bf_context_t *s = r->ctx;+ bf_t T_s, *T = &T_s;+ bf_t ytmp_s;+ BOOL y_is_int, y_is_odd;+ int r_sign, ret, rnd_mode;+ slimb_t y_emin;+ + if (x->len == 0 || y->len == 0) {+ if (y->expn == BF_EXP_ZERO) {+ /* pow(x, 0) = 1 */+ bf_set_ui(r, 1);+ } else if (x->expn == BF_EXP_NAN) {+ bf_set_nan(r);+ } else {+ int cmp_x_abs_1;+ bf_set_ui(r, 1);+ cmp_x_abs_1 = bf_cmpu(x, r);+ if (cmp_x_abs_1 == 0 && (flags & BF_POW_JS_QUIRKS) &&+ (y->expn >= BF_EXP_INF)) {+ bf_set_nan(r);+ } else if (cmp_x_abs_1 == 0 &&+ (!x->sign || y->expn != BF_EXP_NAN)) {+ /* pow(1, y) = 1 even if y = NaN */+ /* pow(-1, +/-inf) = 1 */+ } else if (y->expn == BF_EXP_NAN) {+ bf_set_nan(r);+ } else if (y->expn == BF_EXP_INF) {+ if (y->sign == (cmp_x_abs_1 > 0)) {+ bf_set_zero(r, 0);+ } else {+ bf_set_inf(r, 0);+ }+ } else {+ y_emin = bf_get_exp_min(y);+ y_is_odd = (y_emin == 0);+ if (y->sign == (x->expn == BF_EXP_ZERO)) {+ bf_set_inf(r, y_is_odd & x->sign);+ if (y->sign) {+ /* pow(0, y) with y < 0 */+ return BF_ST_DIVIDE_ZERO;+ }+ } else {+ bf_set_zero(r, y_is_odd & x->sign);+ }+ }+ }+ return 0;+ }+ bf_init(s, T);+ bf_set(T, x);+ y_emin = bf_get_exp_min(y);+ y_is_int = (y_emin >= 0);+ rnd_mode = flags & BF_RND_MASK;+ if (x->sign) {+ if (!y_is_int) {+ bf_set_nan(r);+ bf_delete(T);+ return BF_ST_INVALID_OP;+ }+ y_is_odd = (y_emin == 0);+ r_sign = y_is_odd;+ /* change the directed rounding mode if the sign of the result+ is changed */+ if (r_sign && (rnd_mode == BF_RNDD || rnd_mode == BF_RNDU))+ flags ^= 1;+ bf_neg(T);+ } else {+ r_sign = 0;+ }++ bf_set_ui(r, 1);+ if (bf_cmp_eq(T, r)) {+ /* abs(x) = 1: nothing more to do */+ ret = 0;+ } else {+ /* check the overflow/underflow cases */+ {+ bf_t al_s, *al = &al_s;+ bf_t ah_s, *ah = &ah_s;+ limb_t precl = LIMB_BITS;+ + bf_init(s, al);+ bf_init(s, ah);+ /* compute bounds of log(abs(x)) * y with a low precision */+ /* XXX: compute bf_log() once */+ /* XXX: add a fast test before this slow test */+ bf_log(al, T, precl, BF_RNDD);+ bf_log(ah, T, precl, BF_RNDU);+ bf_mul(al, al, y, precl, BF_RNDD ^ y->sign);+ bf_mul(ah, ah, y, precl, BF_RNDU ^ y->sign);+ ret = check_exp_underflow_overflow(s, r, al, ah, prec, flags);+ bf_delete(al);+ bf_delete(ah);+ if (ret)+ goto done;+ }+ + if (y_is_int) {+ slimb_t T_bits, e;+ int_pow:+ T_bits = T->expn - bf_get_exp_min(T);+ if (T_bits == 1) {+ /* pow(2^b, y) = 2^(b*y) */+ bf_mul_si(T, y, T->expn - 1, LIMB_BITS, BF_RNDZ);+ bf_get_limb(&e, T, 0);+ bf_set_ui(r, 1);+ ret = bf_mul_2exp(r, e, prec, flags);+ } else if (prec == BF_PREC_INF) {+ slimb_t y1;+ /* specific case for infinite precision (integer case) */+ bf_get_limb(&y1, y, 0);+ assert(!y->sign);+ /* x must be an integer, so abs(x) >= 2 */+ if (y1 >= ((slimb_t)1 << BF_EXP_BITS_MAX)) {+ bf_delete(T);+ return bf_set_overflow(r, 0, BF_PREC_INF, flags);+ }+ ret = bf_pow_ui(r, T, y1, BF_PREC_INF, BF_RNDZ);+ } else {+ if (y->expn <= 31) {+ /* small enough power: use exponentiation in all cases */+ } else if (y->sign) {+ /* cannot be exact */+ goto general_case;+ } else {+ if (rnd_mode == BF_RNDF)+ goto general_case; /* no need to track exact results */+ /* see if the result has a chance to be exact:+ if x=a*2^b (a odd), x^y=a^y*2^(b*y)+ x^y needs a precision of at least floor_log2(a)*y bits+ */+ bf_mul_si(r, y, T_bits - 1, LIMB_BITS, BF_RNDZ);+ bf_get_limb(&e, r, 0);+ if (prec < e)+ goto general_case;+ }+ ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_int, (void *)y);+ }+ } else {+ if (rnd_mode != BF_RNDF) {+ bf_t *y1;+ if (y_emin < 0 && check_exact_power2n(r, T, -y_emin)) {+ /* the problem is reduced to a power to an integer */+#if 0+ printf("\nn=%" PRId64 "\n", -(int64_t)y_emin);+ bf_print_str("T", T);+ bf_print_str("r", r);+#endif+ bf_set(T, r);+ y1 = &ytmp_s;+ y1->tab = y->tab;+ y1->len = y->len;+ y1->sign = y->sign;+ y1->expn = y->expn - y_emin;+ y = y1;+ goto int_pow;+ }+ }+ general_case:+ ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_generic, (void *)y);+ }+ }+ done:+ bf_delete(T);+ r->sign = r_sign;+ return ret;+}++/* compute sqrt(-2*x-x^2) to get |sin(x)| from cos(x) - 1. */+static void bf_sqrt_sin(bf_t *r, const bf_t *x, limb_t prec1)+{+ bf_context_t *s = r->ctx;+ bf_t T_s, *T = &T_s;+ bf_init(s, T);+ bf_set(T, x);+ bf_mul(r, T, T, prec1, BF_RNDN);+ bf_mul_2exp(T, 1, BF_PREC_INF, BF_RNDZ);+ bf_add(T, T, r, prec1, BF_RNDN);+ bf_neg(T);+ bf_sqrt(r, T, prec1, BF_RNDF);+ bf_delete(T);+}++static int bf_sincos(bf_t *s, bf_t *c, const bf_t *a, limb_t prec)+{+ bf_context_t *s1 = a->ctx;+ bf_t T_s, *T = &T_s;+ bf_t U_s, *U = &U_s;+ bf_t r_s, *r = &r_s;+ slimb_t K, prec1, i, l, mod, prec2;+ int is_neg;+ + assert(c != a && s != a);++ bf_init(s1, T);+ bf_init(s1, U);+ bf_init(s1, r);+ + /* XXX: precision analysis */+ K = bf_isqrt(prec / 2);+ l = prec / (2 * K) + 1;+ prec1 = prec + 2 * K + l + 8;+ + /* after the modulo reduction, -pi/4 <= T <= pi/4 */+ if (a->expn <= -1) {+ /* abs(a) <= 0.25: no modulo reduction needed */+ bf_set(T, a);+ mod = 0;+ } else {+ slimb_t cancel;+ cancel = 0;+ for(;;) {+ prec2 = prec1 + a->expn + cancel;+ bf_const_pi(U, prec2, BF_RNDF);+ bf_mul_2exp(U, -1, BF_PREC_INF, BF_RNDZ);+ bf_remquo(&mod, T, a, U, prec2, BF_RNDN, BF_RNDN);+ // printf("T.expn=%ld prec2=%ld\n", T->expn, prec2);+ if (mod == 0 || (T->expn != BF_EXP_ZERO &&+ (T->expn + prec2) >= (prec1 - 1)))+ break;+ /* increase the number of bits until the precision is good enough */+ cancel = bf_max(-T->expn, (cancel + 1) * 3 / 2);+ }+ mod &= 3;+ }+ + is_neg = T->sign;+ + /* compute cosm1(x) = cos(x) - 1 */+ bf_mul(T, T, T, prec1, BF_RNDN);+ bf_mul_2exp(T, -2 * K, BF_PREC_INF, BF_RNDZ);+ + /* Taylor expansion:+ -x^2/2 + x^4/4! - x^6/6! + ...+ */+ bf_set_ui(r, 1);+ for(i = l ; i >= 1; i--) {+ bf_set_ui(U, 2 * i - 1);+ bf_mul_ui(U, U, 2 * i, BF_PREC_INF, BF_RNDZ);+ bf_div(U, T, U, prec1, BF_RNDN);+ bf_mul(r, r, U, prec1, BF_RNDN);+ bf_neg(r);+ if (i != 1)+ bf_add_si(r, r, 1, prec1, BF_RNDN);+ }+ bf_delete(U);++ /* undo argument reduction:+ cosm1(2*x)= 2*(2*cosm1(x)+cosm1(x)^2)+ */+ for(i = 0; i < K; i++) {+ bf_mul(T, r, r, prec1, BF_RNDN);+ bf_mul_2exp(r, 1, BF_PREC_INF, BF_RNDZ);+ bf_add(r, r, T, prec1, BF_RNDN);+ bf_mul_2exp(r, 1, BF_PREC_INF, BF_RNDZ);+ }+ bf_delete(T);++ if (c) {+ if ((mod & 1) == 0) {+ bf_add_si(c, r, 1, prec1, BF_RNDN);+ } else {+ bf_sqrt_sin(c, r, prec1);+ c->sign = is_neg ^ 1;+ }+ c->sign ^= mod >> 1;+ }+ if (s) {+ if ((mod & 1) == 0) {+ bf_sqrt_sin(s, r, prec1);+ s->sign = is_neg;+ } else {+ bf_add_si(s, r, 1, prec1, BF_RNDN);+ }+ s->sign ^= mod >> 1;+ }+ bf_delete(r);+ return BF_ST_INEXACT;+}++static int bf_cos_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)+{+ return bf_sincos(NULL, r, a, prec);+}++int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)+{+ if (a->len == 0) {+ if (a->expn == BF_EXP_NAN) {+ bf_set_nan(r);+ return 0;+ } else if (a->expn == BF_EXP_INF) {+ bf_set_nan(r);+ return BF_ST_INVALID_OP;+ } else {+ bf_set_ui(r, 1);+ return 0;+ }+ }++ /* small argument case: result = 1+r(x) with r(x) = -x^2/2 ++ O(X^4). We assume r(x) < 2^(2*EXP(x) - 1). */+ if (a->expn < 0) {+ slimb_t e;+ e = 2 * a->expn - 1;+ if (e < -(prec + 2)) {+ bf_set_ui(r, 1);+ return bf_add_epsilon(r, r, e, 1, prec, flags);+ }+ }+ + return bf_ziv_rounding(r, a, prec, flags, bf_cos_internal, NULL);+}++static int bf_sin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)+{+ return bf_sincos(r, NULL, a, prec);+}++int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)+{+ if (a->len == 0) {+ if (a->expn == BF_EXP_NAN) {+ bf_set_nan(r);+ return 0;+ } else if (a->expn == BF_EXP_INF) {+ bf_set_nan(r);+ return BF_ST_INVALID_OP;+ } else {+ bf_set_zero(r, a->sign);+ return 0;+ }+ }++ /* small argument case: result = x+r(x) with r(x) = -x^3/6 ++ O(X^5). We assume r(x) < 2^(3*EXP(x) - 2). */+ if (a->expn < 0) {+ slimb_t e;+ e = sat_add(2 * a->expn, a->expn - 2);+ if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {+ bf_set(r, a);+ return bf_add_epsilon(r, r, e, 1 - a->sign, prec, flags);+ }+ }++ return bf_ziv_rounding(r, a, prec, flags, bf_sin_internal, NULL);+}++static int bf_tan_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)+{+ bf_context_t *s = r->ctx;+ bf_t T_s, *T = &T_s;+ limb_t prec1;+ + /* XXX: precision analysis */+ prec1 = prec + 8;+ bf_init(s, T);+ bf_sincos(r, T, a, prec1);+ bf_div(r, r, T, prec1, BF_RNDF);+ bf_delete(T);+ return BF_ST_INEXACT;+}++int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)+{+ assert(r != a);+ if (a->len == 0) {+ if (a->expn == BF_EXP_NAN) {+ bf_set_nan(r);+ return 0;+ } else if (a->expn == BF_EXP_INF) {+ bf_set_nan(r);+ return BF_ST_INVALID_OP;+ } else {+ bf_set_zero(r, a->sign);+ return 0;+ }+ }++ /* small argument case: result = x+r(x) with r(x) = x^3/3 ++ O(X^5). We assume r(x) < 2^(3*EXP(x) - 1). */+ if (a->expn < 0) {+ slimb_t e;+ e = sat_add(2 * a->expn, a->expn - 1);+ if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {+ bf_set(r, a);+ return bf_add_epsilon(r, r, e, a->sign, prec, flags);+ }+ }+ + return bf_ziv_rounding(r, a, prec, flags, bf_tan_internal, NULL);+}++/* if add_pi2 is true, add pi/2 to the result (used for acos(x) to+ avoid cancellation) */+static int bf_atan_internal(bf_t *r, const bf_t *a, limb_t prec,+ void *opaque)+{+ bf_context_t *s = r->ctx;+ BOOL add_pi2 = (BOOL)(intptr_t)opaque;+ bf_t T_s, *T = &T_s;+ bf_t U_s, *U = &U_s;+ bf_t V_s, *V = &V_s;+ bf_t X2_s, *X2 = &X2_s;+ int cmp_1;+ slimb_t prec1, i, K, l;+ + /* XXX: precision analysis */+ K = bf_isqrt((prec + 1) / 2);+ l = prec / (2 * K) + 1;+ prec1 = prec + K + 2 * l + 32;+ // printf("prec=%d K=%d l=%d prec1=%d\n", (int)prec, (int)K, (int)l, (int)prec1);+ + bf_init(s, T);+ cmp_1 = (a->expn >= 1); /* a >= 1 */+ if (cmp_1) {+ bf_set_ui(T, 1);+ bf_div(T, T, a, prec1, BF_RNDN);+ } else {+ bf_set(T, a);+ }++ /* abs(T) <= 1 */++ /* argument reduction */++ bf_init(s, U);+ bf_init(s, V);+ bf_init(s, X2);+ for(i = 0; i < K; i++) {+ /* T = T / (1 + sqrt(1 + T^2)) */+ bf_mul(U, T, T, prec1, BF_RNDN);+ bf_add_si(U, U, 1, prec1, BF_RNDN);+ bf_sqrt(V, U, prec1, BF_RNDN);+ bf_add_si(V, V, 1, prec1, BF_RNDN);+ bf_div(T, T, V, prec1, BF_RNDN);+ }++ /* Taylor series: + x - x^3/3 + ... + (-1)^ l * y^(2*l + 1) / (2*l+1) + */+ bf_mul(X2, T, T, prec1, BF_RNDN);+ bf_set_ui(r, 0);+ for(i = l; i >= 1; i--) {+ bf_set_si(U, 1);+ bf_set_ui(V, 2 * i + 1);+ bf_div(U, U, V, prec1, BF_RNDN);+ bf_neg(r);+ bf_add(r, r, U, prec1, BF_RNDN);+ bf_mul(r, r, X2, prec1, BF_RNDN);+ }+ bf_neg(r);+ bf_add_si(r, r, 1, prec1, BF_RNDN);+ bf_mul(r, r, T, prec1, BF_RNDN);++ /* undo the argument reduction */+ bf_mul_2exp(r, K, BF_PREC_INF, BF_RNDZ);+ + bf_delete(U);+ bf_delete(V);+ bf_delete(X2);++ i = add_pi2;+ if (cmp_1 > 0) {+ /* undo the inversion : r = sign(a)*PI/2 - r */+ bf_neg(r);+ i += 1 - 2 * a->sign;+ }+ /* add i*(pi/2) with -1 <= i <= 2 */+ if (i != 0) {+ bf_const_pi(T, prec1, BF_RNDF);+ if (i != 2)+ bf_mul_2exp(T, -1, BF_PREC_INF, BF_RNDZ);+ T->sign = (i < 0);+ bf_add(r, T, r, prec1, BF_RNDN);+ }+ + bf_delete(T);+ return BF_ST_INEXACT;+}++int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)+{+ bf_context_t *s = r->ctx;+ bf_t T_s, *T = &T_s;+ int res;+ + if (a->len == 0) {+ if (a->expn == BF_EXP_NAN) {+ bf_set_nan(r);+ return 0;+ } else if (a->expn == BF_EXP_INF) {+ /* -PI/2 or PI/2 */+ bf_const_pi_signed(r, a->sign, prec, flags);+ bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ);+ return BF_ST_INEXACT;+ } else {+ bf_set_zero(r, a->sign);+ return 0;+ }+ }+ + bf_init(s, T);+ bf_set_ui(T, 1);+ res = bf_cmpu(a, T);+ bf_delete(T);+ if (res == 0) {+ /* short cut: abs(a) == 1 -> +/-pi/4 */+ bf_const_pi_signed(r, a->sign, prec, flags);+ bf_mul_2exp(r, -2, BF_PREC_INF, BF_RNDZ);+ return BF_ST_INEXACT;+ }++ /* small argument case: result = x+r(x) with r(x) = -x^3/3 ++ O(X^5). We assume r(x) < 2^(3*EXP(x) - 1). */+ if (a->expn < 0) {+ slimb_t e;+ e = sat_add(2 * a->expn, a->expn - 1);+ if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {+ bf_set(r, a);+ return bf_add_epsilon(r, r, e, 1 - a->sign, prec, flags);+ }+ }+ + return bf_ziv_rounding(r, a, prec, flags, bf_atan_internal, (void *)FALSE);+}++static int bf_atan2_internal(bf_t *r, const bf_t *y, limb_t prec, void *opaque)+{+ bf_context_t *s = r->ctx;+ const bf_t *x = opaque;+ bf_t T_s, *T = &T_s;+ limb_t prec1;+ int ret;+ + if (y->expn == BF_EXP_NAN || x->expn == BF_EXP_NAN) {+ bf_set_nan(r);+ return 0;+ }++ /* compute atan(y/x) assumming inf/inf = 1 and 0/0 = 0 */+ bf_init(s, T);+ prec1 = prec + 32;+ if (y->expn == BF_EXP_INF && x->expn == BF_EXP_INF) {+ bf_set_ui(T, 1);+ T->sign = y->sign ^ x->sign;+ } else if (y->expn == BF_EXP_ZERO && x->expn == BF_EXP_ZERO) {+ bf_set_zero(T, y->sign ^ x->sign);+ } else {+ bf_div(T, y, x, prec1, BF_RNDF);+ }+ ret = bf_atan(r, T, prec1, BF_RNDF);++ if (x->sign) {+ /* if x < 0 (it includes -0), return sign(y)*pi + atan(y/x) */+ bf_const_pi(T, prec1, BF_RNDF);+ T->sign = y->sign;+ bf_add(r, r, T, prec1, BF_RNDN);+ ret |= BF_ST_INEXACT;+ }++ bf_delete(T);+ return ret;+}++int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x,+ limb_t prec, bf_flags_t flags)+{+ return bf_ziv_rounding(r, y, prec, flags, bf_atan2_internal, (void *)x);+}++static int bf_asin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)+{+ bf_context_t *s = r->ctx;+ BOOL is_acos = (BOOL)(intptr_t)opaque;+ bf_t T_s, *T = &T_s;+ limb_t prec1, prec2;+ + /* asin(x) = atan(x/sqrt(1-x^2)) + acos(x) = pi/2 - asin(x) */+ prec1 = prec + 8;+ /* increase the precision in x^2 to compensate the cancellation in+ (1-x^2) if x is close to 1 */+ /* XXX: use less precision when possible */+ if (a->expn >= 0)+ prec2 = BF_PREC_INF;+ else+ prec2 = prec1;+ bf_init(s, T);+ bf_mul(T, a, a, prec2, BF_RNDN);+ bf_neg(T);+ bf_add_si(T, T, 1, prec2, BF_RNDN);++ bf_sqrt(r, T, prec1, BF_RNDN);+ bf_div(T, a, r, prec1, BF_RNDN);+ if (is_acos)+ bf_neg(T);+ bf_atan_internal(r, T, prec1, (void *)(intptr_t)is_acos);+ bf_delete(T);+ return BF_ST_INEXACT;+}++int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)+{+ bf_context_t *s = r->ctx;+ bf_t T_s, *T = &T_s;+ int res;++ if (a->len == 0) {+ if (a->expn == BF_EXP_NAN) {+ bf_set_nan(r);+ return 0;+ } else if (a->expn == BF_EXP_INF) {+ bf_set_nan(r);+ return BF_ST_INVALID_OP;+ } else {+ bf_set_zero(r, a->sign);+ return 0;+ }+ }+ bf_init(s, T);+ bf_set_ui(T, 1);+ res = bf_cmpu(a, T);+ bf_delete(T);+ if (res > 0) {+ bf_set_nan(r);+ return BF_ST_INVALID_OP;+ }+ + /* small argument case: result = x+r(x) with r(x) = x^3/6 ++ O(X^5). We assume r(x) < 2^(3*EXP(x) - 2). */+ if (a->expn < 0) {+ slimb_t e;+ e = sat_add(2 * a->expn, a->expn - 2);+ if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {+ bf_set(r, a);+ return bf_add_epsilon(r, r, e, a->sign, prec, flags);+ }+ }++ return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)FALSE);+}++int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)+{+ bf_context_t *s = r->ctx;+ bf_t T_s, *T = &T_s;+ int res;++ if (a->len == 0) {+ if (a->expn == BF_EXP_NAN) {+ bf_set_nan(r);+ return 0;+ } else if (a->expn == BF_EXP_INF) {+ bf_set_nan(r);+ return BF_ST_INVALID_OP;+ } else {+ bf_const_pi(r, prec, flags);+ bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ);+ return BF_ST_INEXACT;+ }+ }+ bf_init(s, T);+ bf_set_ui(T, 1);+ res = bf_cmpu(a, T);+ bf_delete(T);+ if (res > 0) {+ bf_set_nan(r);+ return BF_ST_INVALID_OP;+ } else if (res == 0 && a->sign == 0) {+ bf_set_zero(r, 0);+ return 0;+ }+ + return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)TRUE);+}++/***************************************************************/+/* decimal floating point numbers */++#ifdef USE_BF_DEC++#define adddq(r1, r0, a1, a0) \+ do { \+ limb_t __t = r0; \+ r0 += (a0); \+ r1 += (a1) + (r0 < __t); \+ } while (0)++#define subdq(r1, r0, a1, a0) \+ do { \+ limb_t __t = r0; \+ r0 -= (a0); \+ r1 -= (a1) + (r0 > __t); \+ } while (0)++#if LIMB_BITS == 64++/* Note: we assume __int128 is available */+#define muldq(r1, r0, a, b) \+ do { \+ unsigned __int128 __t; \+ __t = (unsigned __int128)(a) * (unsigned __int128)(b); \+ r0 = __t; \+ r1 = __t >> 64; \+ } while (0)++#define divdq(q, r, a1, a0, b) \+ do { \+ unsigned __int128 __t; \+ limb_t __b = (b); \+ __t = ((unsigned __int128)(a1) << 64) | (a0); \+ q = __t / __b; \+ r = __t % __b; \+ } while (0)++#else++#define muldq(r1, r0, a, b) \+ do { \+ uint64_t __t; \+ __t = (uint64_t)(a) * (uint64_t)(b); \+ r0 = __t; \+ r1 = __t >> 32; \+ } while (0)++#define divdq(q, r, a1, a0, b) \+ do { \+ uint64_t __t; \+ limb_t __b = (b); \+ __t = ((uint64_t)(a1) << 32) | (a0); \+ q = __t / __b; \+ r = __t % __b; \+ } while (0)++#endif /* LIMB_BITS != 64 */++static inline __maybe_unused limb_t shrd(limb_t low, limb_t high, long shift)+{+ if (shift != 0)+ low = (low >> shift) | (high << (LIMB_BITS - shift));+ return low;+}++static inline __maybe_unused limb_t shld(limb_t a1, limb_t a0, long shift)+{+ if (shift != 0)+ return (a1 << shift) | (a0 >> (LIMB_BITS - shift));+ else+ return a1;+}++#if LIMB_DIGITS == 19++/* WARNING: hardcoded for b = 1e19. It is assumed that:+ 0 <= a1 < 2^63 */+#define divdq_base(q, r, a1, a0)\+do {\+ uint64_t __a0, __a1, __t0, __t1, __b = BF_DEC_BASE; \+ __a0 = a0;\+ __a1 = a1;\+ __t0 = __a1;\+ __t0 = shld(__t0, __a0, 1);\+ muldq(q, __t1, __t0, UINT64_C(17014118346046923173)); \+ muldq(__t1, __t0, q, __b);\+ subdq(__a1, __a0, __t1, __t0);\+ subdq(__a1, __a0, 1, __b * 2); \+ __t0 = (slimb_t)__a1 >> 1; \+ q += 2 + __t0;\+ adddq(__a1, __a0, 0, __b & __t0);\+ q += __a1; \+ __a0 += __b & __a1; \+ r = __a0;\+} while(0)++#elif LIMB_DIGITS == 9++/* WARNING: hardcoded for b = 1e9. It is assumed that:+ 0 <= a1 < 2^29 */+#define divdq_base(q, r, a1, a0)\+do {\+ uint32_t __t0, __t1, __b = BF_DEC_BASE; \+ __t0 = a1;\+ __t1 = a0;\+ __t0 = (__t0 << 3) | (__t1 >> (32 - 3)); \+ muldq(q, __t1, __t0, 2305843009U);\+ r = a0 - q * __b;\+ __t1 = (r >= __b);\+ q += __t1;\+ if (__t1)\+ r -= __b;\+} while(0)++#endif++/* fast integer division by a fixed constant */++typedef struct FastDivData {+ limb_t m1; /* multiplier */+ int8_t shift1;+ int8_t shift2;+} FastDivData;++/* From "Division by Invariant Integers using Multiplication" by+ Torborn Granlund and Peter L. Montgomery */+/* d must be != 0 */+static inline __maybe_unused void fast_udiv_init(FastDivData *s, limb_t d)+{+ int l;+ limb_t q, r, m1;+ if (d == 1)+ l = 0;+ else+ l = 64 - clz64(d - 1);+ divdq(q, r, ((limb_t)1 << l) - d, 0, d);+ (void)r;+ m1 = q + 1;+ // printf("d=%lu l=%d m1=0x%016lx\n", d, l, m1);+ s->m1 = m1;+ s->shift1 = l;+ if (s->shift1 > 1)+ s->shift1 = 1;+ s->shift2 = l - 1;+ if (s->shift2 < 0)+ s->shift2 = 0;+}++static inline limb_t fast_udiv(limb_t a, const FastDivData *s)+{+ limb_t t0, t1;+ muldq(t1, t0, s->m1, a);+ t0 = (a - t1) >> s->shift1;+ return (t1 + t0) >> s->shift2;+}++/* contains 10^i */+const limb_t mp_pow_dec[LIMB_DIGITS + 1] = {+ 1U,+ 10U,+ 100U,+ 1000U,+ 10000U,+ 100000U,+ 1000000U,+ 10000000U,+ 100000000U,+ 1000000000U,+#if LIMB_BITS == 64+ 10000000000U,+ 100000000000U,+ 1000000000000U,+ 10000000000000U,+ 100000000000000U,+ 1000000000000000U,+ 10000000000000000U,+ 100000000000000000U,+ 1000000000000000000U,+ 10000000000000000000U,+#endif+};++/* precomputed from fast_udiv_init(10^i) */+static const FastDivData mp_pow_div[LIMB_DIGITS + 1] = {+#if LIMB_BITS == 32+ { 0x00000001, 0, 0 },+ { 0x9999999a, 1, 3 },+ { 0x47ae147b, 1, 6 },+ { 0x0624dd30, 1, 9 },+ { 0xa36e2eb2, 1, 13 },+ { 0x4f8b588f, 1, 16 },+ { 0x0c6f7a0c, 1, 19 },+ { 0xad7f29ac, 1, 23 },+ { 0x5798ee24, 1, 26 },+ { 0x12e0be83, 1, 29 },+#else+ { 0x0000000000000001, 0, 0 },+ { 0x999999999999999a, 1, 3 },+ { 0x47ae147ae147ae15, 1, 6 },+ { 0x0624dd2f1a9fbe77, 1, 9 },+ { 0xa36e2eb1c432ca58, 1, 13 },+ { 0x4f8b588e368f0847, 1, 16 },+ { 0x0c6f7a0b5ed8d36c, 1, 19 },+ { 0xad7f29abcaf48579, 1, 23 },+ { 0x5798ee2308c39dfa, 1, 26 },+ { 0x12e0be826d694b2f, 1, 29 },+ { 0xb7cdfd9d7bdbab7e, 1, 33 },+ { 0x5fd7fe17964955fe, 1, 36 },+ { 0x19799812dea11198, 1, 39 },+ { 0xc25c268497681c27, 1, 43 },+ { 0x6849b86a12b9b01f, 1, 46 },+ { 0x203af9ee756159b3, 1, 49 },+ { 0xcd2b297d889bc2b7, 1, 53 },+ { 0x70ef54646d496893, 1, 56 },+ { 0x2725dd1d243aba0f, 1, 59 },+ { 0xd83c94fb6d2ac34d, 1, 63 },+#endif+};++/* divide by 10^shift with 0 <= shift <= LIMB_DIGITS */+static inline limb_t fast_shr_dec(limb_t a, int shift)+{+ return fast_udiv(a, &mp_pow_div[shift]);+}++/* division and remainder by 10^shift */+#define fast_shr_rem_dec(q, r, a, shift) q = fast_shr_dec(a, shift), r = a - q * mp_pow_dec[shift]+ +limb_t mp_add_dec(limb_t *res, const limb_t *op1, const limb_t *op2, + mp_size_t n, limb_t carry)+{+ limb_t base = BF_DEC_BASE;+ mp_size_t i;+ limb_t k, a, v;++ k=carry;+ for(i=0;i<n;i++) {+ /* XXX: reuse the trick in add_mod */+ v = op1[i];+ a = v + op2[i] + k - base;+ k = a <= v;+ if (!k) + a += base;+ res[i]=a;+ }+ return k;+}++limb_t mp_add_ui_dec(limb_t *tab, limb_t b, mp_size_t n)+{+ limb_t base = BF_DEC_BASE;+ mp_size_t i;+ limb_t k, a, v;++ k=b;+ for(i=0;i<n;i++) {+ v = tab[i];+ a = v + k - base;+ k = a <= v;+ if (!k) + a += base;+ tab[i] = a;+ if (k == 0)+ break;+ }+ return k;+}++limb_t mp_sub_dec(limb_t *res, const limb_t *op1, const limb_t *op2, + mp_size_t n, limb_t carry)+{+ limb_t base = BF_DEC_BASE;+ mp_size_t i;+ limb_t k, v, a;++ k=carry;+ for(i=0;i<n;i++) {+ v = op1[i];+ a = v - op2[i] - k;+ k = a > v;+ if (k)+ a += base;+ res[i] = a;+ }+ return k;+}++limb_t mp_sub_ui_dec(limb_t *tab, limb_t b, mp_size_t n)+{+ limb_t base = BF_DEC_BASE;+ mp_size_t i;+ limb_t k, v, a;+ + k=b;+ for(i=0;i<n;i++) {+ v = tab[i];+ a = v - k;+ k = a > v;+ if (k)+ a += base;+ tab[i]=a;+ if (k == 0)+ break;+ }+ return k;+}++/* taba[] = taba[] * b + l. 0 <= b, l <= base - 1. Return the high carry */+limb_t mp_mul1_dec(limb_t *tabr, const limb_t *taba, mp_size_t n, + limb_t b, limb_t l)+{+ mp_size_t i;+ limb_t t0, t1, r;++ for(i = 0; i < n; i++) {+ muldq(t1, t0, taba[i], b);+ adddq(t1, t0, 0, l);+ divdq_base(l, r, t1, t0);+ tabr[i] = r;+ }+ return l;+}++/* tabr[] += taba[] * b. 0 <= b <= base - 1. Return the value to add+ to the high word */+limb_t mp_add_mul1_dec(limb_t *tabr, const limb_t *taba, mp_size_t n,+ limb_t b)+{+ mp_size_t i;+ limb_t l, t0, t1, r;++ l = 0;+ for(i = 0; i < n; i++) {+ muldq(t1, t0, taba[i], b);+ adddq(t1, t0, 0, l);+ adddq(t1, t0, 0, tabr[i]);+ divdq_base(l, r, t1, t0);+ tabr[i] = r;+ }+ return l;+}++/* tabr[] -= taba[] * b. 0 <= b <= base - 1. Return the value to+ substract to the high word. */+limb_t mp_sub_mul1_dec(limb_t *tabr, const limb_t *taba, mp_size_t n,+ limb_t b)+{+ limb_t base = BF_DEC_BASE;+ mp_size_t i;+ limb_t l, t0, t1, r, a, v, c;++ /* XXX: optimize */+ l = 0;+ for(i = 0; i < n; i++) {+ muldq(t1, t0, taba[i], b);+ adddq(t1, t0, 0, l);+ divdq_base(l, r, t1, t0);+ v = tabr[i];+ a = v - r;+ c = a > v;+ if (c)+ a += base;+ /* never bigger than base because r = 0 when l = base - 1 */+ l += c;+ tabr[i] = a;+ }+ return l;+}++/* size of the result : op1_size + op2_size. */+void mp_mul_basecase_dec(limb_t *result, + const limb_t *op1, mp_size_t op1_size, + const limb_t *op2, mp_size_t op2_size) +{+ mp_size_t i;+ limb_t r;+ + result[op1_size] = mp_mul1_dec(result, op1, op1_size, op2[0], 0);++ for(i=1;i<op2_size;i++) {+ r = mp_add_mul1_dec(result + i, op1, op1_size, op2[i]);+ result[i + op1_size] = r;+ }+}++/* taba[] = (taba[] + r*base^na) / b. 0 <= b < base. 0 <= r <+ b. Return the remainder. */+limb_t mp_div1_dec(limb_t *tabr, const limb_t *taba, mp_size_t na, + limb_t b, limb_t r)+{+ limb_t base = BF_DEC_BASE;+ mp_size_t i;+ limb_t t0, t1, q;+ int shift;++#if (BF_DEC_BASE % 2) == 0+ if (b == 2) {+ limb_t base_div2;+ /* Note: only works if base is even */+ base_div2 = base >> 1;+ if (r)+ r = base_div2;+ for(i = na - 1; i >= 0; i--) {+ t0 = taba[i];+ tabr[i] = (t0 >> 1) + r;+ r = 0;+ if (t0 & 1)+ r = base_div2;+ }+ if (r)+ r = 1;+ } else +#endif+ if (na >= UDIV1NORM_THRESHOLD) {+ shift = clz(b);+ if (shift == 0) {+ /* normalized case: b >= 2^(LIMB_BITS-1) */+ limb_t b_inv;+ b_inv = udiv1norm_init(b);+ for(i = na - 1; i >= 0; i--) {+ muldq(t1, t0, r, base);+ adddq(t1, t0, 0, taba[i]);+ q = udiv1norm(&r, t1, t0, b, b_inv);+ tabr[i] = q;+ }+ } else {+ limb_t b_inv;+ b <<= shift;+ b_inv = udiv1norm_init(b);+ for(i = na - 1; i >= 0; i--) {+ muldq(t1, t0, r, base);+ adddq(t1, t0, 0, taba[i]);+ t1 = (t1 << shift) | (t0 >> (LIMB_BITS - shift));+ t0 <<= shift;+ q = udiv1norm(&r, t1, t0, b, b_inv);+ r >>= shift;+ tabr[i] = q;+ }+ }+ } else {+ for(i = na - 1; i >= 0; i--) {+ muldq(t1, t0, r, base);+ adddq(t1, t0, 0, taba[i]);+ divdq(q, r, t1, t0, b);+ tabr[i] = q;+ }+ }+ return r;+}++static __maybe_unused void mp_print_str_dec(const char *str,+ const limb_t *tab, slimb_t n)+{+ slimb_t i;+ printf("%s=", str);+ for(i = n - 1; i >= 0; i--) {+ if (i != n - 1)+ printf("_");+ printf("%0*" PRIu_LIMB, LIMB_DIGITS, tab[i]);+ }+ printf("\n");+}++static __maybe_unused void mp_print_str_h_dec(const char *str,+ const limb_t *tab, slimb_t n,+ limb_t high)+{+ slimb_t i;+ printf("%s=", str);+ printf("%0*" PRIu_LIMB, LIMB_DIGITS, high);+ for(i = n - 1; i >= 0; i--) {+ printf("_");+ printf("%0*" PRIu_LIMB, LIMB_DIGITS, tab[i]);+ }+ printf("\n");+}++//#define DEBUG_DIV_SLOW++#define DIV_STATIC_ALLOC_LEN 16++/* return q = a / b and r = a % b. ++ taba[na] must be allocated if tabb1[nb - 1] < B / 2. tabb1[nb - 1]+ must be != zero. na must be >= nb. 's' can be NULL if tabb1[nb - 1]+ >= B / 2.++ The remainder is is returned in taba and contains nb libms. tabq+ contains na - nb + 1 limbs. No overlap is permitted.++ Running time of the standard method: (na - nb + 1) * nb+ Return 0 if OK, -1 if memory alloc error+*/+/* XXX: optimize */+static int mp_div_dec(bf_context_t *s, limb_t *tabq,+ limb_t *taba, mp_size_t na, + const limb_t *tabb1, mp_size_t nb)+{+ limb_t base = BF_DEC_BASE;+ limb_t r, mult, t0, t1, a, c, q, v, *tabb;+ mp_size_t i, j;+ limb_t static_tabb[DIV_STATIC_ALLOC_LEN];+ +#ifdef DEBUG_DIV_SLOW+ mp_print_str_dec("a", taba, na);+ mp_print_str_dec("b", tabb1, nb);+#endif++ /* normalize tabb */+ r = tabb1[nb - 1];+ assert(r != 0);+ i = na - nb;+ if (r >= BF_DEC_BASE / 2) {+ mult = 1;+ tabb = (limb_t *)tabb1;+ q = 1;+ for(j = nb - 1; j >= 0; j--) {+ if (taba[i + j] != tabb[j]) {+ if (taba[i + j] < tabb[j])+ q = 0;+ break;+ }+ }+ tabq[i] = q;+ if (q) {+ mp_sub_dec(taba + i, taba + i, tabb, nb, 0);+ }+ i--;+ } else {+ mult = base / (r + 1);+ if (likely(nb <= DIV_STATIC_ALLOC_LEN)) {+ tabb = static_tabb;+ } else {+ tabb = bf_malloc(s, sizeof(limb_t) * nb);+ if (!tabb)+ return -1;+ }+ mp_mul1_dec(tabb, tabb1, nb, mult, 0);+ taba[na] = mp_mul1_dec(taba, taba, na, mult, 0);+ }++#ifdef DEBUG_DIV_SLOW+ printf("mult=" FMT_LIMB "\n", mult);+ mp_print_str_dec("a_norm", taba, na + 1);+ mp_print_str_dec("b_norm", tabb, nb);+#endif++ for(; i >= 0; i--) {+ if (unlikely(taba[i + nb] >= tabb[nb - 1])) {+ /* XXX: check if it is really possible */+ q = base - 1;+ } else {+ muldq(t1, t0, taba[i + nb], base);+ adddq(t1, t0, 0, taba[i + nb - 1]);+ divdq(q, r, t1, t0, tabb[nb - 1]);+ }+ // printf("i=%d q1=%ld\n", i, q);++ r = mp_sub_mul1_dec(taba + i, tabb, nb, q);+ // mp_dump("r1", taba + i, nb, bd);+ // printf("r2=%ld\n", r);++ v = taba[i + nb];+ a = v - r;+ c = a > v;+ if (c)+ a += base;+ taba[i + nb] = a;++ if (c != 0) {+ /* negative result */+ for(;;) {+ q--;+ c = mp_add_dec(taba + i, taba + i, tabb, nb, 0);+ /* propagate carry and test if positive result */+ if (c != 0) {+ if (++taba[i + nb] == base) {+ break;+ }+ }+ }+ }+ tabq[i] = q;+ }++#ifdef DEBUG_DIV_SLOW+ mp_print_str_dec("q", tabq, na - nb + 1);+ mp_print_str_dec("r", taba, nb);+#endif++ /* remove the normalization */+ if (mult != 1) {+ mp_div1_dec(taba, taba, nb, mult, 0);+ if (unlikely(tabb != static_tabb))+ bf_free(s, tabb);+ }+ return 0;+}++/* divide by 10^shift */+static limb_t mp_shr_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n, + limb_t shift, limb_t high)+{+ mp_size_t i;+ limb_t l, a, q, r;++ assert(shift >= 1 && shift < LIMB_DIGITS);+ l = high;+ for(i = n - 1; i >= 0; i--) {+ a = tab[i];+ fast_shr_rem_dec(q, r, a, shift);+ tab_r[i] = q + l * mp_pow_dec[LIMB_DIGITS - shift];+ l = r;+ }+ return l;+}++/* multiply by 10^shift */+static limb_t mp_shl_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n, + limb_t shift, limb_t low)+{+ mp_size_t i;+ limb_t l, a, q, r;++ assert(shift >= 1 && shift < LIMB_DIGITS);+ l = low;+ for(i = 0; i < n; i++) {+ a = tab[i];+ fast_shr_rem_dec(q, r, a, LIMB_DIGITS - shift);+ tab_r[i] = r * mp_pow_dec[shift] + l;+ l = q;+ }+ return l;+}++static limb_t mp_sqrtrem2_dec(limb_t *tabs, limb_t *taba)+{+ int k;+ dlimb_t a, b, r;+ limb_t taba1[2], s, r0, r1;++ /* convert to binary and normalize */+ a = (dlimb_t)taba[1] * BF_DEC_BASE + taba[0];+ k = clz(a >> LIMB_BITS) & ~1;+ b = a << k;+ taba1[0] = b;+ taba1[1] = b >> LIMB_BITS;+ mp_sqrtrem2(&s, taba1);+ s >>= (k >> 1);+ /* convert the remainder back to decimal */+ r = a - (dlimb_t)s * (dlimb_t)s;+ divdq_base(r1, r0, r >> LIMB_BITS, r);+ taba[0] = r0;+ tabs[0] = s;+ return r1;+}++//#define DEBUG_SQRTREM_DEC++/* tmp_buf must contain (n / 2 + 1 limbs) */+static limb_t mp_sqrtrem_rec_dec(limb_t *tabs, limb_t *taba, limb_t n,+ limb_t *tmp_buf)+{+ limb_t l, h, rh, ql, qh, c, i;+ + if (n == 1)+ return mp_sqrtrem2_dec(tabs, taba);+#ifdef DEBUG_SQRTREM_DEC+ mp_print_str_dec("a", taba, 2 * n);+#endif+ l = n / 2;+ h = n - l;+ qh = mp_sqrtrem_rec_dec(tabs + l, taba + 2 * l, h, tmp_buf);+#ifdef DEBUG_SQRTREM_DEC+ mp_print_str_dec("s1", tabs + l, h);+ mp_print_str_h_dec("r1", taba + 2 * l, h, qh);+ mp_print_str_h_dec("r2", taba + l, n, qh);+#endif+ + /* the remainder is in taba + 2 * l. Its high bit is in qh */+ if (qh) {+ mp_sub_dec(taba + 2 * l, taba + 2 * l, tabs + l, h, 0);+ }+ /* instead of dividing by 2*s, divide by s (which is normalized)+ and update q and r */+ mp_div_dec(NULL, tmp_buf, taba + l, n, tabs + l, h);+ qh += tmp_buf[l];+ for(i = 0; i < l; i++)+ tabs[i] = tmp_buf[i];+ ql = mp_div1_dec(tabs, tabs, l, 2, qh & 1);+ qh = qh >> 1; /* 0 or 1 */+ if (ql)+ rh = mp_add_dec(taba + l, taba + l, tabs + l, h, 0);+ else+ rh = 0;+#ifdef DEBUG_SQRTREM_DEC+ mp_print_str_h_dec("q", tabs, l, qh);+ mp_print_str_h_dec("u", taba + l, h, rh);+#endif+ + mp_add_ui_dec(tabs + l, qh, h);+#ifdef DEBUG_SQRTREM_DEC+ mp_print_str_dec("s2", tabs, n);+#endif+ + /* q = qh, tabs[l - 1 ... 0], r = taba[n - 1 ... l] */+ /* subtract q^2. if qh = 1 then q = B^l, so we can take shortcuts */+ if (qh) {+ c = qh;+ } else {+ mp_mul_basecase_dec(taba + n, tabs, l, tabs, l);+ c = mp_sub_dec(taba, taba, taba + n, 2 * l, 0);+ }+ rh -= mp_sub_ui_dec(taba + 2 * l, c, n - 2 * l);+ if ((slimb_t)rh < 0) {+ mp_sub_ui_dec(tabs, 1, n);+ rh += mp_add_mul1_dec(taba, tabs, n, 2);+ rh += mp_add_ui_dec(taba, 1, n);+ }+ return rh;+}++/* 'taba' has 2*n limbs with n >= 1 and taba[2*n-1] >= B/4. Return (s,+ r) with s=floor(sqrt(a)) and r=a-s^2. 0 <= r <= 2 * s. tabs has n+ limbs. r is returned in the lower n limbs of taba. Its r[n] is the+ returned value of the function. */+int mp_sqrtrem_dec(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n)+{+ limb_t tmp_buf1[8];+ limb_t *tmp_buf;+ mp_size_t n2;+ n2 = n / 2 + 1;+ if (n2 <= countof(tmp_buf1)) {+ tmp_buf = tmp_buf1;+ } else {+ tmp_buf = bf_malloc(s, sizeof(limb_t) * n2);+ if (!tmp_buf)+ return -1;+ }+ taba[n] = mp_sqrtrem_rec_dec(tabs, taba, n, tmp_buf);+ if (tmp_buf != tmp_buf1)+ bf_free(s, tmp_buf);+ return 0;+}++/* return the number of leading zero digits, from 0 to LIMB_DIGITS */+static int clz_dec(limb_t a)+{+ if (a == 0)+ return LIMB_DIGITS;+ switch(LIMB_BITS - 1 - clz(a)) {+ case 0: /* 1-1 */+ return LIMB_DIGITS - 1;+ case 1: /* 2-3 */+ return LIMB_DIGITS - 1;+ case 2: /* 4-7 */+ return LIMB_DIGITS - 1;+ case 3: /* 8-15 */+ if (a < 10)+ return LIMB_DIGITS - 1;+ else+ return LIMB_DIGITS - 2;+ case 4: /* 16-31 */+ return LIMB_DIGITS - 2;+ case 5: /* 32-63 */+ return LIMB_DIGITS - 2;+ case 6: /* 64-127 */+ if (a < 100)+ return LIMB_DIGITS - 2;+ else+ return LIMB_DIGITS - 3;+ case 7: /* 128-255 */+ return LIMB_DIGITS - 3;+ case 8: /* 256-511 */+ return LIMB_DIGITS - 3;+ case 9: /* 512-1023 */+ if (a < 1000)+ return LIMB_DIGITS - 3;+ else+ return LIMB_DIGITS - 4;+ case 10: /* 1024-2047 */+ return LIMB_DIGITS - 4;+ case 11: /* 2048-4095 */+ return LIMB_DIGITS - 4;+ case 12: /* 4096-8191 */+ return LIMB_DIGITS - 4;+ case 13: /* 8192-16383 */+ if (a < 10000)+ return LIMB_DIGITS - 4;+ else+ return LIMB_DIGITS - 5;+ case 14: /* 16384-32767 */+ return LIMB_DIGITS - 5;+ case 15: /* 32768-65535 */+ return LIMB_DIGITS - 5;+ case 16: /* 65536-131071 */+ if (a < 100000)+ return LIMB_DIGITS - 5;+ else+ return LIMB_DIGITS - 6;+ case 17: /* 131072-262143 */+ return LIMB_DIGITS - 6;+ case 18: /* 262144-524287 */+ return LIMB_DIGITS - 6;+ case 19: /* 524288-1048575 */+ if (a < 1000000)+ return LIMB_DIGITS - 6;+ else+ return LIMB_DIGITS - 7;+ case 20: /* 1048576-2097151 */+ return LIMB_DIGITS - 7;+ case 21: /* 2097152-4194303 */+ return LIMB_DIGITS - 7;+ case 22: /* 4194304-8388607 */+ return LIMB_DIGITS - 7;+ case 23: /* 8388608-16777215 */+ if (a < 10000000)+ return LIMB_DIGITS - 7;+ else+ return LIMB_DIGITS - 8;+ case 24: /* 16777216-33554431 */+ return LIMB_DIGITS - 8;+ case 25: /* 33554432-67108863 */+ return LIMB_DIGITS - 8;+ case 26: /* 67108864-134217727 */+ if (a < 100000000)+ return LIMB_DIGITS - 8;+ else+ return LIMB_DIGITS - 9;+#if LIMB_BITS == 64+ case 27: /* 134217728-268435455 */+ return LIMB_DIGITS - 9;+ case 28: /* 268435456-536870911 */+ return LIMB_DIGITS - 9;+ case 29: /* 536870912-1073741823 */+ if (a < 1000000000)+ return LIMB_DIGITS - 9;+ else+ return LIMB_DIGITS - 10;+ case 30: /* 1073741824-2147483647 */+ return LIMB_DIGITS - 10;+ case 31: /* 2147483648-4294967295 */+ return LIMB_DIGITS - 10;+ case 32: /* 4294967296-8589934591 */+ return LIMB_DIGITS - 10;+ case 33: /* 8589934592-17179869183 */+ if (a < 10000000000)+ return LIMB_DIGITS - 10;+ else+ return LIMB_DIGITS - 11;+ case 34: /* 17179869184-34359738367 */+ return LIMB_DIGITS - 11;+ case 35: /* 34359738368-68719476735 */+ return LIMB_DIGITS - 11;+ case 36: /* 68719476736-137438953471 */+ if (a < 100000000000)+ return LIMB_DIGITS - 11;+ else+ return LIMB_DIGITS - 12;+ case 37: /* 137438953472-274877906943 */+ return LIMB_DIGITS - 12;+ case 38: /* 274877906944-549755813887 */+ return LIMB_DIGITS - 12;+ case 39: /* 549755813888-1099511627775 */+ if (a < 1000000000000)+ return LIMB_DIGITS - 12;+ else+ return LIMB_DIGITS - 13;+ case 40: /* 1099511627776-2199023255551 */+ return LIMB_DIGITS - 13;+ case 41: /* 2199023255552-4398046511103 */+ return LIMB_DIGITS - 13;+ case 42: /* 4398046511104-8796093022207 */+ return LIMB_DIGITS - 13;+ case 43: /* 8796093022208-17592186044415 */+ if (a < 10000000000000)+ return LIMB_DIGITS - 13;+ else+ return LIMB_DIGITS - 14;+ case 44: /* 17592186044416-35184372088831 */+ return LIMB_DIGITS - 14;+ case 45: /* 35184372088832-70368744177663 */+ return LIMB_DIGITS - 14;+ case 46: /* 70368744177664-140737488355327 */+ if (a < 100000000000000)+ return LIMB_DIGITS - 14;+ else+ return LIMB_DIGITS - 15;+ case 47: /* 140737488355328-281474976710655 */+ return LIMB_DIGITS - 15;+ case 48: /* 281474976710656-562949953421311 */+ return LIMB_DIGITS - 15;+ case 49: /* 562949953421312-1125899906842623 */+ if (a < 1000000000000000)+ return LIMB_DIGITS - 15;+ else+ return LIMB_DIGITS - 16;+ case 50: /* 1125899906842624-2251799813685247 */+ return LIMB_DIGITS - 16;+ case 51: /* 2251799813685248-4503599627370495 */+ return LIMB_DIGITS - 16;+ case 52: /* 4503599627370496-9007199254740991 */+ return LIMB_DIGITS - 16;+ case 53: /* 9007199254740992-18014398509481983 */+ if (a < 10000000000000000)+ return LIMB_DIGITS - 16;+ else+ return LIMB_DIGITS - 17;+ case 54: /* 18014398509481984-36028797018963967 */+ return LIMB_DIGITS - 17;+ case 55: /* 36028797018963968-72057594037927935 */+ return LIMB_DIGITS - 17;+ case 56: /* 72057594037927936-144115188075855871 */+ if (a < 100000000000000000)+ return LIMB_DIGITS - 17;+ else+ return LIMB_DIGITS - 18;+ case 57: /* 144115188075855872-288230376151711743 */+ return LIMB_DIGITS - 18;+ case 58: /* 288230376151711744-576460752303423487 */+ return LIMB_DIGITS - 18;+ case 59: /* 576460752303423488-1152921504606846975 */+ if (a < 1000000000000000000)+ return LIMB_DIGITS - 18;+ else+ return LIMB_DIGITS - 19;+#endif+ default:+ return 0;+ }+}++/* for debugging */+void bfdec_print_str(const char *str, const bfdec_t *a)+{+ slimb_t i;+ printf("%s=", str);++ if (a->expn == BF_EXP_NAN) {+ printf("NaN");+ } else {+ if (a->sign)+ putchar('-');+ if (a->expn == BF_EXP_ZERO) {+ putchar('0');+ } else if (a->expn == BF_EXP_INF) {+ printf("Inf");+ } else {+ printf("0.");+ for(i = a->len - 1; i >= 0; i--)+ printf("%0*" PRIu_LIMB, LIMB_DIGITS, a->tab[i]);+ printf("e%" PRId_LIMB, a->expn);+ }+ }+ printf("\n");+}++/* return != 0 if one digit between 0 and bit_pos inclusive is not zero. */+static inline limb_t scan_digit_nz(const bfdec_t *r, slimb_t bit_pos)+{+ slimb_t pos;+ limb_t v, q;+ int shift;++ if (bit_pos < 0)+ return 0;+ pos = (limb_t)bit_pos / LIMB_DIGITS;+ shift = (limb_t)bit_pos % LIMB_DIGITS;+ fast_shr_rem_dec(q, v, r->tab[pos], shift + 1);+ (void)q;+ if (v != 0)+ return 1;+ pos--;+ while (pos >= 0) {+ if (r->tab[pos] != 0)+ return 1;+ pos--;+ }+ return 0;+}++static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos)+{+ slimb_t i;+ int shift;+ i = floor_div(pos, LIMB_DIGITS);+ if (i < 0 || i >= len)+ return 0;+ shift = pos - i * LIMB_DIGITS;+ return fast_shr_dec(tab[i], shift) % 10;+}++#if 0+static limb_t get_digits(const limb_t *tab, limb_t len, slimb_t pos)+{+ limb_t a0, a1;+ int shift;+ slimb_t i;+ + i = floor_div(pos, LIMB_DIGITS);+ shift = pos - i * LIMB_DIGITS;+ if (i >= 0 && i < len)+ a0 = tab[i];+ else+ a0 = 0;+ if (shift == 0) {+ return a0;+ } else {+ i++;+ if (i >= 0 && i < len)+ a1 = tab[i];+ else+ a1 = 0;+ return fast_shr_dec(a0, shift) ++ fast_urem(a1, &mp_pow_div[LIMB_DIGITS - shift]) *+ mp_pow_dec[shift];+ }+}+#endif++/* return the addend for rounding. Note that prec can be <= 0 for bf_rint() */+static int bfdec_get_rnd_add(int *pret, const bfdec_t *r, limb_t l,+ slimb_t prec, int rnd_mode)+{+ int add_one, inexact;+ limb_t digit1, digit0;+ + // bfdec_print_str("get_rnd_add", r);+ if (rnd_mode == BF_RNDF) {+ digit0 = 1; /* faithful rounding does not honor the INEXACT flag */+ } else {+ /* starting limb for bit 'prec + 1' */+ digit0 = scan_digit_nz(r, l * LIMB_DIGITS - 1 - bf_max(0, prec + 1));+ }++ /* get the digit at 'prec' */+ digit1 = get_digit(r->tab, l, l * LIMB_DIGITS - 1 - prec);+ inexact = (digit1 | digit0) != 0;+ + add_one = 0;+ switch(rnd_mode) {+ case BF_RNDZ:+ break;+ case BF_RNDN:+ if (digit1 == 5) {+ if (digit0) {+ add_one = 1;+ } else {+ /* round to even */+ add_one =+ get_digit(r->tab, l, l * LIMB_DIGITS - 1 - (prec - 1)) & 1;+ }+ } else if (digit1 > 5) {+ add_one = 1;+ }+ break;+ case BF_RNDD:+ case BF_RNDU:+ if (r->sign == (rnd_mode == BF_RNDD))+ add_one = inexact;+ break;+ case BF_RNDNA:+ case BF_RNDF:+ add_one = (digit1 >= 5);+ break;+ case BF_RNDA:+ add_one = inexact;+ break;+ default:+ abort();+ }+ + if (inexact)+ *pret |= BF_ST_INEXACT;+ return add_one;+}++/* round to prec1 bits assuming 'r' is non zero and finite. 'r' is+ assumed to have length 'l' (1 <= l <= r->len). prec1 can be+ BF_PREC_INF. BF_FLAG_SUBNORMAL is not supported. Cannot fail with+ BF_ST_MEM_ERROR.+ */+static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l)+{+ int shift, add_one, rnd_mode, ret;+ slimb_t i, bit_pos, pos, e_min, e_max, e_range, prec;++ /* XXX: align to IEEE 754 2008 for decimal numbers ? */+ e_range = (limb_t)1 << (bf_get_exp_bits(flags) - 1);+ e_min = -e_range + 3;+ e_max = e_range;+ + if (flags & BF_FLAG_RADPNT_PREC) {+ /* 'prec' is the precision after the decimal point */+ if (prec1 != BF_PREC_INF)+ prec = r->expn + prec1;+ else+ prec = prec1;+ } else if (unlikely(r->expn < e_min) && (flags & BF_FLAG_SUBNORMAL)) {+ /* restrict the precision in case of potentially subnormal+ result */+ assert(prec1 != BF_PREC_INF);+ prec = prec1 - (e_min - r->expn);+ } else {+ prec = prec1;+ }+ + /* round to prec bits */+ rnd_mode = flags & BF_RND_MASK;+ ret = 0;+ add_one = bfdec_get_rnd_add(&ret, r, l, prec, rnd_mode);+ + if (prec <= 0) {+ if (add_one) {+ bfdec_resize(r, 1); /* cannot fail because r is non zero */+ r->tab[0] = BF_DEC_BASE / 10;+ r->expn += 1 - prec;+ ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;+ return ret;+ } else {+ goto underflow;+ }+ } else if (add_one) {+ limb_t carry;+ + /* add one starting at digit 'prec - 1' */+ bit_pos = l * LIMB_DIGITS - 1 - (prec - 1);+ pos = bit_pos / LIMB_DIGITS;+ carry = mp_pow_dec[bit_pos % LIMB_DIGITS];+ carry = mp_add_ui_dec(r->tab + pos, carry, l - pos);+ if (carry) {+ /* shift right by one digit */+ mp_shr_dec(r->tab + pos, r->tab + pos, l - pos, 1, 1);+ r->expn++;+ }+ }+ + /* check underflow */+ if (unlikely(r->expn < e_min)) {+ if (flags & BF_FLAG_SUBNORMAL) {+ /* if inexact, also set the underflow flag */+ if (ret & BF_ST_INEXACT)+ ret |= BF_ST_UNDERFLOW;+ } else {+ underflow:+ bfdec_set_zero(r, r->sign);+ ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;+ return ret;+ }+ }+ + /* check overflow */+ if (unlikely(r->expn > e_max)) {+ bfdec_set_inf(r, r->sign);+ ret |= BF_ST_OVERFLOW | BF_ST_INEXACT;+ return ret;+ }+ + /* keep the bits starting at 'prec - 1' */+ bit_pos = l * LIMB_DIGITS - 1 - (prec - 1);+ i = floor_div(bit_pos, LIMB_DIGITS);+ if (i >= 0) {+ shift = smod(bit_pos, LIMB_DIGITS);+ if (shift != 0) {+ r->tab[i] = fast_shr_dec(r->tab[i], shift) *+ mp_pow_dec[shift];+ }+ } else {+ i = 0;+ }+ /* remove trailing zeros */+ while (r->tab[i] == 0)+ i++;+ if (i > 0) {+ l -= i;+ memmove(r->tab, r->tab + i, l * sizeof(limb_t));+ }+ bfdec_resize(r, l); /* cannot fail */+ return ret;+}++/* Cannot fail with BF_ST_MEM_ERROR. */+int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags)+{+ if (r->len == 0)+ return 0;+ return __bfdec_round(r, prec, flags, r->len);+}++/* 'r' must be a finite number. Cannot fail with BF_ST_MEM_ERROR. */+int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags)+{+ limb_t l, v;+ int shift, ret;+ + // bfdec_print_str("bf_renorm", r);+ l = r->len;+ while (l > 0 && r->tab[l - 1] == 0)+ l--;+ if (l == 0) {+ /* zero */+ r->expn = BF_EXP_ZERO;+ bfdec_resize(r, 0); /* cannot fail */+ ret = 0;+ } else {+ r->expn -= (r->len - l) * LIMB_DIGITS;+ /* shift to have the MSB set to '1' */+ v = r->tab[l - 1];+ shift = clz_dec(v);+ if (shift != 0) {+ mp_shl_dec(r->tab, r->tab, l, shift, 0);+ r->expn -= shift;+ }+ ret = __bfdec_round(r, prec1, flags, l);+ }+ // bf_print_str("r_final", r);+ return ret;+}++int bfdec_set_ui(bfdec_t *r, uint64_t v)+{+#if LIMB_BITS == 32+ if (v >= BF_DEC_BASE * BF_DEC_BASE) {+ if (bfdec_resize(r, 3))+ goto fail;+ r->tab[0] = v % BF_DEC_BASE;+ v /= BF_DEC_BASE;+ r->tab[1] = v % BF_DEC_BASE;+ r->tab[2] = v / BF_DEC_BASE;+ r->expn = 3 * LIMB_DIGITS;+ } else+#endif+ if (v >= BF_DEC_BASE) {+ if (bfdec_resize(r, 2))+ goto fail;+ r->tab[0] = v % BF_DEC_BASE;+ r->tab[1] = v / BF_DEC_BASE;+ r->expn = 2 * LIMB_DIGITS;+ } else {+ if (bfdec_resize(r, 1))+ goto fail;+ r->tab[0] = v;+ r->expn = LIMB_DIGITS;+ }+ r->sign = 0;+ return bfdec_normalize_and_round(r, BF_PREC_INF, 0);+ fail:+ bfdec_set_nan(r);+ return BF_ST_MEM_ERROR;+}++int bfdec_set_si(bfdec_t *r, int64_t v)+{+ int ret;+ if (v < 0) {+ ret = bfdec_set_ui(r, -v);+ r->sign = 1;+ } else {+ ret = bfdec_set_ui(r, v);+ }+ return ret;+}++static int bfdec_add_internal(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, bf_flags_t flags, int b_neg)+{+ bf_context_t *s = r->ctx;+ int is_sub, cmp_res, a_sign, b_sign, ret;++ a_sign = a->sign;+ b_sign = b->sign ^ b_neg;+ is_sub = a_sign ^ b_sign;+ cmp_res = bfdec_cmpu(a, b);+ if (cmp_res < 0) {+ const bfdec_t *tmp;+ tmp = a;+ a = b;+ b = tmp;+ a_sign = b_sign; /* b_sign is never used later */+ }+ /* abs(a) >= abs(b) */+ if (cmp_res == 0 && is_sub && a->expn < BF_EXP_INF) {+ /* zero result */+ bfdec_set_zero(r, (flags & BF_RND_MASK) == BF_RNDD);+ ret = 0;+ } else if (a->len == 0 || b->len == 0) {+ ret = 0;+ if (a->expn >= BF_EXP_INF) {+ if (a->expn == BF_EXP_NAN) {+ /* at least one operand is NaN */+ bfdec_set_nan(r);+ ret = 0;+ } else if (b->expn == BF_EXP_INF && is_sub) {+ /* infinities with different signs */+ bfdec_set_nan(r);+ ret = BF_ST_INVALID_OP;+ } else {+ bfdec_set_inf(r, a_sign);+ }+ } else {+ /* at least one zero and not subtract */+ if (bfdec_set(r, a))+ return BF_ST_MEM_ERROR;+ r->sign = a_sign;+ goto renorm;+ }+ } else {+ slimb_t d, a_offset, b_offset, i, r_len;+ limb_t carry;+ limb_t *b1_tab;+ int b_shift;+ mp_size_t b1_len;+ + d = a->expn - b->expn;++ /* XXX: not efficient in time and memory if the precision is+ not infinite */+ r_len = bf_max(a->len, b->len + (d + LIMB_DIGITS - 1) / LIMB_DIGITS);+ if (bfdec_resize(r, r_len))+ goto fail;+ r->sign = a_sign;+ r->expn = a->expn;++ a_offset = r_len - a->len;+ for(i = 0; i < a_offset; i++)+ r->tab[i] = 0;+ for(i = 0; i < a->len; i++)+ r->tab[a_offset + i] = a->tab[i];+ + b_shift = d % LIMB_DIGITS;+ if (b_shift == 0) {+ b1_len = b->len;+ b1_tab = (limb_t *)b->tab;+ } else {+ b1_len = b->len + 1;+ b1_tab = bf_malloc(s, sizeof(limb_t) * b1_len);+ if (!b1_tab)+ goto fail;+ b1_tab[0] = mp_shr_dec(b1_tab + 1, b->tab, b->len, b_shift, 0) *+ mp_pow_dec[LIMB_DIGITS - b_shift];+ }+ b_offset = r_len - (b->len + (d + LIMB_DIGITS - 1) / LIMB_DIGITS);+ + if (is_sub) {+ carry = mp_sub_dec(r->tab + b_offset, r->tab + b_offset,+ b1_tab, b1_len, 0);+ if (carry != 0) {+ carry = mp_sub_ui_dec(r->tab + b_offset + b1_len, carry,+ r_len - (b_offset + b1_len));+ assert(carry == 0);+ }+ } else {+ carry = mp_add_dec(r->tab + b_offset, r->tab + b_offset,+ b1_tab, b1_len, 0);+ if (carry != 0) {+ carry = mp_add_ui_dec(r->tab + b_offset + b1_len, carry,+ r_len - (b_offset + b1_len));+ }+ if (carry != 0) {+ if (bfdec_resize(r, r_len + 1)) {+ if (b_shift != 0)+ bf_free(s, b1_tab);+ goto fail;+ }+ r->tab[r_len] = 1;+ r->expn += LIMB_DIGITS;+ }+ }+ if (b_shift != 0)+ bf_free(s, b1_tab);+ renorm:+ ret = bfdec_normalize_and_round(r, prec, flags);+ }+ return ret;+ fail:+ bfdec_set_nan(r);+ return BF_ST_MEM_ERROR;+}++static int __bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,+ bf_flags_t flags)+{+ return bfdec_add_internal(r, a, b, prec, flags, 0);+}++static int __bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,+ bf_flags_t flags)+{+ return bfdec_add_internal(r, a, b, prec, flags, 1);+}++int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,+ bf_flags_t flags)+{+ return bf_op2((bf_t *)r, (bf_t *)a, (bf_t *)b, prec, flags,+ (bf_op2_func_t *)__bfdec_add);+}++int bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,+ bf_flags_t flags)+{+ return bf_op2((bf_t *)r, (bf_t *)a, (bf_t *)b, prec, flags,+ (bf_op2_func_t *)__bfdec_sub);+}++int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,+ bf_flags_t flags)+{+ int ret, r_sign;++ if (a->len < b->len) {+ const bfdec_t *tmp = a;+ a = b;+ b = tmp;+ }+ r_sign = a->sign ^ b->sign;+ /* here b->len <= a->len */+ if (b->len == 0) {+ if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {+ bfdec_set_nan(r);+ ret = 0;+ } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_INF) {+ if ((a->expn == BF_EXP_INF && b->expn == BF_EXP_ZERO) ||+ (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_INF)) {+ bfdec_set_nan(r);+ ret = BF_ST_INVALID_OP;+ } else {+ bfdec_set_inf(r, r_sign);+ ret = 0;+ }+ } else {+ bfdec_set_zero(r, r_sign);+ ret = 0;+ }+ } else {+ bfdec_t tmp, *r1 = NULL;+ limb_t a_len, b_len;+ limb_t *a_tab, *b_tab;+ + a_len = a->len;+ b_len = b->len;+ a_tab = a->tab;+ b_tab = b->tab;+ + if (r == a || r == b) {+ bfdec_init(r->ctx, &tmp);+ r1 = r;+ r = &tmp;+ }+ if (bfdec_resize(r, a_len + b_len)) {+ bfdec_set_nan(r);+ ret = BF_ST_MEM_ERROR;+ goto done;+ }+ mp_mul_basecase_dec(r->tab, a_tab, a_len, b_tab, b_len);+ r->sign = r_sign;+ r->expn = a->expn + b->expn;+ ret = bfdec_normalize_and_round(r, prec, flags);+ done:+ if (r == &tmp)+ bfdec_move(r1, &tmp);+ }+ return ret;+}++int bfdec_mul_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,+ bf_flags_t flags)+{+ bfdec_t b;+ int ret;+ bfdec_init(r->ctx, &b);+ ret = bfdec_set_si(&b, b1);+ ret |= bfdec_mul(r, a, &b, prec, flags);+ bfdec_delete(&b);+ return ret;+}++int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,+ bf_flags_t flags)+{+ bfdec_t b;+ int ret;+ + bfdec_init(r->ctx, &b);+ ret = bfdec_set_si(&b, b1);+ ret |= bfdec_add(r, a, &b, prec, flags);+ bfdec_delete(&b);+ return ret;+}++static int __bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b,+ limb_t prec, bf_flags_t flags)+{+ int ret, r_sign;+ limb_t n, nb, precl;+ + r_sign = a->sign ^ b->sign;+ if (a->expn >= BF_EXP_INF || b->expn >= BF_EXP_INF) {+ if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {+ bfdec_set_nan(r);+ return 0;+ } else if (a->expn == BF_EXP_INF && b->expn == BF_EXP_INF) {+ bfdec_set_nan(r);+ return BF_ST_INVALID_OP;+ } else if (a->expn == BF_EXP_INF) {+ bfdec_set_inf(r, r_sign);+ return 0;+ } else {+ bfdec_set_zero(r, r_sign);+ return 0;+ }+ } else if (a->expn == BF_EXP_ZERO) {+ if (b->expn == BF_EXP_ZERO) {+ bfdec_set_nan(r);+ return BF_ST_INVALID_OP;+ } else {+ bfdec_set_zero(r, r_sign);+ return 0;+ }+ } else if (b->expn == BF_EXP_ZERO) {+ bfdec_set_inf(r, r_sign);+ return BF_ST_DIVIDE_ZERO;+ }++ nb = b->len;+ if (prec == BF_PREC_INF) {+ /* infinite precision: return BF_ST_INVALID_OP if not an exact+ result */+ /* XXX: check */+ precl = nb + 1;+ } else if (flags & BF_FLAG_RADPNT_PREC) {+ /* number of digits after the decimal point */+ /* XXX: check (2 extra digits for rounding + 2 digits) */+ precl = (bf_max(a->expn - b->expn, 0) + 2 ++ prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS;+ } else {+ /* number of limbs of the quotient (2 extra digits for rounding) */+ precl = (prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS;+ }+ n = bf_max(a->len, precl);+ + {+ limb_t *taba, na, i;+ slimb_t d;+ + na = n + nb;+ taba = bf_malloc(r->ctx, (na + 1) * sizeof(limb_t));+ if (!taba)+ goto fail;+ d = na - a->len;+ memset(taba, 0, d * sizeof(limb_t));+ memcpy(taba + d, a->tab, a->len * sizeof(limb_t));+ if (bfdec_resize(r, n + 1))+ goto fail1;+ if (mp_div_dec(r->ctx, r->tab, taba, na, b->tab, nb)) {+ fail1:+ bf_free(r->ctx, taba);+ goto fail;+ }+ /* see if non zero remainder */+ for(i = 0; i < nb; i++) {+ if (taba[i] != 0)+ break;+ }+ bf_free(r->ctx, taba);+ if (i != nb) {+ if (prec == BF_PREC_INF) {+ bfdec_set_nan(r);+ return BF_ST_INVALID_OP;+ } else {+ r->tab[0] |= 1;+ }+ }+ r->expn = a->expn - b->expn + LIMB_DIGITS;+ r->sign = r_sign;+ ret = bfdec_normalize_and_round(r, prec, flags);+ }+ return ret;+ fail:+ bfdec_set_nan(r);+ return BF_ST_MEM_ERROR;+}++int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,+ bf_flags_t flags)+{+ return bf_op2((bf_t *)r, (bf_t *)a, (bf_t *)b, prec, flags,+ (bf_op2_func_t *)__bfdec_div);+}++/* a and b must be finite numbers with a >= 0 and b > 0. 'q' is the+ integer defined as floor(a/b) and r = a - q * b. */+static void bfdec_tdivremu(bf_context_t *s, bfdec_t *q, bfdec_t *r,+ const bfdec_t *a, const bfdec_t *b)+{+ if (bfdec_cmpu(a, b) < 0) {+ bfdec_set_ui(q, 0);+ bfdec_set(r, a);+ } else {+ bfdec_div(q, a, b, 0, BF_RNDZ | BF_FLAG_RADPNT_PREC);+ bfdec_mul(r, q, b, BF_PREC_INF, BF_RNDZ);+ bfdec_sub(r, a, r, BF_PREC_INF, BF_RNDZ);+ }+}++/* division and remainder. + + rnd_mode is the rounding mode for the quotient. The additional+ rounding mode BF_RND_EUCLIDIAN is supported.++ 'q' is an integer. 'r' is rounded with prec and flags (prec can be+ BF_PREC_INF).+*/+int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,+ limb_t prec, bf_flags_t flags, int rnd_mode)+{+ bf_context_t *s = q->ctx;+ bfdec_t a1_s, *a1 = &a1_s;+ bfdec_t b1_s, *b1 = &b1_s;+ bfdec_t r1_s, *r1 = &r1_s;+ int q_sign, res;+ BOOL is_ceil, is_rndn;+ + assert(q != a && q != b);+ assert(r != a && r != b);+ assert(q != r);+ + if (a->len == 0 || b->len == 0) {+ bfdec_set_zero(q, 0);+ if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {+ bfdec_set_nan(r);+ return 0;+ } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_ZERO) {+ bfdec_set_nan(r);+ return BF_ST_INVALID_OP;+ } else {+ bfdec_set(r, a);+ return bfdec_round(r, prec, flags);+ }+ }++ q_sign = a->sign ^ b->sign;+ is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);+ switch(rnd_mode) {+ default:+ case BF_RNDZ:+ case BF_RNDN:+ case BF_RNDNA:+ is_ceil = FALSE;+ break;+ case BF_RNDD:+ is_ceil = q_sign;+ break;+ case BF_RNDU:+ is_ceil = q_sign ^ 1;+ break;+ case BF_RNDA:+ is_ceil = TRUE;+ break;+ case BF_DIVREM_EUCLIDIAN:+ is_ceil = a->sign;+ break;+ }++ a1->expn = a->expn;+ a1->tab = a->tab;+ a1->len = a->len;+ a1->sign = 0;+ + b1->expn = b->expn;+ b1->tab = b->tab;+ b1->len = b->len;+ b1->sign = 0;++ // bfdec_print_str("a1", a1);+ // bfdec_print_str("b1", b1);+ /* XXX: could improve to avoid having a large 'q' */+ bfdec_tdivremu(s, q, r, a1, b1);+ if (bfdec_is_nan(q) || bfdec_is_nan(r))+ goto fail;+ // bfdec_print_str("q", q);+ // bfdec_print_str("r", r);+ + if (r->len != 0) {+ if (is_rndn) {+ bfdec_init(s, r1);+ if (bfdec_set(r1, r))+ goto fail;+ if (bfdec_mul_si(r1, r1, 2, BF_PREC_INF, BF_RNDZ)) {+ bfdec_delete(r1);+ goto fail;+ }+ res = bfdec_cmpu(r1, b);+ bfdec_delete(r1);+ if (res > 0 ||+ (res == 0 &&+ (rnd_mode == BF_RNDNA ||+ (get_digit(q->tab, q->len, q->len * LIMB_DIGITS - q->expn) & 1) != 0))) {+ goto do_sub_r;+ }+ } else if (is_ceil) {+ do_sub_r:+ res = bfdec_add_si(q, q, 1, BF_PREC_INF, BF_RNDZ);+ res |= bfdec_sub(r, r, b1, BF_PREC_INF, BF_RNDZ);+ if (res & BF_ST_MEM_ERROR)+ goto fail;+ }+ }++ r->sign ^= a->sign;+ q->sign = q_sign;+ return bfdec_round(r, prec, flags);+ fail:+ bfdec_set_nan(q);+ bfdec_set_nan(r);+ return BF_ST_MEM_ERROR;+}++int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,+ bf_flags_t flags, int rnd_mode)+{+ bfdec_t q_s, *q = &q_s;+ int ret;+ + bfdec_init(r->ctx, q);+ ret = bfdec_divrem(q, r, a, b, prec, flags, rnd_mode);+ bfdec_delete(q);+ return ret;+}++/* convert to integer (infinite precision) */+int bfdec_rint(bfdec_t *r, int rnd_mode)+{+ return bfdec_round(r, 0, rnd_mode | BF_FLAG_RADPNT_PREC);+}++int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags)+{+ bf_context_t *s = a->ctx;+ int ret, k;+ limb_t *a1, v;+ slimb_t n, n1, prec1;+ limb_t res;++ assert(r != a);++ if (a->len == 0) {+ if (a->expn == BF_EXP_NAN) {+ bfdec_set_nan(r);+ } else if (a->expn == BF_EXP_INF && a->sign) {+ goto invalid_op;+ } else {+ bfdec_set(r, a);+ }+ ret = 0;+ } else if (a->sign || prec == BF_PREC_INF) {+ invalid_op:+ bfdec_set_nan(r);+ ret = BF_ST_INVALID_OP;+ } else {+ if (flags & BF_FLAG_RADPNT_PREC) {+ prec1 = bf_max(floor_div(a->expn + 1, 2) + prec, 1);+ } else {+ prec1 = prec;+ }+ /* convert the mantissa to an integer with at least 2 *+ prec + 4 digits */+ n = (2 * (prec1 + 2) + 2 * LIMB_DIGITS - 1) / (2 * LIMB_DIGITS);+ if (bfdec_resize(r, n))+ goto fail;+ a1 = bf_malloc(s, sizeof(limb_t) * 2 * n);+ if (!a1)+ goto fail;+ n1 = bf_min(2 * n, a->len);+ memset(a1, 0, (2 * n - n1) * sizeof(limb_t));+ memcpy(a1 + 2 * n - n1, a->tab + a->len - n1, n1 * sizeof(limb_t));+ if (a->expn & 1) {+ res = mp_shr_dec(a1, a1, 2 * n, 1, 0);+ } else {+ res = 0;+ }+ /* normalize so that a1 >= B^(2*n)/4. Not need for n = 1+ because mp_sqrtrem2_dec already does it */+ k = 0;+ if (n > 1) {+ v = a1[2 * n - 1];+ while (v < BF_DEC_BASE / 4) {+ k++;+ v *= 4;+ }+ if (k != 0)+ mp_mul1_dec(a1, a1, 2 * n, 1 << (2 * k), 0);+ }+ if (mp_sqrtrem_dec(s, r->tab, a1, n)) {+ bf_free(s, a1);+ goto fail;+ }+ if (k != 0)+ mp_div1_dec(r->tab, r->tab, n, 1 << k, 0);+ if (!res) {+ res = mp_scan_nz(a1, n + 1);+ }+ bf_free(s, a1);+ if (!res) {+ res = mp_scan_nz(a->tab, a->len - n1);+ }+ if (res != 0)+ r->tab[0] |= 1;+ r->sign = 0;+ r->expn = (a->expn + 1) >> 1;+ ret = bfdec_round(r, prec, flags);+ }+ return ret;+ fail:+ bfdec_set_nan(r);+ return BF_ST_MEM_ERROR;+}++/* The rounding mode is always BF_RNDZ. Return BF_ST_OVERFLOW if there+ is an overflow and 0 otherwise. No memory error is possible. */+int bfdec_get_int32(int *pres, const bfdec_t *a)+{+ uint32_t v;+ int ret;+ if (a->expn >= BF_EXP_INF) {+ ret = 0;+ if (a->expn == BF_EXP_INF) {+ v = (uint32_t)INT32_MAX + a->sign;+ /* XXX: return overflow ? */+ } else {+ v = INT32_MAX;+ }+ } else if (a->expn <= 0) {+ v = 0;+ ret = 0;+ } else if (a->expn <= 9) {+ v = fast_shr_dec(a->tab[a->len - 1], LIMB_DIGITS - a->expn);+ if (a->sign)+ v = -v;+ ret = 0;+ } else if (a->expn == 10) {+ uint64_t v1;+ uint32_t v_max;+#if LIMB_BITS == 64+ v1 = fast_shr_dec(a->tab[a->len - 1], LIMB_DIGITS - a->expn);+#else+ v1 = (uint64_t)a->tab[a->len - 1] * 10 ++ get_digit(a->tab, a->len, (a->len - 1) * LIMB_DIGITS - 1);+#endif+ v_max = (uint32_t)INT32_MAX + a->sign;+ if (v1 > v_max) {+ v = v_max;+ ret = BF_ST_OVERFLOW;+ } else {+ v = v1;+ if (a->sign)+ v = -v;+ ret = 0;+ }+ } else {+ v = (uint32_t)INT32_MAX + a->sign;+ ret = BF_ST_OVERFLOW;+ }+ *pres = v;+ return ret;+}++/* power to an integer with infinite precision */+int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b)+{+ int ret, n_bits, i;+ + assert(r != a);+ if (b == 0)+ return bfdec_set_ui(r, 1);+ ret = bfdec_set(r, a);+ n_bits = LIMB_BITS - clz(b);+ for(i = n_bits - 2; i >= 0; i--) {+ ret |= bfdec_mul(r, r, r, BF_PREC_INF, BF_RNDZ);+ if ((b >> i) & 1)+ ret |= bfdec_mul(r, r, a, BF_PREC_INF, BF_RNDZ);+ }+ return ret;+}++char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags)+{+ return bf_ftoa_internal(plen, (const bf_t *)a, 10, prec, flags, TRUE);+}++int bfdec_atof(bfdec_t *r, const char *str, const char **pnext,+ limb_t prec, bf_flags_t flags)+{+ slimb_t dummy_exp;+ return bf_atof_internal((bf_t *)r, &dummy_exp, str, pnext, 10, prec,+ flags, TRUE);+}++#endif /* USE_BF_DEC */++#ifdef USE_FFT_MUL+/***************************************************************/+/* Integer multiplication with FFT */++/* or LIMB_BITS at bit position 'pos' in tab */+static inline void put_bits(limb_t *tab, limb_t len, slimb_t pos, limb_t val)+{+ limb_t i;+ int p;++ i = pos >> LIMB_LOG2_BITS;+ p = pos & (LIMB_BITS - 1);+ if (i < len)+ tab[i] |= val << p;+ if (p != 0) {+ i++;+ if (i < len) {+ tab[i] |= val >> (LIMB_BITS - p);+ }+ }+}++#if defined(__AVX2__)++typedef double NTTLimb;++/* we must have: modulo >= 1 << NTT_MOD_LOG2_MIN */+#define NTT_MOD_LOG2_MIN 50+#define NTT_MOD_LOG2_MAX 51+#define NB_MODS 5+#define NTT_PROOT_2EXP 39+static const int ntt_int_bits[NB_MODS] = { 254, 203, 152, 101, 50, };++static const limb_t ntt_mods[NB_MODS] = { 0x00073a8000000001, 0x0007858000000001, 0x0007a38000000001, 0x0007a68000000001, 0x0007fd8000000001,+};++static const limb_t ntt_proot[2][NB_MODS] = {+ { 0x00056198d44332c8, 0x0002eb5d640aad39, 0x00047e31eaa35fd0, 0x0005271ac118a150, 0x00075e0ce8442bd5, },+ { 0x000461169761bcc5, 0x0002dac3cb2da688, 0x0004abc97751e3bf, 0x000656778fc8c485, 0x0000dc6469c269fa, },+};++static const limb_t ntt_mods_cr[NB_MODS * (NB_MODS - 1) / 2] = {+ 0x00020e4da740da8e, 0x0004c3dc09c09c1d, 0x000063bd097b4271, 0x000799d8f18f18fd,+ 0x0005384222222264, 0x000572b07c1f07fe, 0x00035cd08888889a,+ 0x00066015555557e3, 0x000725960b60b623,+ 0x0002fc1fa1d6ce12,+};++#else++typedef limb_t NTTLimb;++#if LIMB_BITS == 64++#define NTT_MOD_LOG2_MIN 61+#define NTT_MOD_LOG2_MAX 62+#define NB_MODS 5+#define NTT_PROOT_2EXP 51+static const int ntt_int_bits[NB_MODS] = { 307, 246, 185, 123, 61, };++static const limb_t ntt_mods[NB_MODS] = { 0x28d8000000000001, 0x2a88000000000001, 0x2ed8000000000001, 0x3508000000000001, 0x3aa8000000000001,+};++static const limb_t ntt_proot[2][NB_MODS] = {+ { 0x1b8ea61034a2bea7, 0x21a9762de58206fb, 0x02ca782f0756a8ea, 0x278384537a3e50a1, 0x106e13fee74ce0ab, },+ { 0x233513af133e13b8, 0x1d13140d1c6f75f1, 0x12cde57f97e3eeda, 0x0d6149e23cbe654f, 0x36cd204f522a1379, },+};++static const limb_t ntt_mods_cr[NB_MODS * (NB_MODS - 1) / 2] = {+ 0x08a9ed097b425eea, 0x18a44aaaaaaaaab3, 0x2493f57f57f57f5d, 0x126b8d0649a7f8d4,+ 0x09d80ed7303b5ccc, 0x25b8bcf3cf3cf3d5, 0x2ce6ce63398ce638,+ 0x0e31fad40a57eb59, 0x02a3529fd4a7f52f,+ 0x3a5493e93e93e94a,+};++#elif LIMB_BITS == 32++/* we must have: modulo >= 1 << NTT_MOD_LOG2_MIN */+#define NTT_MOD_LOG2_MIN 29+#define NTT_MOD_LOG2_MAX 30+#define NB_MODS 5+#define NTT_PROOT_2EXP 20+static const int ntt_int_bits[NB_MODS] = { 148, 119, 89, 59, 29, };++static const limb_t ntt_mods[NB_MODS] = { 0x0000000032b00001, 0x0000000033700001, 0x0000000036d00001, 0x0000000037300001, 0x000000003e500001,+};++static const limb_t ntt_proot[2][NB_MODS] = {+ { 0x0000000032525f31, 0x0000000005eb3b37, 0x00000000246eda9f, 0x0000000035f25901, 0x00000000022f5768, },+ { 0x00000000051eba1a, 0x00000000107be10e, 0x000000001cd574e0, 0x00000000053806e6, 0x000000002cd6bf98, },+};++static const limb_t ntt_mods_cr[NB_MODS * (NB_MODS - 1) / 2] = {+ 0x000000000449559a, 0x000000001eba6ca9, 0x000000002ec18e46, 0x000000000860160b,+ 0x000000000d321307, 0x000000000bf51120, 0x000000000f662938,+ 0x000000000932ab3e, 0x000000002f40eef8,+ 0x000000002e760905,+};++#endif /* LIMB_BITS */++#endif /* !AVX2 */++#if defined(__AVX2__)+#define NTT_TRIG_K_MAX 18+#else+#define NTT_TRIG_K_MAX 19+#endif++typedef struct BFNTTState {+ bf_context_t *ctx;+ + /* used for mul_mod_fast() */+ limb_t ntt_mods_div[NB_MODS];++ limb_t ntt_proot_pow[NB_MODS][2][NTT_PROOT_2EXP + 1];+ limb_t ntt_proot_pow_inv[NB_MODS][2][NTT_PROOT_2EXP + 1];+ NTTLimb *ntt_trig[NB_MODS][2][NTT_TRIG_K_MAX + 1];+ /* 1/2^n mod m */+ limb_t ntt_len_inv[NB_MODS][NTT_PROOT_2EXP + 1][2];+#if defined(__AVX2__)+ __m256d ntt_mods_cr_vec[NB_MODS * (NB_MODS - 1) / 2];+ __m256d ntt_mods_vec[NB_MODS];+ __m256d ntt_mods_inv_vec[NB_MODS];+#else+ limb_t ntt_mods_cr_inv[NB_MODS * (NB_MODS - 1) / 2];+#endif+} BFNTTState;++static NTTLimb *get_trig(BFNTTState *s, int k, int inverse, int m_idx);++/* add modulo with up to (LIMB_BITS-1) bit modulo */+static inline limb_t add_mod(limb_t a, limb_t b, limb_t m)+{+ limb_t r;+ r = a + b;+ if (r >= m)+ r -= m;+ return r;+}++/* sub modulo with up to LIMB_BITS bit modulo */+static inline limb_t sub_mod(limb_t a, limb_t b, limb_t m)+{+ limb_t r;+ r = a - b;+ if (r > a)+ r += m;+ return r;+}++/* return (r0+r1*B) mod m + precondition: 0 <= r0+r1*B < 2^(64+NTT_MOD_LOG2_MIN) +*/+static inline limb_t mod_fast(dlimb_t r, + limb_t m, limb_t m_inv)+{+ limb_t a1, q, t0, r1, r0;+ + a1 = r >> NTT_MOD_LOG2_MIN;+ + q = ((dlimb_t)a1 * m_inv) >> LIMB_BITS;+ r = r - (dlimb_t)q * m - m * 2;+ r1 = r >> LIMB_BITS;+ t0 = (slimb_t)r1 >> 1;+ r += m & t0;+ r0 = r;+ r1 = r >> LIMB_BITS;+ r0 += m & r1;+ return r0;+}++/* faster version using precomputed modulo inverse. + precondition: 0 <= a * b < 2^(64+NTT_MOD_LOG2_MIN) */+static inline limb_t mul_mod_fast(limb_t a, limb_t b, + limb_t m, limb_t m_inv)+{+ dlimb_t r;+ r = (dlimb_t)a * (dlimb_t)b;+ return mod_fast(r, m, m_inv);+}++static inline limb_t init_mul_mod_fast(limb_t m)+{+ dlimb_t t;+ assert(m < (limb_t)1 << NTT_MOD_LOG2_MAX);+ assert(m >= (limb_t)1 << NTT_MOD_LOG2_MIN);+ t = (dlimb_t)1 << (LIMB_BITS + NTT_MOD_LOG2_MIN);+ return t / m;+}++/* Faster version used when the multiplier is constant. 0 <= a < 2^64,+ 0 <= b < m. */+static inline limb_t mul_mod_fast2(limb_t a, limb_t b, + limb_t m, limb_t b_inv)+{+ limb_t r, q;++ q = ((dlimb_t)a * (dlimb_t)b_inv) >> LIMB_BITS;+ r = a * b - q * m;+ if (r >= m)+ r -= m;+ return r;+}++/* Faster version used when the multiplier is constant. 0 <= a < 2^64,+ 0 <= b < m. Let r = a * b mod m. The return value is 'r' or 'r ++ m'. */+static inline limb_t mul_mod_fast3(limb_t a, limb_t b, + limb_t m, limb_t b_inv)+{+ limb_t r, q;++ q = ((dlimb_t)a * (dlimb_t)b_inv) >> LIMB_BITS;+ r = a * b - q * m;+ return r;+}++static inline limb_t init_mul_mod_fast2(limb_t b, limb_t m)+{+ return ((dlimb_t)b << LIMB_BITS) / m;+}++#ifdef __AVX2__++static inline limb_t ntt_limb_to_int(NTTLimb a, limb_t m)+{+ slimb_t v;+ v = a;+ if (v < 0)+ v += m;+ if (v >= m)+ v -= m;+ return v;+}++static inline NTTLimb int_to_ntt_limb(limb_t a, limb_t m)+{+ return (slimb_t)a;+}++static inline NTTLimb int_to_ntt_limb2(limb_t a, limb_t m)+{+ if (a >= (m / 2))+ a -= m;+ return (slimb_t)a;+}++/* return r + m if r < 0 otherwise r. */+static inline __m256d ntt_mod1(__m256d r, __m256d m)+{+ return _mm256_blendv_pd(r, r + m, r);+}++/* input: abs(r) < 2 * m. Output: abs(r) < m */+static inline __m256d ntt_mod(__m256d r, __m256d mf, __m256d m2f)+{+ return _mm256_blendv_pd(r, r + m2f, r) - mf;+}++/* input: abs(a*b) < 2 * m^2, output: abs(r) < m */+static inline __m256d ntt_mul_mod(__m256d a, __m256d b, __m256d mf,+ __m256d m_inv)+{+ __m256d r, q, ab1, ab0, qm0, qm1;+ ab1 = a * b;+ q = _mm256_round_pd(ab1 * m_inv, 0); /* round to nearest */+ qm1 = q * mf;+ qm0 = _mm256_fmsub_pd(q, mf, qm1); /* low part */+ ab0 = _mm256_fmsub_pd(a, b, ab1); /* low part */+ r = (ab1 - qm1) + (ab0 - qm0);+ return r;+}++static void *bf_aligned_malloc(bf_context_t *s, size_t size, size_t align)+{+ void *ptr;+ void **ptr1;+ ptr = bf_malloc(s, size + sizeof(void *) + align - 1);+ if (!ptr)+ return NULL;+ ptr1 = (void **)(((uintptr_t)ptr + sizeof(void *) + align - 1) &+ ~(align - 1));+ ptr1[-1] = ptr;+ return ptr1;+}++static void bf_aligned_free(bf_context_t *s, void *ptr)+{+ if (!ptr)+ return;+ bf_free(s, ((void **)ptr)[-1]);+}++static void *ntt_malloc(BFNTTState *s, size_t size)+{+ return bf_aligned_malloc(s->ctx, size, 64);+}++static void ntt_free(BFNTTState *s, void *ptr)+{+ bf_aligned_free(s->ctx, ptr);+}++static no_inline int ntt_fft(BFNTTState *s,+ NTTLimb *out_buf, NTTLimb *in_buf,+ NTTLimb *tmp_buf, int fft_len_log2,+ int inverse, int m_idx)+{+ limb_t nb_blocks, fft_per_block, p, k, n, stride_in, i, j;+ NTTLimb *tab_in, *tab_out, *tmp, *trig;+ __m256d m_inv, mf, m2f, c, a0, a1, b0, b1;+ limb_t m;+ int l;+ + m = ntt_mods[m_idx];+ + m_inv = _mm256_set1_pd(1.0 / (double)m);+ mf = _mm256_set1_pd(m);+ m2f = _mm256_set1_pd(m * 2);++ n = (limb_t)1 << fft_len_log2;+ assert(n >= 8);+ stride_in = n / 2;++ tab_in = in_buf;+ tab_out = tmp_buf;+ trig = get_trig(s, fft_len_log2, inverse, m_idx);+ if (!trig)+ return -1;+ p = 0;+ for(k = 0; k < stride_in; k += 4) {+ a0 = _mm256_load_pd(&tab_in[k]);+ a1 = _mm256_load_pd(&tab_in[k + stride_in]);+ c = _mm256_load_pd(trig);+ trig += 4;+ b0 = ntt_mod(a0 + a1, mf, m2f);+ b1 = ntt_mul_mod(a0 - a1, c, mf, m_inv);+ a0 = _mm256_permute2f128_pd(b0, b1, 0x20);+ a1 = _mm256_permute2f128_pd(b0, b1, 0x31);+ a0 = _mm256_permute4x64_pd(a0, 0xd8);+ a1 = _mm256_permute4x64_pd(a1, 0xd8);+ _mm256_store_pd(&tab_out[p], a0);+ _mm256_store_pd(&tab_out[p + 4], a1);+ p += 2 * 4;+ }+ tmp = tab_in;+ tab_in = tab_out;+ tab_out = tmp;++ trig = get_trig(s, fft_len_log2 - 1, inverse, m_idx);+ if (!trig)+ return -1;+ p = 0;+ for(k = 0; k < stride_in; k += 4) {+ a0 = _mm256_load_pd(&tab_in[k]);+ a1 = _mm256_load_pd(&tab_in[k + stride_in]);+ c = _mm256_setr_pd(trig[0], trig[0], trig[1], trig[1]);+ trig += 2;+ b0 = ntt_mod(a0 + a1, mf, m2f);+ b1 = ntt_mul_mod(a0 - a1, c, mf, m_inv);+ a0 = _mm256_permute2f128_pd(b0, b1, 0x20);+ a1 = _mm256_permute2f128_pd(b0, b1, 0x31);+ _mm256_store_pd(&tab_out[p], a0);+ _mm256_store_pd(&tab_out[p + 4], a1);+ p += 2 * 4;+ }+ tmp = tab_in;+ tab_in = tab_out;+ tab_out = tmp;+ + nb_blocks = n / 4;+ fft_per_block = 4;++ l = fft_len_log2 - 2;+ while (nb_blocks != 2) {+ nb_blocks >>= 1;+ p = 0;+ k = 0;+ trig = get_trig(s, l, inverse, m_idx);+ if (!trig)+ return -1;+ for(i = 0; i < nb_blocks; i++) {+ c = _mm256_set1_pd(trig[0]);+ trig++;+ for(j = 0; j < fft_per_block; j += 4) {+ a0 = _mm256_load_pd(&tab_in[k + j]);+ a1 = _mm256_load_pd(&tab_in[k + j + stride_in]);+ b0 = ntt_mod(a0 + a1, mf, m2f);+ b1 = ntt_mul_mod(a0 - a1, c, mf, m_inv);+ _mm256_store_pd(&tab_out[p + j], b0);+ _mm256_store_pd(&tab_out[p + j + fft_per_block], b1);+ }+ k += fft_per_block;+ p += 2 * fft_per_block;+ }+ fft_per_block <<= 1;+ l--;+ tmp = tab_in;+ tab_in = tab_out;+ tab_out = tmp;+ }++ tab_out = out_buf;+ for(k = 0; k < stride_in; k += 4) {+ a0 = _mm256_load_pd(&tab_in[k]);+ a1 = _mm256_load_pd(&tab_in[k + stride_in]);+ b0 = ntt_mod(a0 + a1, mf, m2f);+ b1 = ntt_mod(a0 - a1, mf, m2f);+ _mm256_store_pd(&tab_out[k], b0);+ _mm256_store_pd(&tab_out[k + stride_in], b1);+ }+ return 0;+}++static void ntt_vec_mul(BFNTTState *s,+ NTTLimb *tab1, NTTLimb *tab2, limb_t fft_len_log2,+ int k_tot, int m_idx)+{+ limb_t i, c_inv, n, m;+ __m256d m_inv, mf, a, b, c;+ + m = ntt_mods[m_idx];+ c_inv = s->ntt_len_inv[m_idx][k_tot][0];+ m_inv = _mm256_set1_pd(1.0 / (double)m);+ mf = _mm256_set1_pd(m);+ c = _mm256_set1_pd(int_to_ntt_limb(c_inv, m));+ n = (limb_t)1 << fft_len_log2;+ for(i = 0; i < n; i += 4) {+ a = _mm256_load_pd(&tab1[i]);+ b = _mm256_load_pd(&tab2[i]);+ a = ntt_mul_mod(a, b, mf, m_inv);+ a = ntt_mul_mod(a, c, mf, m_inv);+ _mm256_store_pd(&tab1[i], a);+ }+}++static no_inline void mul_trig(NTTLimb *buf,+ limb_t n, limb_t c1, limb_t m, limb_t m_inv1)+{+ limb_t i, c2, c3, c4;+ __m256d c, c_mul, a0, mf, m_inv;+ assert(n >= 2);+ + mf = _mm256_set1_pd(m);+ m_inv = _mm256_set1_pd(1.0 / (double)m);++ c2 = mul_mod_fast(c1, c1, m, m_inv1);+ c3 = mul_mod_fast(c2, c1, m, m_inv1);+ c4 = mul_mod_fast(c2, c2, m, m_inv1);+ c = _mm256_setr_pd(1, int_to_ntt_limb(c1, m),+ int_to_ntt_limb(c2, m), int_to_ntt_limb(c3, m));+ c_mul = _mm256_set1_pd(int_to_ntt_limb(c4, m));+ for(i = 0; i < n; i += 4) {+ a0 = _mm256_load_pd(&buf[i]);+ a0 = ntt_mul_mod(a0, c, mf, m_inv);+ _mm256_store_pd(&buf[i], a0);+ c = ntt_mul_mod(c, c_mul, mf, m_inv);+ }+}++#else++static void *ntt_malloc(BFNTTState *s, size_t size)+{+ return bf_malloc(s->ctx, size);+}++static void ntt_free(BFNTTState *s, void *ptr)+{+ bf_free(s->ctx, ptr);+}++static inline limb_t ntt_limb_to_int(NTTLimb a, limb_t m)+{+ if (a >= m)+ a -= m;+ return a;+}++static inline NTTLimb int_to_ntt_limb(slimb_t a, limb_t m)+{+ return a;+}++static no_inline int ntt_fft(BFNTTState *s, NTTLimb *out_buf, NTTLimb *in_buf,+ NTTLimb *tmp_buf, int fft_len_log2,+ int inverse, int m_idx)+{+ limb_t nb_blocks, fft_per_block, p, k, n, stride_in, i, j, m, m2;+ NTTLimb *tab_in, *tab_out, *tmp, a0, a1, b0, b1, c, *trig, c_inv;+ int l;+ + m = ntt_mods[m_idx];+ m2 = 2 * m;+ n = (limb_t)1 << fft_len_log2;+ nb_blocks = n;+ fft_per_block = 1;+ stride_in = n / 2;+ tab_in = in_buf;+ tab_out = tmp_buf;+ l = fft_len_log2;+ while (nb_blocks != 2) {+ nb_blocks >>= 1;+ p = 0;+ k = 0;+ trig = get_trig(s, l, inverse, m_idx);+ if (!trig)+ return -1;+ for(i = 0; i < nb_blocks; i++) {+ c = trig[0];+ c_inv = trig[1];+ trig += 2;+ for(j = 0; j < fft_per_block; j++) {+ a0 = tab_in[k + j];+ a1 = tab_in[k + j + stride_in];+ b0 = add_mod(a0, a1, m2);+ b1 = a0 - a1 + m2;+ b1 = mul_mod_fast3(b1, c, m, c_inv);+ tab_out[p + j] = b0;+ tab_out[p + j + fft_per_block] = b1;+ }+ k += fft_per_block;+ p += 2 * fft_per_block;+ }+ fft_per_block <<= 1;+ l--;+ tmp = tab_in;+ tab_in = tab_out;+ tab_out = tmp;+ }+ /* no twiddle in last step */+ tab_out = out_buf; + for(k = 0; k < stride_in; k++) {+ a0 = tab_in[k];+ a1 = tab_in[k + stride_in];+ b0 = add_mod(a0, a1, m2);+ b1 = sub_mod(a0, a1, m2);+ tab_out[k] = b0;+ tab_out[k + stride_in] = b1;+ }+ return 0;+}++static void ntt_vec_mul(BFNTTState *s,+ NTTLimb *tab1, NTTLimb *tab2, int fft_len_log2,+ int k_tot, int m_idx)+{+ limb_t i, norm, norm_inv, a, n, m, m_inv;+ + m = ntt_mods[m_idx];+ m_inv = s->ntt_mods_div[m_idx];+ norm = s->ntt_len_inv[m_idx][k_tot][0];+ norm_inv = s->ntt_len_inv[m_idx][k_tot][1];+ n = (limb_t)1 << fft_len_log2;+ for(i = 0; i < n; i++) {+ a = tab1[i];+ /* need to reduce the range so that the product is <+ 2^(LIMB_BITS+NTT_MOD_LOG2_MIN) */+ if (a >= m)+ a -= m;+ a = mul_mod_fast(a, tab2[i], m, m_inv);+ a = mul_mod_fast3(a, norm, m, norm_inv);+ tab1[i] = a;+ }+}++static no_inline void mul_trig(NTTLimb *buf,+ limb_t n, limb_t c_mul, limb_t m, limb_t m_inv)+{+ limb_t i, c0, c_mul_inv;+ + c0 = 1;+ c_mul_inv = init_mul_mod_fast2(c_mul, m);+ for(i = 0; i < n; i++) {+ buf[i] = mul_mod_fast(buf[i], c0, m, m_inv);+ c0 = mul_mod_fast2(c0, c_mul, m, c_mul_inv);+ }+}++#endif /* !AVX2 */++static no_inline NTTLimb *get_trig(BFNTTState *s,+ int k, int inverse, int m_idx)+{+ NTTLimb *tab;+ limb_t i, n2, c, c_mul, m, c_mul_inv;+ + if (k > NTT_TRIG_K_MAX)+ return NULL;++ tab = s->ntt_trig[m_idx][inverse][k];+ if (tab)+ return tab;+ n2 = (limb_t)1 << (k - 1);+ m = ntt_mods[m_idx];+#ifdef __AVX2__+ tab = ntt_malloc(s, sizeof(NTTLimb) * n2);+#else+ tab = ntt_malloc(s, sizeof(NTTLimb) * n2 * 2);+#endif+ if (!tab)+ return NULL;+ c = 1;+ c_mul = s->ntt_proot_pow[m_idx][inverse][k];+ c_mul_inv = s->ntt_proot_pow_inv[m_idx][inverse][k];+ for(i = 0; i < n2; i++) {+#ifdef __AVX2__+ tab[i] = int_to_ntt_limb2(c, m);+#else+ tab[2 * i] = int_to_ntt_limb(c, m);+ tab[2 * i + 1] = init_mul_mod_fast2(c, m);+#endif+ c = mul_mod_fast2(c, c_mul, m, c_mul_inv);+ }+ s->ntt_trig[m_idx][inverse][k] = tab;+ return tab;+}++void fft_clear_cache(bf_context_t *s1)+{+ int m_idx, inverse, k;+ BFNTTState *s = s1->ntt_state;+ if (s) {+ for(m_idx = 0; m_idx < NB_MODS; m_idx++) {+ for(inverse = 0; inverse < 2; inverse++) {+ for(k = 0; k < NTT_TRIG_K_MAX + 1; k++) {+ if (s->ntt_trig[m_idx][inverse][k]) {+ ntt_free(s, s->ntt_trig[m_idx][inverse][k]);+ s->ntt_trig[m_idx][inverse][k] = NULL;+ }+ }+ }+ }+#if defined(__AVX2__)+ bf_aligned_free(s1, s);+#else+ bf_free(s1, s);+#endif+ s1->ntt_state = NULL;+ }+}++#define STRIP_LEN 16++/* dst = buf1, src = buf2 */+static int ntt_fft_partial(BFNTTState *s, NTTLimb *buf1,+ int k1, int k2, limb_t n1, limb_t n2, int inverse,+ limb_t m_idx)+{+ limb_t i, j, c_mul, c0, m, m_inv, strip_len, l;+ NTTLimb *buf2, *buf3;+ + buf2 = NULL;+ buf3 = ntt_malloc(s, sizeof(NTTLimb) * n1);+ if (!buf3)+ goto fail;+ if (k2 == 0) {+ if (ntt_fft(s, buf1, buf1, buf3, k1, inverse, m_idx))+ goto fail;+ } else {+ strip_len = STRIP_LEN;+ buf2 = ntt_malloc(s, sizeof(NTTLimb) * n1 * strip_len);+ if (!buf2)+ goto fail;+ m = ntt_mods[m_idx];+ m_inv = s->ntt_mods_div[m_idx];+ c0 = s->ntt_proot_pow[m_idx][inverse][k1 + k2];+ c_mul = 1;+ assert((n2 % strip_len) == 0);+ for(j = 0; j < n2; j += strip_len) {+ for(i = 0; i < n1; i++) {+ for(l = 0; l < strip_len; l++) {+ buf2[i + l * n1] = buf1[i * n2 + (j + l)];+ }+ }+ for(l = 0; l < strip_len; l++) {+ if (inverse)+ mul_trig(buf2 + l * n1, n1, c_mul, m, m_inv);+ if (ntt_fft(s, buf2 + l * n1, buf2 + l * n1, buf3, k1, inverse, m_idx))+ goto fail;+ if (!inverse)+ mul_trig(buf2 + l * n1, n1, c_mul, m, m_inv);+ c_mul = mul_mod_fast(c_mul, c0, m, m_inv);+ }+ + for(i = 0; i < n1; i++) {+ for(l = 0; l < strip_len; l++) {+ buf1[i * n2 + (j + l)] = buf2[i + l *n1];+ }+ }+ }+ ntt_free(s, buf2);+ }+ ntt_free(s, buf3);+ return 0;+ fail:+ ntt_free(s, buf2);+ ntt_free(s, buf3);+ return -1;+}+++/* dst = buf1, src = buf2, tmp = buf3 */+static int ntt_conv(BFNTTState *s, NTTLimb *buf1, NTTLimb *buf2,+ int k, int k_tot, limb_t m_idx)+{+ limb_t n1, n2, i;+ int k1, k2;+ + if (k <= NTT_TRIG_K_MAX) {+ k1 = k;+ } else {+ /* recursive split of the FFT */+ k1 = bf_min(k / 2, NTT_TRIG_K_MAX);+ }+ k2 = k - k1;+ n1 = (limb_t)1 << k1;+ n2 = (limb_t)1 << k2;+ + if (ntt_fft_partial(s, buf1, k1, k2, n1, n2, 0, m_idx))+ return -1;+ if (ntt_fft_partial(s, buf2, k1, k2, n1, n2, 0, m_idx))+ return -1;+ if (k2 == 0) {+ ntt_vec_mul(s, buf1, buf2, k, k_tot, m_idx);+ } else {+ for(i = 0; i < n1; i++) {+ ntt_conv(s, buf1 + i * n2, buf2 + i * n2, k2, k_tot, m_idx);+ }+ }+ if (ntt_fft_partial(s, buf1, k1, k2, n1, n2, 1, m_idx))+ return -1;+ return 0;+}+++static no_inline void limb_to_ntt(BFNTTState *s,+ NTTLimb *tabr, limb_t fft_len,+ const limb_t *taba, limb_t a_len, int dpl,+ int first_m_idx, int nb_mods)+{+ slimb_t i, n;+ dlimb_t a, b;+ int j, shift;+ limb_t base_mask1, a0, a1, a2, r, m, m_inv;+ +#if 0+ for(i = 0; i < a_len; i++) {+ printf("%" PRId64 ": " FMT_LIMB "\n",+ (int64_t)i, taba[i]);+ }+#endif + memset(tabr, 0, sizeof(NTTLimb) * fft_len * nb_mods);+ shift = dpl & (LIMB_BITS - 1);+ if (shift == 0)+ base_mask1 = -1;+ else+ base_mask1 = ((limb_t)1 << shift) - 1;+ n = bf_min(fft_len, (a_len * LIMB_BITS + dpl - 1) / dpl);+ for(i = 0; i < n; i++) {+ a0 = get_bits(taba, a_len, i * dpl);+ if (dpl <= LIMB_BITS) {+ a0 &= base_mask1;+ a = a0;+ } else {+ a1 = get_bits(taba, a_len, i * dpl + LIMB_BITS);+ if (dpl <= (LIMB_BITS + NTT_MOD_LOG2_MIN)) {+ a = a0 | ((dlimb_t)(a1 & base_mask1) << LIMB_BITS);+ } else {+ if (dpl > 2 * LIMB_BITS) {+ a2 = get_bits(taba, a_len, i * dpl + LIMB_BITS * 2) &+ base_mask1;+ } else {+ a1 &= base_mask1;+ a2 = 0;+ }+ // printf("a=0x%016lx%016lx%016lx\n", a2, a1, a0);+ a = (a0 >> (LIMB_BITS - NTT_MOD_LOG2_MAX + NTT_MOD_LOG2_MIN)) |+ ((dlimb_t)a1 << (NTT_MOD_LOG2_MAX - NTT_MOD_LOG2_MIN)) |+ ((dlimb_t)a2 << (LIMB_BITS + NTT_MOD_LOG2_MAX - NTT_MOD_LOG2_MIN));+ a0 &= ((limb_t)1 << (LIMB_BITS - NTT_MOD_LOG2_MAX + NTT_MOD_LOG2_MIN)) - 1;+ }+ }+ for(j = 0; j < nb_mods; j++) {+ m = ntt_mods[first_m_idx + j];+ m_inv = s->ntt_mods_div[first_m_idx + j];+ r = mod_fast(a, m, m_inv);+ if (dpl > (LIMB_BITS + NTT_MOD_LOG2_MIN)) {+ b = ((dlimb_t)r << (LIMB_BITS - NTT_MOD_LOG2_MAX + NTT_MOD_LOG2_MIN)) | a0;+ r = mod_fast(b, m, m_inv);+ }+ tabr[i + j * fft_len] = int_to_ntt_limb(r, m);+ }+ }+}++#if defined(__AVX2__)++#define VEC_LEN 4++typedef union {+ __m256d v;+ double d[4];+} VecUnion;++static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len,+ const NTTLimb *buf, int fft_len_log2, int dpl,+ int nb_mods)+{+ const limb_t *mods = ntt_mods + NB_MODS - nb_mods;+ const __m256d *mods_cr_vec, *mf, *m_inv;+ VecUnion y[NB_MODS];+ limb_t u[NB_MODS], carry[NB_MODS], fft_len, base_mask1, r;+ slimb_t i, len, pos;+ int j, k, l, shift, n_limb1, p;+ dlimb_t t;+ + j = NB_MODS * (NB_MODS - 1) / 2 - nb_mods * (nb_mods - 1) / 2;+ mods_cr_vec = s->ntt_mods_cr_vec + j;+ mf = s->ntt_mods_vec + NB_MODS - nb_mods;+ m_inv = s->ntt_mods_inv_vec + NB_MODS - nb_mods;+ + shift = dpl & (LIMB_BITS - 1);+ if (shift == 0)+ base_mask1 = -1;+ else+ base_mask1 = ((limb_t)1 << shift) - 1;+ n_limb1 = ((unsigned)dpl - 1) / LIMB_BITS;+ for(j = 0; j < NB_MODS; j++) + carry[j] = 0;+ for(j = 0; j < NB_MODS; j++) + u[j] = 0; /* avoid warnings */+ memset(tabr, 0, sizeof(limb_t) * r_len);+ fft_len = (limb_t)1 << fft_len_log2;+ len = bf_min(fft_len, (r_len * LIMB_BITS + dpl - 1) / dpl);+ len = (len + VEC_LEN - 1) & ~(VEC_LEN - 1);+ i = 0;+ while (i < len) {+ for(j = 0; j < nb_mods; j++)+ y[j].v = *(__m256d *)&buf[i + fft_len * j];++ /* Chinese remainder to get mixed radix representation */+ l = 0;+ for(j = 0; j < nb_mods - 1; j++) {+ y[j].v = ntt_mod1(y[j].v, mf[j]);+ for(k = j + 1; k < nb_mods; k++) {+ y[k].v = ntt_mul_mod(y[k].v - y[j].v,+ mods_cr_vec[l], mf[k], m_inv[k]);+ l++;+ }+ }+ y[j].v = ntt_mod1(y[j].v, mf[j]);+ + for(p = 0; p < VEC_LEN; p++) {+ /* back to normal representation */+ u[0] = (int64_t)y[nb_mods - 1].d[p];+ l = 1;+ for(j = nb_mods - 2; j >= 1; j--) {+ r = (int64_t)y[j].d[p];+ for(k = 0; k < l; k++) {+ t = (dlimb_t)u[k] * mods[j] + r;+ r = t >> LIMB_BITS;+ u[k] = t;+ }+ u[l] = r;+ l++;+ }+ /* XXX: for nb_mods = 5, l should be 4 */+ + /* last step adds the carry */+ r = (int64_t)y[0].d[p];+ for(k = 0; k < l; k++) {+ t = (dlimb_t)u[k] * mods[j] + r + carry[k];+ r = t >> LIMB_BITS;+ u[k] = t;+ }+ u[l] = r + carry[l];++#if 0+ printf("%" PRId64 ": ", i);+ for(j = nb_mods - 1; j >= 0; j--) {+ printf(" %019" PRIu64, u[j]);+ }+ printf("\n");+#endif+ + /* write the digits */+ pos = i * dpl;+ for(j = 0; j < n_limb1; j++) {+ put_bits(tabr, r_len, pos, u[j]);+ pos += LIMB_BITS;+ }+ put_bits(tabr, r_len, pos, u[n_limb1] & base_mask1);+ /* shift by dpl digits and set the carry */+ if (shift == 0) {+ for(j = n_limb1 + 1; j < nb_mods; j++)+ carry[j - (n_limb1 + 1)] = u[j];+ } else {+ for(j = n_limb1; j < nb_mods - 1; j++) {+ carry[j - n_limb1] = (u[j] >> shift) |+ (u[j + 1] << (LIMB_BITS - shift));+ }+ carry[nb_mods - 1 - n_limb1] = u[nb_mods - 1] >> shift;+ }+ i++;+ }+ }+}+#else+static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len,+ const NTTLimb *buf, int fft_len_log2, int dpl,+ int nb_mods)+{+ const limb_t *mods = ntt_mods + NB_MODS - nb_mods;+ const limb_t *mods_cr, *mods_cr_inv;+ limb_t y[NB_MODS], u[NB_MODS], carry[NB_MODS], fft_len, base_mask1, r;+ slimb_t i, len, pos;+ int j, k, l, shift, n_limb1;+ dlimb_t t;+ + j = NB_MODS * (NB_MODS - 1) / 2 - nb_mods * (nb_mods - 1) / 2;+ mods_cr = ntt_mods_cr + j;+ mods_cr_inv = s->ntt_mods_cr_inv + j;++ shift = dpl & (LIMB_BITS - 1);+ if (shift == 0)+ base_mask1 = -1;+ else+ base_mask1 = ((limb_t)1 << shift) - 1;+ n_limb1 = ((unsigned)dpl - 1) / LIMB_BITS;+ for(j = 0; j < NB_MODS; j++) + carry[j] = 0;+ for(j = 0; j < NB_MODS; j++) + u[j] = 0; /* avoid warnings */+ memset(tabr, 0, sizeof(limb_t) * r_len);+ fft_len = (limb_t)1 << fft_len_log2;+ len = bf_min(fft_len, (r_len * LIMB_BITS + dpl - 1) / dpl);+ for(i = 0; i < len; i++) {+ for(j = 0; j < nb_mods; j++) {+ y[j] = ntt_limb_to_int(buf[i + fft_len * j], mods[j]);+ }++ /* Chinese remainder to get mixed radix representation */+ l = 0;+ for(j = 0; j < nb_mods - 1; j++) {+ for(k = j + 1; k < nb_mods; k++) {+ limb_t m;+ m = mods[k];+ /* Note: there is no overflow in the sub_mod() because+ the modulos are sorted by increasing order */+ y[k] = mul_mod_fast2(y[k] - y[j] + m, + mods_cr[l], m, mods_cr_inv[l]);+ l++;+ }+ }+ + /* back to normal representation */+ u[0] = y[nb_mods - 1];+ l = 1;+ for(j = nb_mods - 2; j >= 1; j--) {+ r = y[j];+ for(k = 0; k < l; k++) {+ t = (dlimb_t)u[k] * mods[j] + r;+ r = t >> LIMB_BITS;+ u[k] = t;+ }+ u[l] = r;+ l++;+ }+ + /* last step adds the carry */+ r = y[0];+ for(k = 0; k < l; k++) {+ t = (dlimb_t)u[k] * mods[j] + r + carry[k];+ r = t >> LIMB_BITS;+ u[k] = t;+ }+ u[l] = r + carry[l];++#if 0+ printf("%" PRId64 ": ", (int64_t)i);+ for(j = nb_mods - 1; j >= 0; j--) {+ printf(" " FMT_LIMB, u[j]);+ }+ printf("\n");+#endif+ + /* write the digits */+ pos = i * dpl;+ for(j = 0; j < n_limb1; j++) {+ put_bits(tabr, r_len, pos, u[j]);+ pos += LIMB_BITS;+ }+ put_bits(tabr, r_len, pos, u[n_limb1] & base_mask1);+ /* shift by dpl digits and set the carry */+ if (shift == 0) {+ for(j = n_limb1 + 1; j < nb_mods; j++)+ carry[j - (n_limb1 + 1)] = u[j];+ } else {+ for(j = n_limb1; j < nb_mods - 1; j++) {+ carry[j - n_limb1] = (u[j] >> shift) |+ (u[j + 1] << (LIMB_BITS - shift));+ }+ carry[nb_mods - 1 - n_limb1] = u[nb_mods - 1] >> shift;+ }+ }+}+#endif++static int ntt_static_init(bf_context_t *s1)+{+ BFNTTState *s;+ int inverse, i, j, k, l;+ limb_t c, c_inv, c_inv2, m, m_inv;++ if (s1->ntt_state)+ return 0;+#if defined(__AVX2__)+ s = bf_aligned_malloc(s1, sizeof(*s), 64);+#else+ s = bf_malloc(s1, sizeof(*s));+#endif+ if (!s)+ return -1;+ memset(s, 0, sizeof(*s));+ s1->ntt_state = s;+ s->ctx = s1;+ + for(j = 0; j < NB_MODS; j++) {+ m = ntt_mods[j];+ m_inv = init_mul_mod_fast(m);+ s->ntt_mods_div[j] = m_inv;+#if defined(__AVX2__)+ s->ntt_mods_vec[j] = _mm256_set1_pd(m);+ s->ntt_mods_inv_vec[j] = _mm256_set1_pd(1.0 / (double)m);+#endif+ c_inv2 = (m + 1) / 2; /* 1/2 */+ c_inv = 1;+ for(i = 0; i <= NTT_PROOT_2EXP; i++) {+ s->ntt_len_inv[j][i][0] = c_inv;+ s->ntt_len_inv[j][i][1] = init_mul_mod_fast2(c_inv, m);+ c_inv = mul_mod_fast(c_inv, c_inv2, m, m_inv);+ }++ for(inverse = 0; inverse < 2; inverse++) {+ c = ntt_proot[inverse][j];+ for(i = 0; i < NTT_PROOT_2EXP; i++) {+ s->ntt_proot_pow[j][inverse][NTT_PROOT_2EXP - i] = c;+ s->ntt_proot_pow_inv[j][inverse][NTT_PROOT_2EXP - i] =+ init_mul_mod_fast2(c, m);+ c = mul_mod_fast(c, c, m, m_inv);+ }+ }+ }++ l = 0;+ for(j = 0; j < NB_MODS - 1; j++) {+ for(k = j + 1; k < NB_MODS; k++) {+#if defined(__AVX2__)+ s->ntt_mods_cr_vec[l] = _mm256_set1_pd(int_to_ntt_limb2(ntt_mods_cr[l],+ ntt_mods[k]));+#else+ s->ntt_mods_cr_inv[l] = init_mul_mod_fast2(ntt_mods_cr[l],+ ntt_mods[k]);+#endif+ l++;+ }+ }+ return 0;+}++int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len)+{+ int dpl, fft_len_log2, n_bits, nb_mods, dpl_found, fft_len_log2_found;+ int int_bits, nb_mods_found;+ limb_t cost, min_cost;+ + min_cost = -1;+ dpl_found = 0;+ nb_mods_found = 4;+ fft_len_log2_found = 0;+ for(nb_mods = 3; nb_mods <= NB_MODS; nb_mods++) {+ int_bits = ntt_int_bits[NB_MODS - nb_mods];+ dpl = bf_min((int_bits - 4) / 2,+ 2 * LIMB_BITS + 2 * NTT_MOD_LOG2_MIN - NTT_MOD_LOG2_MAX);+ for(;;) {+ fft_len_log2 = ceil_log2((len * LIMB_BITS + dpl - 1) / dpl);+ if (fft_len_log2 > NTT_PROOT_2EXP)+ goto next;+ n_bits = fft_len_log2 + 2 * dpl;+ if (n_bits <= int_bits) {+ cost = ((limb_t)(fft_len_log2 + 1) << fft_len_log2) * nb_mods;+ // printf("n=%d dpl=%d: cost=%" PRId64 "\n", nb_mods, dpl, (int64_t)cost);+ if (cost < min_cost) {+ min_cost = cost;+ dpl_found = dpl;+ nb_mods_found = nb_mods;+ fft_len_log2_found = fft_len_log2;+ }+ break;+ }+ dpl--;+ if (dpl == 0)+ break;+ }+ next: ;+ }+ if (!dpl_found)+ abort();+ /* limit dpl if possible to reduce fixed cost of limb/NTT conversion */+ if (dpl_found > (LIMB_BITS + NTT_MOD_LOG2_MIN) &&+ ((limb_t)(LIMB_BITS + NTT_MOD_LOG2_MIN) << fft_len_log2_found) >=+ len * LIMB_BITS) {+ dpl_found = LIMB_BITS + NTT_MOD_LOG2_MIN;+ }+ *pnb_mods = nb_mods_found;+ *pdpl = dpl_found;+ return fft_len_log2_found;+}++/* return 0 if OK, -1 if memory error */+static no_inline int fft_mul(bf_context_t *s1,+ bf_t *res, limb_t *a_tab, limb_t a_len,+ limb_t *b_tab, limb_t b_len, int mul_flags)+{+ BFNTTState *s;+ int dpl, fft_len_log2, j, nb_mods, reduced_mem;+ slimb_t len, fft_len;+ NTTLimb *buf1, *buf2, *ptr;+#if defined(USE_MUL_CHECK)+ limb_t ha, hb, hr, h_ref;+#endif+ + if (ntt_static_init(s1))+ return -1;+ s = s1->ntt_state;+ + /* find the optimal number of digits per limb (dpl) */+ len = a_len + b_len;+ fft_len_log2 = bf_get_fft_size(&dpl, &nb_mods, len);+ fft_len = (uint64_t)1 << fft_len_log2;+ // printf("len=%" PRId64 " fft_len_log2=%d dpl=%d\n", len, fft_len_log2, dpl);+#if defined(USE_MUL_CHECK)+ ha = mp_mod1(a_tab, a_len, BF_CHKSUM_MOD, 0);+ hb = mp_mod1(b_tab, b_len, BF_CHKSUM_MOD, 0);+#endif+ if ((mul_flags & (FFT_MUL_R_OVERLAP_A | FFT_MUL_R_OVERLAP_B)) == 0) {+ if (!(mul_flags & FFT_MUL_R_NORESIZE))+ bf_resize(res, 0);+ } else if (mul_flags & FFT_MUL_R_OVERLAP_B) {+ limb_t *tmp_tab, tmp_len;+ /* it is better to free 'b' first */+ tmp_tab = a_tab;+ a_tab = b_tab;+ b_tab = tmp_tab;+ tmp_len = a_len;+ a_len = b_len;+ b_len = tmp_len;+ }+ buf1 = ntt_malloc(s, sizeof(NTTLimb) * fft_len * nb_mods);+ if (!buf1)+ return -1;+ limb_to_ntt(s, buf1, fft_len, a_tab, a_len, dpl,+ NB_MODS - nb_mods, nb_mods);+ if ((mul_flags & (FFT_MUL_R_OVERLAP_A | FFT_MUL_R_OVERLAP_B)) == + FFT_MUL_R_OVERLAP_A) {+ if (!(mul_flags & FFT_MUL_R_NORESIZE))+ bf_resize(res, 0);+ }+ reduced_mem = (fft_len_log2 >= 14);+ if (!reduced_mem) {+ buf2 = ntt_malloc(s, sizeof(NTTLimb) * fft_len * nb_mods);+ if (!buf2)+ goto fail;+ limb_to_ntt(s, buf2, fft_len, b_tab, b_len, dpl,+ NB_MODS - nb_mods, nb_mods);+ if (!(mul_flags & FFT_MUL_R_NORESIZE))+ bf_resize(res, 0); /* in case res == b */+ } else {+ buf2 = ntt_malloc(s, sizeof(NTTLimb) * fft_len);+ if (!buf2)+ goto fail;+ }+ for(j = 0; j < nb_mods; j++) {+ if (reduced_mem) {+ limb_to_ntt(s, buf2, fft_len, b_tab, b_len, dpl,+ NB_MODS - nb_mods + j, 1);+ ptr = buf2;+ } else {+ ptr = buf2 + fft_len * j;+ }+ if (ntt_conv(s, buf1 + fft_len * j, ptr,+ fft_len_log2, fft_len_log2, j + NB_MODS - nb_mods))+ goto fail;+ }+ if (!(mul_flags & FFT_MUL_R_NORESIZE))+ bf_resize(res, 0); /* in case res == b and reduced mem */+ ntt_free(s, buf2);+ buf2 = NULL;+ if (!(mul_flags & FFT_MUL_R_NORESIZE)) {+ if (bf_resize(res, len))+ goto fail;+ }+ ntt_to_limb(s, res->tab, len, buf1, fft_len_log2, dpl, nb_mods);+ ntt_free(s, buf1);+#if defined(USE_MUL_CHECK)+ hr = mp_mod1(res->tab, len, BF_CHKSUM_MOD, 0);+ h_ref = mul_mod(ha, hb, BF_CHKSUM_MOD);+ if (hr != h_ref) {+ printf("ntt_mul_error: len=%" PRId_LIMB " fft_len_log2=%d dpl=%d nb_mods=%d\n",+ len, fft_len_log2, dpl, nb_mods);+ // printf("ha=0x" FMT_LIMB" hb=0x" FMT_LIMB " hr=0x" FMT_LIMB " expected=0x" FMT_LIMB "\n", ha, hb, hr, h_ref);+ exit(1);+ }+#endif + return 0;+ fail:+ ntt_free(s, buf1);+ ntt_free(s, buf2);+ return -1;+}++#else /* USE_FFT_MUL */++int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len)+{+ return 0;+}++#endif /* !USE_FFT_MUL */
+ libbf-quickjs-2021-03-27/libbf.h view
@@ -0,0 +1,535 @@+/*+ * Tiny arbitrary precision floating point library+ * + * Copyright (c) 2017-2021 Fabrice Bellard+ *+ * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ *+ * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+ * THE SOFTWARE.+ */+#ifndef LIBBF_H+#define LIBBF_H++#include <stddef.h>+#include <stdint.h>++#if INTPTR_MAX >= INT64_MAX+#define LIMB_LOG2_BITS 6+#else+#define LIMB_LOG2_BITS 5+#endif++#define LIMB_BITS (1 << LIMB_LOG2_BITS)++#if LIMB_BITS == 64+typedef __int128 int128_t;+typedef unsigned __int128 uint128_t;+typedef int64_t slimb_t;+typedef uint64_t limb_t;+typedef uint128_t dlimb_t;+#define BF_RAW_EXP_MIN INT64_MIN+#define BF_RAW_EXP_MAX INT64_MAX++#define LIMB_DIGITS 19+#define BF_DEC_BASE UINT64_C(10000000000000000000)++#else++typedef int32_t slimb_t;+typedef uint32_t limb_t;+typedef uint64_t dlimb_t;+#define BF_RAW_EXP_MIN INT32_MIN+#define BF_RAW_EXP_MAX INT32_MAX++#define LIMB_DIGITS 9+#define BF_DEC_BASE 1000000000U++#endif++/* in bits */+/* minimum number of bits for the exponent */+#define BF_EXP_BITS_MIN 3+/* maximum number of bits for the exponent */+#define BF_EXP_BITS_MAX (LIMB_BITS - 3)+/* extended range for exponent, used internally */+#define BF_EXT_EXP_BITS_MAX (BF_EXP_BITS_MAX + 1)+/* minimum possible precision */+#define BF_PREC_MIN 2+/* minimum possible precision */+#define BF_PREC_MAX (((limb_t)1 << (LIMB_BITS - 2)) - 2)+/* some operations support infinite precision */+#define BF_PREC_INF (BF_PREC_MAX + 1) /* infinite precision */++#if LIMB_BITS == 64+#define BF_CHKSUM_MOD (UINT64_C(975620677) * UINT64_C(9795002197))+#else+#define BF_CHKSUM_MOD 975620677U+#endif++#define BF_EXP_ZERO BF_RAW_EXP_MIN+#define BF_EXP_INF (BF_RAW_EXP_MAX - 1)+#define BF_EXP_NAN BF_RAW_EXP_MAX++/* +/-zero is represented with expn = BF_EXP_ZERO and len = 0,+ +/-infinity is represented with expn = BF_EXP_INF and len = 0,+ NaN is represented with expn = BF_EXP_NAN and len = 0 (sign is ignored)+ */+typedef struct {+ struct bf_context_t *ctx;+ int sign;+ slimb_t expn;+ limb_t len;+ limb_t *tab;+} bf_t;++typedef struct {+ /* must be kept identical to bf_t */+ struct bf_context_t *ctx;+ int sign;+ slimb_t expn;+ limb_t len;+ limb_t *tab;+} bfdec_t;++typedef enum {+ BF_RNDN, /* round to nearest, ties to even */+ BF_RNDZ, /* round to zero */+ BF_RNDD, /* round to -inf (the code relies on (BF_RNDD xor BF_RNDU) = 1) */+ BF_RNDU, /* round to +inf */+ BF_RNDNA, /* round to nearest, ties away from zero */+ BF_RNDA, /* round away from zero */+ BF_RNDF, /* faithful rounding (nondeterministic, either RNDD or RNDU,+ inexact flag is always set) */+} bf_rnd_t;++/* allow subnormal numbers. Only available if the number of exponent+ bits is <= BF_EXP_BITS_USER_MAX and prec != BF_PREC_INF. */+#define BF_FLAG_SUBNORMAL (1 << 3)+/* 'prec' is the precision after the radix point instead of the whole+ mantissa. Can only be used with bf_round() and+ bfdec_[add|sub|mul|div|sqrt|round](). */+#define BF_FLAG_RADPNT_PREC (1 << 4)++#define BF_RND_MASK 0x7+#define BF_EXP_BITS_SHIFT 5+#define BF_EXP_BITS_MASK 0x3f++/* shortcut for bf_set_exp_bits(BF_EXT_EXP_BITS_MAX) */+#define BF_FLAG_EXT_EXP (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)++/* contains the rounding mode and number of exponents bits */+typedef uint32_t bf_flags_t;++typedef void *bf_realloc_func_t(void *opaque, void *ptr, size_t size);++typedef struct {+ bf_t val;+ limb_t prec;+} BFConstCache;++typedef struct bf_context_t {+ void *realloc_opaque;+ bf_realloc_func_t *realloc_func;+ BFConstCache log2_cache;+ BFConstCache pi_cache;+ struct BFNTTState *ntt_state;+} bf_context_t;++static inline int bf_get_exp_bits(bf_flags_t flags)+{+ int e;+ e = (flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK;+ if (e == BF_EXP_BITS_MASK)+ return BF_EXP_BITS_MAX + 1;+ else+ return BF_EXP_BITS_MAX - e;+}++static inline bf_flags_t bf_set_exp_bits(int n)+{+ return ((BF_EXP_BITS_MAX - n) & BF_EXP_BITS_MASK) << BF_EXP_BITS_SHIFT;+}++/* returned status */+#define BF_ST_INVALID_OP (1 << 0)+#define BF_ST_DIVIDE_ZERO (1 << 1)+#define BF_ST_OVERFLOW (1 << 2)+#define BF_ST_UNDERFLOW (1 << 3)+#define BF_ST_INEXACT (1 << 4)+/* indicate that a memory allocation error occured. NaN is returned */+#define BF_ST_MEM_ERROR (1 << 5) ++#define BF_RADIX_MAX 36 /* maximum radix for bf_atof() and bf_ftoa() */++static inline slimb_t bf_max(slimb_t a, slimb_t b)+{+ if (a > b)+ return a;+ else+ return b;+}++static inline slimb_t bf_min(slimb_t a, slimb_t b)+{+ if (a < b)+ return a;+ else+ return b;+}++void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func,+ void *realloc_opaque);+void bf_context_end(bf_context_t *s);+/* free memory allocated for the bf cache data */+void bf_clear_cache(bf_context_t *s);++static inline void *bf_realloc(bf_context_t *s, void *ptr, size_t size)+{+ return s->realloc_func(s->realloc_opaque, ptr, size);+}++/* 'size' must be != 0 */+static inline void *bf_malloc(bf_context_t *s, size_t size)+{+ return bf_realloc(s, NULL, size);+}++static inline void bf_free(bf_context_t *s, void *ptr)+{+ /* must test ptr otherwise equivalent to malloc(0) */+ if (ptr)+ bf_realloc(s, ptr, 0);+}++void bf_init(bf_context_t *s, bf_t *r);++static inline void bf_delete(bf_t *r)+{+ bf_context_t *s = r->ctx;+ /* we accept to delete a zeroed bf_t structure */+ if (s && r->tab) {+ bf_realloc(s, r->tab, 0);+ }+}++static inline void bf_neg(bf_t *r)+{+ r->sign ^= 1;+}++static inline int bf_is_finite(const bf_t *a)+{+ return (a->expn < BF_EXP_INF);+}++static inline int bf_is_nan(const bf_t *a)+{+ return (a->expn == BF_EXP_NAN);+}++static inline int bf_is_zero(const bf_t *a)+{+ return (a->expn == BF_EXP_ZERO);+}++static inline void bf_memcpy(bf_t *r, const bf_t *a)+{+ *r = *a;+}++int bf_set_ui(bf_t *r, uint64_t a);+int bf_set_si(bf_t *r, int64_t a);+void bf_set_nan(bf_t *r);+void bf_set_zero(bf_t *r, int is_neg);+void bf_set_inf(bf_t *r, int is_neg);+int bf_set(bf_t *r, const bf_t *a);+void bf_move(bf_t *r, bf_t *a);+int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode);+int bf_set_float64(bf_t *a, double d);++int bf_cmpu(const bf_t *a, const bf_t *b);+int bf_cmp_full(const bf_t *a, const bf_t *b);+int bf_cmp(const bf_t *a, const bf_t *b);+static inline int bf_cmp_eq(const bf_t *a, const bf_t *b)+{+ return bf_cmp(a, b) == 0;+}++static inline int bf_cmp_le(const bf_t *a, const bf_t *b)+{+ return bf_cmp(a, b) <= 0;+}++static inline int bf_cmp_lt(const bf_t *a, const bf_t *b)+{+ return bf_cmp(a, b) < 0;+}++int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);+int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);+int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags);+int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);+int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec, bf_flags_t flags);+int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, + bf_flags_t flags);+int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags);+int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);+#define BF_DIVREM_EUCLIDIAN BF_RNDF+int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,+ limb_t prec, bf_flags_t flags, int rnd_mode);+int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,+ bf_flags_t flags, int rnd_mode);+int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,+ bf_flags_t flags, int rnd_mode);+/* round to integer with infinite precision */+int bf_rint(bf_t *r, int rnd_mode);+int bf_round(bf_t *r, limb_t prec, bf_flags_t flags);+int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a);+int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);+slimb_t bf_get_exp_min(const bf_t *a);+int bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b);+int bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b);+int bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b);++/* additional flags for bf_atof */+/* do not accept hex radix prefix (0x or 0X) if radix = 0 or radix = 16 */+#define BF_ATOF_NO_HEX (1 << 16)+/* accept binary (0b or 0B) or octal (0o or 0O) radix prefix if radix = 0 */+#define BF_ATOF_BIN_OCT (1 << 17)+/* Do not parse NaN or Inf */+#define BF_ATOF_NO_NAN_INF (1 << 18)+/* return the exponent separately */+#define BF_ATOF_EXPONENT (1 << 19)++int bf_atof(bf_t *a, const char *str, const char **pnext, int radix,+ limb_t prec, bf_flags_t flags);+/* this version accepts prec = BF_PREC_INF and returns the radix+ exponent */+int bf_atof2(bf_t *r, slimb_t *pexponent,+ const char *str, const char **pnext, int radix,+ limb_t prec, bf_flags_t flags);+int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,+ slimb_t expn, limb_t prec, bf_flags_t flags);+++/* Conversion of floating point number to string. Return a null+ terminated string or NULL if memory error. *plen contains its+ length if plen != NULL. The exponent letter is "e" for base 10,+ "p" for bases 2, 8, 16 with a binary exponent and "@" for the other+ bases. */++#define BF_FTOA_FORMAT_MASK (3 << 16)++/* fixed format: prec significant digits rounded with (flags &+ BF_RND_MASK). Exponential notation is used if too many zeros are+ needed.*/+#define BF_FTOA_FORMAT_FIXED (0 << 16)+/* fractional format: prec digits after the decimal point rounded with+ (flags & BF_RND_MASK) */+#define BF_FTOA_FORMAT_FRAC (1 << 16)+/* free format: + + For binary radices with bf_ftoa() and for bfdec_ftoa(): use the minimum+ number of digits to represent 'a'. The precision and the rounding+ mode are ignored.+ + For the non binary radices with bf_ftoa(): use as many digits as+ necessary so that bf_atof() return the same number when using+ precision 'prec', rounding to nearest and the subnormal+ configuration of 'flags'. The result is meaningful only if 'a' is+ already rounded to 'prec' bits. If the subnormal flag is set, the+ exponent in 'flags' must also be set to the desired exponent range.+*/+#define BF_FTOA_FORMAT_FREE (2 << 16)+/* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits+ (takes more computation time). Identical to BF_FTOA_FORMAT_FREE for+ binary radices with bf_ftoa() and for bfdec_ftoa(). */+#define BF_FTOA_FORMAT_FREE_MIN (3 << 16)++/* force exponential notation for fixed or free format */+#define BF_FTOA_FORCE_EXP (1 << 20)+/* add 0x prefix for base 16, 0o prefix for base 8 or 0b prefix for+ base 2 if non zero value */+#define BF_FTOA_ADD_PREFIX (1 << 21)+/* return "Infinity" instead of "Inf" and add a "+" for positive+ exponents */+#define BF_FTOA_JS_QUIRKS (1 << 22)++char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec,+ bf_flags_t flags);++/* modulo 2^n instead of saturation. NaN and infinity return 0 */+#define BF_GET_INT_MOD (1 << 0) +int bf_get_int32(int *pres, const bf_t *a, int flags);+int bf_get_int64(int64_t *pres, const bf_t *a, int flags);+int bf_get_uint64(uint64_t *pres, const bf_t *a);++/* the following functions are exported for testing only. */+void mp_print_str(const char *str, const limb_t *tab, limb_t n);+void bf_print_str(const char *str, const bf_t *a);+int bf_resize(bf_t *r, limb_t len);+int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len);+int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags);+int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k);+slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv,+ int is_ceil1);+int mp_mul(bf_context_t *s, limb_t *result, + const limb_t *op1, limb_t op1_size, + const limb_t *op2, limb_t op2_size);+limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2, + limb_t n, limb_t carry);+limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n);+int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n);+int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n);+limb_t bf_isqrt(limb_t a);++/* transcendental functions */+int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags);+int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags);+int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);+int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);+#define BF_POW_JS_QUIRKS (1 << 16) /* (+/-1)^(+/-Inf) = NaN, 1^NaN = NaN */+int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags);+int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);+int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);+int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);+int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);+int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x,+ limb_t prec, bf_flags_t flags);+int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);+int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);++/* decimal floating point */++static inline void bfdec_init(bf_context_t *s, bfdec_t *r)+{+ bf_init(s, (bf_t *)r);+}+static inline void bfdec_delete(bfdec_t *r)+{+ bf_delete((bf_t *)r);+}++static inline void bfdec_neg(bfdec_t *r)+{+ r->sign ^= 1;+}++static inline int bfdec_is_finite(const bfdec_t *a)+{+ return (a->expn < BF_EXP_INF);+}++static inline int bfdec_is_nan(const bfdec_t *a)+{+ return (a->expn == BF_EXP_NAN);+}++static inline int bfdec_is_zero(const bfdec_t *a)+{+ return (a->expn == BF_EXP_ZERO);+}++static inline void bfdec_memcpy(bfdec_t *r, const bfdec_t *a)+{+ bf_memcpy((bf_t *)r, (const bf_t *)a);+}++int bfdec_set_ui(bfdec_t *r, uint64_t a);+int bfdec_set_si(bfdec_t *r, int64_t a);++static inline void bfdec_set_nan(bfdec_t *r)+{+ bf_set_nan((bf_t *)r);+}+static inline void bfdec_set_zero(bfdec_t *r, int is_neg)+{+ bf_set_zero((bf_t *)r, is_neg);+}+static inline void bfdec_set_inf(bfdec_t *r, int is_neg)+{+ bf_set_inf((bf_t *)r, is_neg);+}+static inline int bfdec_set(bfdec_t *r, const bfdec_t *a)+{+ return bf_set((bf_t *)r, (bf_t *)a);+}+static inline void bfdec_move(bfdec_t *r, bfdec_t *a)+{+ bf_move((bf_t *)r, (bf_t *)a);+}+static inline int bfdec_cmpu(const bfdec_t *a, const bfdec_t *b)+{+ return bf_cmpu((const bf_t *)a, (const bf_t *)b);+}+static inline int bfdec_cmp_full(const bfdec_t *a, const bfdec_t *b)+{+ return bf_cmp_full((const bf_t *)a, (const bf_t *)b);+}+static inline int bfdec_cmp(const bfdec_t *a, const bfdec_t *b)+{+ return bf_cmp((const bf_t *)a, (const bf_t *)b);+}+static inline int bfdec_cmp_eq(const bfdec_t *a, const bfdec_t *b)+{+ return bfdec_cmp(a, b) == 0;+}+static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b)+{+ return bfdec_cmp(a, b) <= 0;+}+static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b)+{+ return bfdec_cmp(a, b) < 0;+}++int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,+ bf_flags_t flags);+int bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,+ bf_flags_t flags);+int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,+ bf_flags_t flags);+int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,+ bf_flags_t flags);+int bfdec_mul_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,+ bf_flags_t flags);+int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,+ bf_flags_t flags);+int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,+ limb_t prec, bf_flags_t flags, int rnd_mode);+int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,+ bf_flags_t flags, int rnd_mode);+int bfdec_rint(bfdec_t *r, int rnd_mode);+int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags);+int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags);+int bfdec_get_int32(int *pres, const bfdec_t *a);+int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b);++char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags);+int bfdec_atof(bfdec_t *r, const char *str, const char **pnext,+ limb_t prec, bf_flags_t flags);++/* the following functions are exported for testing only. */+extern const limb_t mp_pow_dec[LIMB_DIGITS + 1];+void bfdec_print_str(const char *str, const bfdec_t *a);+static inline int bfdec_resize(bfdec_t *r, limb_t len)+{+ return bf_resize((bf_t *)r, len);+}+int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags);++#endif /* LIBBF_H */
tests/RunUnitTests.hs view
@@ -1,6 +1,7 @@ {-# Language BlockArguments #-} module Main(main) where +import Data.Foldable(traverse_) import System.Exit(exitFailure) import System.IO(hPutStrLn,stderr) import Control.Monad(unless)@@ -15,6 +16,8 @@ print $ bfFromString 10 (expBits 3 <> precBits 2 <> rnd ToZero) "1.0e200" dblTest "+" (+) (bfAdd (float64 NearEven)) 1 2 dblTest "/" (/) (bfDiv (float64 NearEven)) 1 0+ traverse_ (\bf -> bfSubnormalTest bf False)+ [bfPosZero, bfFromInt 1, bfFromInt 0, bfNaN, bfNegInf, bfPosInf] check :: String -> Bool -> IO () check x b = unless b@@ -40,5 +43,9 @@ (res1,Ok) -> Right res1 (_, s) -> Left ("result: " ++ show s) --+-- Check that calling bfIsSubnormal on a BigFloat value returns the expected+-- result.+bfSubnormalTest :: BigFloat -> Bool -> IO ()+bfSubnormalTest bf expected =+ check ("bfIsSubnormal (float32 NearEven) " ++ show bf)+ (bfIsSubnormal (float32 NearEven) bf == expected)