150696a6eSStefan Eßer /* 250696a6eSStefan Eßer * ***************************************************************************** 350696a6eSStefan Eßer * 450696a6eSStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 550696a6eSStefan Eßer * 6*a970610aSStefan Eßer * Copyright (c) 2018-2024 Gavin D. Howard and contributors. 750696a6eSStefan Eßer * 850696a6eSStefan Eßer * Redistribution and use in source and binary forms, with or without 950696a6eSStefan Eßer * modification, are permitted provided that the following conditions are met: 1050696a6eSStefan Eßer * 1150696a6eSStefan Eßer * * Redistributions of source code must retain the above copyright notice, this 1250696a6eSStefan Eßer * list of conditions and the following disclaimer. 1350696a6eSStefan Eßer * 1450696a6eSStefan Eßer * * Redistributions in binary form must reproduce the above copyright notice, 1550696a6eSStefan Eßer * this list of conditions and the following disclaimer in the documentation 1650696a6eSStefan Eßer * and/or other materials provided with the distribution. 1750696a6eSStefan Eßer * 1850696a6eSStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1950696a6eSStefan Eßer * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2050696a6eSStefan Eßer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2150696a6eSStefan Eßer * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 2250696a6eSStefan Eßer * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2350696a6eSStefan Eßer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2450696a6eSStefan Eßer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2550696a6eSStefan Eßer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2650696a6eSStefan Eßer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2750696a6eSStefan Eßer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2850696a6eSStefan Eßer * POSSIBILITY OF SUCH DAMAGE. 2950696a6eSStefan Eßer * 3050696a6eSStefan Eßer * ***************************************************************************** 3150696a6eSStefan Eßer * 3250696a6eSStefan Eßer * The public functions for libbc. 3350696a6eSStefan Eßer * 3450696a6eSStefan Eßer */ 3550696a6eSStefan Eßer 3650696a6eSStefan Eßer #if BC_ENABLE_LIBRARY 3750696a6eSStefan Eßer 3850696a6eSStefan Eßer #include <setjmp.h> 3950696a6eSStefan Eßer #include <string.h> 4050696a6eSStefan Eßer #include <time.h> 4150696a6eSStefan Eßer 4250696a6eSStefan Eßer #include <bcl.h> 4350696a6eSStefan Eßer 4450696a6eSStefan Eßer #include <library.h> 4550696a6eSStefan Eßer #include <num.h> 4650696a6eSStefan Eßer #include <vm.h> 4750696a6eSStefan Eßer 48d101cdd6SStefan Eßer #ifndef _WIN32 49d101cdd6SStefan Eßer #include <pthread.h> 50d101cdd6SStefan Eßer #endif // _WIN32 51d101cdd6SStefan Eßer 5244d4804dSStefan Eßer // The asserts in this file are important to testing; in many cases, the test 5344d4804dSStefan Eßer // would not work without the asserts, so don't remove them without reason. 5444d4804dSStefan Eßer // 5544d4804dSStefan Eßer // Also, there are many uses of bc_num_clear() here; that is because numbers are 5644d4804dSStefan Eßer // being reused, and a clean slate is required. 5744d4804dSStefan Eßer // 58d101cdd6SStefan Eßer // Also, there are a bunch of BC_UNSETJMP between calls to bc_num_init(). That 59d101cdd6SStefan Eßer // is because locals are being initialized, and unlike bc proper, this code 60d101cdd6SStefan Eßer // cannot assume that allocation failures are fatal. So we have to reset the 61d101cdd6SStefan Eßer // jumps every time to ensure that the locals will be correct after jumping. 6250696a6eSStefan Eßer 63175a4d10SStefan Eßer #if BC_ENABLE_MEMCHECK 64175a4d10SStefan Eßer 65175a4d10SStefan Eßer BC_NORETURN void 66175a4d10SStefan Eßer bcl_invalidGeneration(void) 67175a4d10SStefan Eßer { 68175a4d10SStefan Eßer abort(); 69175a4d10SStefan Eßer } 70175a4d10SStefan Eßer 71175a4d10SStefan Eßer BC_NORETURN void 72175a4d10SStefan Eßer bcl_nonexistentNum(void) 73175a4d10SStefan Eßer { 74175a4d10SStefan Eßer abort(); 75175a4d10SStefan Eßer } 76175a4d10SStefan Eßer 77175a4d10SStefan Eßer BC_NORETURN void 78175a4d10SStefan Eßer bcl_numIdxOutOfRange(void) 79175a4d10SStefan Eßer { 80175a4d10SStefan Eßer abort(); 81175a4d10SStefan Eßer } 82175a4d10SStefan Eßer 83175a4d10SStefan Eßer #endif // BC_ENABLE_MEMCHECK 84175a4d10SStefan Eßer 85d101cdd6SStefan Eßer static BclTls* tls = NULL; 86d101cdd6SStefan Eßer static BclTls tls_real; 87d101cdd6SStefan Eßer 88d101cdd6SStefan Eßer BclError 89d101cdd6SStefan Eßer bcl_start(void) 9078bc019dSStefan Eßer { 91d101cdd6SStefan Eßer #ifndef _WIN32 9250696a6eSStefan Eßer 93d101cdd6SStefan Eßer int r; 9450696a6eSStefan Eßer 95d101cdd6SStefan Eßer if (tls != NULL) return BCL_ERROR_NONE; 9650696a6eSStefan Eßer 97d101cdd6SStefan Eßer r = pthread_key_create(&tls_real, NULL); 98d101cdd6SStefan Eßer if (BC_ERR(r != 0)) return BCL_ERROR_FATAL_ALLOC_ERR; 99d101cdd6SStefan Eßer 100d101cdd6SStefan Eßer #else // _WIN32 101d101cdd6SStefan Eßer 102d101cdd6SStefan Eßer if (tls != NULL) return BCL_ERROR_NONE; 103d101cdd6SStefan Eßer 104d101cdd6SStefan Eßer tls_real = TlsAlloc(); 105d101cdd6SStefan Eßer if (BC_ERR(tls_real == TLS_OUT_OF_INDEXES)) 106d101cdd6SStefan Eßer { 107d101cdd6SStefan Eßer return BCL_ERROR_FATAL_ALLOC_ERR; 10850696a6eSStefan Eßer } 10950696a6eSStefan Eßer 110d101cdd6SStefan Eßer #endif // _WIN32 111d101cdd6SStefan Eßer 112d101cdd6SStefan Eßer tls = &tls_real; 113d101cdd6SStefan Eßer 114d101cdd6SStefan Eßer return BCL_ERROR_NONE; 115d101cdd6SStefan Eßer } 116d101cdd6SStefan Eßer 117d101cdd6SStefan Eßer /** 118d101cdd6SStefan Eßer * Sets the thread-specific data for the thread. 119d101cdd6SStefan Eßer * @param vm The @a BcVm to set as the thread data. 120d101cdd6SStefan Eßer * @return An error code, if any. 121d101cdd6SStefan Eßer */ 122d101cdd6SStefan Eßer static BclError 123d101cdd6SStefan Eßer bcl_setspecific(BcVm* vm) 12478bc019dSStefan Eßer { 125d101cdd6SStefan Eßer #ifndef _WIN32 126d101cdd6SStefan Eßer 127d101cdd6SStefan Eßer int r; 128d101cdd6SStefan Eßer 129d101cdd6SStefan Eßer assert(tls != NULL); 130d101cdd6SStefan Eßer 131d101cdd6SStefan Eßer r = pthread_setspecific(tls_real, vm); 132d101cdd6SStefan Eßer if (BC_ERR(r != 0)) return BCL_ERROR_FATAL_ALLOC_ERR; 133d101cdd6SStefan Eßer 134d101cdd6SStefan Eßer #else // _WIN32 135d101cdd6SStefan Eßer 136d101cdd6SStefan Eßer bool r; 137d101cdd6SStefan Eßer 138d101cdd6SStefan Eßer assert(tls != NULL); 139d101cdd6SStefan Eßer 140d101cdd6SStefan Eßer r = TlsSetValue(tls_real, vm); 141d101cdd6SStefan Eßer if (BC_ERR(!r)) return BCL_ERROR_FATAL_ALLOC_ERR; 142d101cdd6SStefan Eßer 143d101cdd6SStefan Eßer #endif // _WIN32 144d101cdd6SStefan Eßer 145d101cdd6SStefan Eßer return BCL_ERROR_NONE; 146d101cdd6SStefan Eßer } 147d101cdd6SStefan Eßer 148d101cdd6SStefan Eßer BcVm* 149d101cdd6SStefan Eßer bcl_getspecific(void) 150d101cdd6SStefan Eßer { 151d101cdd6SStefan Eßer BcVm* vm; 152d101cdd6SStefan Eßer 153d101cdd6SStefan Eßer #ifndef _WIN32 154d101cdd6SStefan Eßer 155d101cdd6SStefan Eßer vm = pthread_getspecific(tls_real); 156d101cdd6SStefan Eßer 157d101cdd6SStefan Eßer #else // _WIN32 158d101cdd6SStefan Eßer 159d101cdd6SStefan Eßer vm = TlsGetValue(tls_real); 160d101cdd6SStefan Eßer 161d101cdd6SStefan Eßer #endif // _WIN32 162d101cdd6SStefan Eßer 163d101cdd6SStefan Eßer return vm; 16450696a6eSStefan Eßer } 16550696a6eSStefan Eßer 16678bc019dSStefan Eßer BclError 16778bc019dSStefan Eßer bcl_init(void) 16878bc019dSStefan Eßer { 16950696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 170d101cdd6SStefan Eßer BcVm* vm; 17150696a6eSStefan Eßer 172d101cdd6SStefan Eßer assert(tls != NULL); 17310041e99SStefan Eßer 174d101cdd6SStefan Eßer vm = bcl_getspecific(); 175d101cdd6SStefan Eßer if (vm != NULL) 17678bc019dSStefan Eßer { 177d101cdd6SStefan Eßer assert(vm->refs >= 1); 178d101cdd6SStefan Eßer 179d101cdd6SStefan Eßer vm->refs += 1; 180d101cdd6SStefan Eßer 18110041e99SStefan Eßer return e; 18210041e99SStefan Eßer } 18350696a6eSStefan Eßer 184d101cdd6SStefan Eßer vm = bc_vm_malloc(sizeof(BcVm)); 185d101cdd6SStefan Eßer if (BC_ERR(vm == NULL)) return BCL_ERROR_FATAL_ALLOC_ERR; 186d101cdd6SStefan Eßer 187d101cdd6SStefan Eßer e = bcl_setspecific(vm); 188d101cdd6SStefan Eßer if (BC_ERR(e != BCL_ERROR_NONE)) 189d101cdd6SStefan Eßer { 190d101cdd6SStefan Eßer free(vm); 191d101cdd6SStefan Eßer return e; 192d101cdd6SStefan Eßer } 193d101cdd6SStefan Eßer 194d101cdd6SStefan Eßer memset(vm, 0, sizeof(BcVm)); 195d101cdd6SStefan Eßer 196d101cdd6SStefan Eßer vm->refs += 1; 197d101cdd6SStefan Eßer 198d101cdd6SStefan Eßer assert(vm->refs == 1); 199d101cdd6SStefan Eßer 20044d4804dSStefan Eßer // Setting these to NULL ensures that if an error occurs, we only free what 20144d4804dSStefan Eßer // is necessary. 202d101cdd6SStefan Eßer vm->ctxts.v = NULL; 203d101cdd6SStefan Eßer vm->jmp_bufs.v = NULL; 204d101cdd6SStefan Eßer vm->out.v = NULL; 20550696a6eSStefan Eßer 206d101cdd6SStefan Eßer vm->abrt = false; 207d101cdd6SStefan Eßer vm->leading_zeroes = false; 208d101cdd6SStefan Eßer vm->digit_clamp = true; 20950696a6eSStefan Eßer 21044d4804dSStefan Eßer // The jmp_bufs always has to be initialized first. 211d101cdd6SStefan Eßer bc_vec_init(&vm->jmp_bufs, sizeof(sigjmp_buf), BC_DTOR_NONE); 21250696a6eSStefan Eßer 213d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 21450696a6eSStefan Eßer 21550696a6eSStefan Eßer bc_vm_init(); 21650696a6eSStefan Eßer 217d101cdd6SStefan Eßer bc_vec_init(&vm->ctxts, sizeof(BclContext), BC_DTOR_NONE); 218d101cdd6SStefan Eßer bc_vec_init(&vm->out, sizeof(uchar), BC_DTOR_NONE); 21950696a6eSStefan Eßer 220175a4d10SStefan Eßer #if BC_ENABLE_EXTRA_MATH 221175a4d10SStefan Eßer 222175a4d10SStefan Eßer // We need to seed this in case /dev/random and /dev/urandom don't work. 22350696a6eSStefan Eßer srand((unsigned int) time(NULL)); 224d101cdd6SStefan Eßer bc_rand_init(&vm->rng); 22550696a6eSStefan Eßer 226175a4d10SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 227175a4d10SStefan Eßer 22850696a6eSStefan Eßer err: 229d101cdd6SStefan Eßer 230103d7cdfSStefan Eßer BC_FUNC_FOOTER(vm, e); 231103d7cdfSStefan Eßer 23244d4804dSStefan Eßer // This is why we had to set them to NULL. 233d101cdd6SStefan Eßer if (BC_ERR(vm != NULL && vm->err)) 23478bc019dSStefan Eßer { 235d101cdd6SStefan Eßer if (vm->out.v != NULL) bc_vec_free(&vm->out); 236d101cdd6SStefan Eßer if (vm->jmp_bufs.v != NULL) bc_vec_free(&vm->jmp_bufs); 237d101cdd6SStefan Eßer if (vm->ctxts.v != NULL) bc_vec_free(&vm->ctxts); 238d101cdd6SStefan Eßer bcl_setspecific(NULL); 239d101cdd6SStefan Eßer free(vm); 24050696a6eSStefan Eßer } 24150696a6eSStefan Eßer 24250696a6eSStefan Eßer return e; 24350696a6eSStefan Eßer } 24450696a6eSStefan Eßer 24578bc019dSStefan Eßer BclError 24678bc019dSStefan Eßer bcl_pushContext(BclContext ctxt) 24778bc019dSStefan Eßer { 24850696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 249d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 25050696a6eSStefan Eßer 251d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 25250696a6eSStefan Eßer 253d101cdd6SStefan Eßer bc_vec_push(&vm->ctxts, &ctxt); 25450696a6eSStefan Eßer 25550696a6eSStefan Eßer err: 256175a4d10SStefan Eßer 257d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 25850696a6eSStefan Eßer return e; 25950696a6eSStefan Eßer } 26050696a6eSStefan Eßer 26178bc019dSStefan Eßer void 26278bc019dSStefan Eßer bcl_popContext(void) 26378bc019dSStefan Eßer { 264d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 265d101cdd6SStefan Eßer 266d101cdd6SStefan Eßer if (vm->ctxts.len) bc_vec_pop(&vm->ctxts); 267d101cdd6SStefan Eßer } 268d101cdd6SStefan Eßer 269d101cdd6SStefan Eßer static BclContext 270d101cdd6SStefan Eßer bcl_contextHelper(BcVm* vm) 271d101cdd6SStefan Eßer { 272d101cdd6SStefan Eßer if (!vm->ctxts.len) return NULL; 273d101cdd6SStefan Eßer return *((BclContext*) bc_vec_top(&vm->ctxts)); 27450696a6eSStefan Eßer } 27550696a6eSStefan Eßer 27678bc019dSStefan Eßer BclContext 27778bc019dSStefan Eßer bcl_context(void) 27878bc019dSStefan Eßer { 279d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 280d101cdd6SStefan Eßer return bcl_contextHelper(vm); 28150696a6eSStefan Eßer } 28250696a6eSStefan Eßer 28378bc019dSStefan Eßer void 28478bc019dSStefan Eßer bcl_free(void) 28578bc019dSStefan Eßer { 28644d4804dSStefan Eßer size_t i; 287d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 28844d4804dSStefan Eßer 289d101cdd6SStefan Eßer vm->refs -= 1; 290d101cdd6SStefan Eßer if (vm->refs) return; 29110041e99SStefan Eßer 292175a4d10SStefan Eßer #if BC_ENABLE_EXTRA_MATH 293d101cdd6SStefan Eßer bc_rand_free(&vm->rng); 294175a4d10SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 295d101cdd6SStefan Eßer bc_vec_free(&vm->out); 29650696a6eSStefan Eßer 297d101cdd6SStefan Eßer for (i = 0; i < vm->ctxts.len; ++i) 29878bc019dSStefan Eßer { 299d101cdd6SStefan Eßer BclContext ctxt = *((BclContext*) bc_vec_item(&vm->ctxts, i)); 30050696a6eSStefan Eßer bcl_ctxt_free(ctxt); 30150696a6eSStefan Eßer } 30250696a6eSStefan Eßer 303d101cdd6SStefan Eßer bc_vec_free(&vm->ctxts); 30450696a6eSStefan Eßer 30510328f8bSStefan Eßer bc_vm_atexit(); 30650696a6eSStefan Eßer 307d101cdd6SStefan Eßer free(vm); 308d101cdd6SStefan Eßer bcl_setspecific(NULL); 309d101cdd6SStefan Eßer } 31050696a6eSStefan Eßer 311d101cdd6SStefan Eßer void 312d101cdd6SStefan Eßer bcl_end(void) 313d101cdd6SStefan Eßer { 314d101cdd6SStefan Eßer #ifndef _WIN32 31550696a6eSStefan Eßer 316d101cdd6SStefan Eßer // We ignore the return value. 317d101cdd6SStefan Eßer pthread_key_delete(tls_real); 318d101cdd6SStefan Eßer 319d101cdd6SStefan Eßer #else // _WIN32 320d101cdd6SStefan Eßer 321d101cdd6SStefan Eßer // We ignore the return value. 322d101cdd6SStefan Eßer TlsFree(tls_real); 323d101cdd6SStefan Eßer 324d101cdd6SStefan Eßer #endif // _WIN32 325d101cdd6SStefan Eßer 326d101cdd6SStefan Eßer tls = NULL; 32750696a6eSStefan Eßer } 32850696a6eSStefan Eßer 32978bc019dSStefan Eßer void 33078bc019dSStefan Eßer bcl_gc(void) 33178bc019dSStefan Eßer { 33250696a6eSStefan Eßer bc_vm_freeTemps(); 33350696a6eSStefan Eßer } 33450696a6eSStefan Eßer 33578bc019dSStefan Eßer bool 33678bc019dSStefan Eßer bcl_abortOnFatalError(void) 33778bc019dSStefan Eßer { 338d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 339d101cdd6SStefan Eßer 340d101cdd6SStefan Eßer return vm->abrt; 34150696a6eSStefan Eßer } 34250696a6eSStefan Eßer 34378bc019dSStefan Eßer void 34478bc019dSStefan Eßer bcl_setAbortOnFatalError(bool abrt) 34578bc019dSStefan Eßer { 346d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 347d101cdd6SStefan Eßer 348d101cdd6SStefan Eßer vm->abrt = abrt; 34950696a6eSStefan Eßer } 35050696a6eSStefan Eßer 35178bc019dSStefan Eßer bool 35278bc019dSStefan Eßer bcl_leadingZeroes(void) 35378bc019dSStefan Eßer { 354d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 355d101cdd6SStefan Eßer 356d101cdd6SStefan Eßer return vm->leading_zeroes; 357d43fa8efSStefan Eßer } 358d43fa8efSStefan Eßer 35978bc019dSStefan Eßer void 36078bc019dSStefan Eßer bcl_setLeadingZeroes(bool leadingZeroes) 36178bc019dSStefan Eßer { 362d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 363d101cdd6SStefan Eßer 364d101cdd6SStefan Eßer vm->leading_zeroes = leadingZeroes; 365d101cdd6SStefan Eßer } 366d101cdd6SStefan Eßer 367d101cdd6SStefan Eßer bool 368d101cdd6SStefan Eßer bcl_digitClamp(void) 369d101cdd6SStefan Eßer { 370d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 371d101cdd6SStefan Eßer 372d101cdd6SStefan Eßer return vm->digit_clamp; 373d101cdd6SStefan Eßer } 374d101cdd6SStefan Eßer 375d101cdd6SStefan Eßer void 376d101cdd6SStefan Eßer bcl_setDigitClamp(bool digitClamp) 377d101cdd6SStefan Eßer { 378d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 379d101cdd6SStefan Eßer 380d101cdd6SStefan Eßer vm->digit_clamp = digitClamp; 381d43fa8efSStefan Eßer } 382d43fa8efSStefan Eßer 38378bc019dSStefan Eßer BclContext 38478bc019dSStefan Eßer bcl_ctxt_create(void) 38578bc019dSStefan Eßer { 386d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 38750696a6eSStefan Eßer BclContext ctxt = NULL; 38850696a6eSStefan Eßer 389d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 39050696a6eSStefan Eßer 39144d4804dSStefan Eßer // We want the context to be free of any interference of other parties, so 39244d4804dSStefan Eßer // malloc() is appropriate here. 39350696a6eSStefan Eßer ctxt = bc_vm_malloc(sizeof(BclCtxt)); 39450696a6eSStefan Eßer 395175a4d10SStefan Eßer bc_vec_init(&ctxt->nums, sizeof(BclNum), BC_DTOR_BCL_NUM); 39644d4804dSStefan Eßer bc_vec_init(&ctxt->free_nums, sizeof(BclNumber), BC_DTOR_NONE); 39750696a6eSStefan Eßer 39850696a6eSStefan Eßer ctxt->scale = 0; 39950696a6eSStefan Eßer ctxt->ibase = 10; 40050696a6eSStefan Eßer ctxt->obase = 10; 40150696a6eSStefan Eßer 40250696a6eSStefan Eßer err: 403d101cdd6SStefan Eßer 404d101cdd6SStefan Eßer if (BC_ERR(vm->err && ctxt != NULL)) 40578bc019dSStefan Eßer { 40650696a6eSStefan Eßer if (ctxt->nums.v != NULL) bc_vec_free(&ctxt->nums); 40750696a6eSStefan Eßer free(ctxt); 40850696a6eSStefan Eßer ctxt = NULL; 40950696a6eSStefan Eßer } 41050696a6eSStefan Eßer 411d101cdd6SStefan Eßer BC_FUNC_FOOTER_NO_ERR(vm); 41250696a6eSStefan Eßer 41350696a6eSStefan Eßer return ctxt; 41450696a6eSStefan Eßer } 41550696a6eSStefan Eßer 41678bc019dSStefan Eßer void 41778bc019dSStefan Eßer bcl_ctxt_free(BclContext ctxt) 41878bc019dSStefan Eßer { 41950696a6eSStefan Eßer bc_vec_free(&ctxt->free_nums); 42050696a6eSStefan Eßer bc_vec_free(&ctxt->nums); 42150696a6eSStefan Eßer free(ctxt); 42250696a6eSStefan Eßer } 42350696a6eSStefan Eßer 42478bc019dSStefan Eßer void 42578bc019dSStefan Eßer bcl_ctxt_freeNums(BclContext ctxt) 42678bc019dSStefan Eßer { 42710328f8bSStefan Eßer bc_vec_popAll(&ctxt->nums); 42810328f8bSStefan Eßer bc_vec_popAll(&ctxt->free_nums); 42950696a6eSStefan Eßer } 43050696a6eSStefan Eßer 43178bc019dSStefan Eßer size_t 43278bc019dSStefan Eßer bcl_ctxt_scale(BclContext ctxt) 43378bc019dSStefan Eßer { 43450696a6eSStefan Eßer return ctxt->scale; 43550696a6eSStefan Eßer } 43650696a6eSStefan Eßer 43778bc019dSStefan Eßer void 43878bc019dSStefan Eßer bcl_ctxt_setScale(BclContext ctxt, size_t scale) 43978bc019dSStefan Eßer { 44050696a6eSStefan Eßer ctxt->scale = scale; 44150696a6eSStefan Eßer } 44250696a6eSStefan Eßer 44378bc019dSStefan Eßer size_t 44478bc019dSStefan Eßer bcl_ctxt_ibase(BclContext ctxt) 44578bc019dSStefan Eßer { 44650696a6eSStefan Eßer return ctxt->ibase; 44750696a6eSStefan Eßer } 44850696a6eSStefan Eßer 44978bc019dSStefan Eßer void 45078bc019dSStefan Eßer bcl_ctxt_setIbase(BclContext ctxt, size_t ibase) 45178bc019dSStefan Eßer { 45250696a6eSStefan Eßer if (ibase < BC_NUM_MIN_BASE) ibase = BC_NUM_MIN_BASE; 45350696a6eSStefan Eßer else if (ibase > BC_NUM_MAX_IBASE) ibase = BC_NUM_MAX_IBASE; 45450696a6eSStefan Eßer ctxt->ibase = ibase; 45550696a6eSStefan Eßer } 45650696a6eSStefan Eßer 45778bc019dSStefan Eßer size_t 45878bc019dSStefan Eßer bcl_ctxt_obase(BclContext ctxt) 45978bc019dSStefan Eßer { 46050696a6eSStefan Eßer return ctxt->obase; 46150696a6eSStefan Eßer } 46250696a6eSStefan Eßer 46378bc019dSStefan Eßer void 46478bc019dSStefan Eßer bcl_ctxt_setObase(BclContext ctxt, size_t obase) 46578bc019dSStefan Eßer { 46650696a6eSStefan Eßer ctxt->obase = obase; 46750696a6eSStefan Eßer } 46850696a6eSStefan Eßer 46978bc019dSStefan Eßer BclError 47078bc019dSStefan Eßer bcl_err(BclNumber n) 47178bc019dSStefan Eßer { 47250696a6eSStefan Eßer BclContext ctxt; 473d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 47450696a6eSStefan Eßer 475d101cdd6SStefan Eßer BC_CHECK_CTXT_ERR(vm, ctxt); 47650696a6eSStefan Eßer 477175a4d10SStefan Eßer // We need to clear the top byte in memcheck mode. We can do this because 478175a4d10SStefan Eßer // the parameter is a copy. 479175a4d10SStefan Eßer BCL_CLEAR_GEN(n); 480175a4d10SStefan Eßer 48144d4804dSStefan Eßer // Errors are encoded as (0 - error_code). If the index is in that range, it 48244d4804dSStefan Eßer // is an encoded error. 48378bc019dSStefan Eßer if (n.i >= ctxt->nums.len) 48478bc019dSStefan Eßer { 48550696a6eSStefan Eßer if (n.i > 0 - (size_t) BCL_ERROR_NELEMS) return (BclError) (0 - n.i); 48650696a6eSStefan Eßer else return BCL_ERROR_INVALID_NUM; 48750696a6eSStefan Eßer } 48850696a6eSStefan Eßer else return BCL_ERROR_NONE; 48950696a6eSStefan Eßer } 49050696a6eSStefan Eßer 49144d4804dSStefan Eßer /** 49244d4804dSStefan Eßer * Inserts a BcNum into a context's list of numbers. 49344d4804dSStefan Eßer * @param ctxt The context to insert into. 49444d4804dSStefan Eßer * @param n The BcNum to insert. 49544d4804dSStefan Eßer * @return The resulting BclNumber from the insert. 49644d4804dSStefan Eßer */ 49778bc019dSStefan Eßer static BclNumber 498175a4d10SStefan Eßer bcl_num_insert(BclContext ctxt, BclNum* restrict n) 49978bc019dSStefan Eßer { 50050696a6eSStefan Eßer BclNumber idx; 50150696a6eSStefan Eßer 50244d4804dSStefan Eßer // If there is a free spot... 50378bc019dSStefan Eßer if (ctxt->free_nums.len) 50478bc019dSStefan Eßer { 505175a4d10SStefan Eßer BclNum* ptr; 50650696a6eSStefan Eßer 50744d4804dSStefan Eßer // Get the index of the free spot and remove it. 50850696a6eSStefan Eßer idx = *((BclNumber*) bc_vec_top(&ctxt->free_nums)); 50950696a6eSStefan Eßer bc_vec_pop(&ctxt->free_nums); 51050696a6eSStefan Eßer 51144d4804dSStefan Eßer // Copy the number into the spot. 51250696a6eSStefan Eßer ptr = bc_vec_item(&ctxt->nums, idx.i); 513175a4d10SStefan Eßer 514175a4d10SStefan Eßer memcpy(BCL_NUM_NUM(ptr), n, sizeof(BcNum)); 515175a4d10SStefan Eßer 516175a4d10SStefan Eßer #if BC_ENABLE_MEMCHECK 517175a4d10SStefan Eßer 518175a4d10SStefan Eßer ptr->gen_idx += 1; 519175a4d10SStefan Eßer 520175a4d10SStefan Eßer if (ptr->gen_idx == UCHAR_MAX) 521175a4d10SStefan Eßer { 522175a4d10SStefan Eßer ptr->gen_idx = 0; 523175a4d10SStefan Eßer } 524175a4d10SStefan Eßer 525175a4d10SStefan Eßer idx.i |= (ptr->gen_idx << ((sizeof(size_t) - 1) * CHAR_BIT)); 526175a4d10SStefan Eßer 527175a4d10SStefan Eßer #endif // BC_ENABLE_MEMCHECK 52850696a6eSStefan Eßer } 52978bc019dSStefan Eßer else 53078bc019dSStefan Eßer { 531175a4d10SStefan Eßer #if BC_ENABLE_MEMCHECK 532175a4d10SStefan Eßer n->gen_idx = 0; 533175a4d10SStefan Eßer #endif // BC_ENABLE_MEMCHECK 534175a4d10SStefan Eßer 535175a4d10SStefan Eßer // Just push the number onto the vector because the generation index is 536175a4d10SStefan Eßer // 0. 53750696a6eSStefan Eßer idx.i = ctxt->nums.len; 53850696a6eSStefan Eßer bc_vec_push(&ctxt->nums, n); 53950696a6eSStefan Eßer } 54050696a6eSStefan Eßer 54150696a6eSStefan Eßer return idx; 54250696a6eSStefan Eßer } 54350696a6eSStefan Eßer 54478bc019dSStefan Eßer BclNumber 54578bc019dSStefan Eßer bcl_num_create(void) 54678bc019dSStefan Eßer { 54750696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 548175a4d10SStefan Eßer BclNum n; 54950696a6eSStefan Eßer BclNumber idx; 55050696a6eSStefan Eßer BclContext ctxt; 551d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 55250696a6eSStefan Eßer 553d101cdd6SStefan Eßer BC_CHECK_CTXT(vm, ctxt); 55450696a6eSStefan Eßer 555d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 55650696a6eSStefan Eßer 557175a4d10SStefan Eßer BCL_GROW_NUMS(ctxt); 55850696a6eSStefan Eßer 559175a4d10SStefan Eßer bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE); 56050696a6eSStefan Eßer 56150696a6eSStefan Eßer err: 562175a4d10SStefan Eßer 563d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 56450696a6eSStefan Eßer BC_MAYBE_SETUP(ctxt, e, n, idx); 56550696a6eSStefan Eßer 56650696a6eSStefan Eßer return idx; 56750696a6eSStefan Eßer } 56850696a6eSStefan Eßer 56944d4804dSStefan Eßer /** 57044d4804dSStefan Eßer * Destructs a number and marks its spot as free. 57144d4804dSStefan Eßer * @param ctxt The context. 57244d4804dSStefan Eßer * @param n The index of the number. 57344d4804dSStefan Eßer * @param num The number to destroy. 57444d4804dSStefan Eßer */ 57578bc019dSStefan Eßer static void 576175a4d10SStefan Eßer bcl_num_dtor(BclContext ctxt, BclNumber n, BclNum* restrict num) 57778bc019dSStefan Eßer { 578175a4d10SStefan Eßer assert(num != NULL && BCL_NUM_ARRAY(num) != NULL); 579175a4d10SStefan Eßer 580175a4d10SStefan Eßer BCL_CLEAR_GEN(n); 58150696a6eSStefan Eßer 58250696a6eSStefan Eßer bcl_num_destruct(num); 58350696a6eSStefan Eßer bc_vec_push(&ctxt->free_nums, &n); 584175a4d10SStefan Eßer 585175a4d10SStefan Eßer #if BC_ENABLE_MEMCHECK 586175a4d10SStefan Eßer num->n.num = NULL; 587175a4d10SStefan Eßer #endif // BC_ENABLE_MEMCHECK 58850696a6eSStefan Eßer } 58950696a6eSStefan Eßer 59078bc019dSStefan Eßer void 59178bc019dSStefan Eßer bcl_num_free(BclNumber n) 59278bc019dSStefan Eßer { 593175a4d10SStefan Eßer BclNum* num; 59450696a6eSStefan Eßer BclContext ctxt; 595d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 59650696a6eSStefan Eßer 597d101cdd6SStefan Eßer BC_CHECK_CTXT_ASSERT(vm, ctxt); 59850696a6eSStefan Eßer 599175a4d10SStefan Eßer BCL_CHECK_NUM_VALID(ctxt, n); 60050696a6eSStefan Eßer 601175a4d10SStefan Eßer assert(BCL_NO_GEN(n) < ctxt->nums.len); 602175a4d10SStefan Eßer 603175a4d10SStefan Eßer num = BCL_NUM(ctxt, n); 60450696a6eSStefan Eßer 60550696a6eSStefan Eßer bcl_num_dtor(ctxt, n, num); 60650696a6eSStefan Eßer } 60750696a6eSStefan Eßer 60878bc019dSStefan Eßer BclError 60978bc019dSStefan Eßer bcl_copy(BclNumber d, BclNumber s) 61078bc019dSStefan Eßer { 61150696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 612175a4d10SStefan Eßer BclNum* dest; 613175a4d10SStefan Eßer BclNum* src; 61450696a6eSStefan Eßer BclContext ctxt; 615d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 61650696a6eSStefan Eßer 617d101cdd6SStefan Eßer BC_CHECK_CTXT_ERR(vm, ctxt); 61850696a6eSStefan Eßer 619175a4d10SStefan Eßer BCL_CHECK_NUM_VALID(ctxt, d); 620175a4d10SStefan Eßer BCL_CHECK_NUM_VALID(ctxt, s); 621175a4d10SStefan Eßer 622d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 62350696a6eSStefan Eßer 624175a4d10SStefan Eßer assert(BCL_NO_GEN(d) < ctxt->nums.len); 625175a4d10SStefan Eßer assert(BCL_NO_GEN(s) < ctxt->nums.len); 62650696a6eSStefan Eßer 627175a4d10SStefan Eßer dest = BCL_NUM(ctxt, d); 628175a4d10SStefan Eßer src = BCL_NUM(ctxt, s); 62950696a6eSStefan Eßer 63050696a6eSStefan Eßer assert(dest != NULL && src != NULL); 631175a4d10SStefan Eßer assert(BCL_NUM_ARRAY(dest) != NULL && BCL_NUM_ARRAY(src) != NULL); 63250696a6eSStefan Eßer 633175a4d10SStefan Eßer bc_num_copy(BCL_NUM_NUM(dest), BCL_NUM_NUM(src)); 63450696a6eSStefan Eßer 63550696a6eSStefan Eßer err: 636175a4d10SStefan Eßer 637d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 63850696a6eSStefan Eßer 63950696a6eSStefan Eßer return e; 64050696a6eSStefan Eßer } 64150696a6eSStefan Eßer 64278bc019dSStefan Eßer BclNumber 64378bc019dSStefan Eßer bcl_dup(BclNumber s) 64478bc019dSStefan Eßer { 64550696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 646175a4d10SStefan Eßer BclNum *src, dest; 64750696a6eSStefan Eßer BclNumber idx; 64850696a6eSStefan Eßer BclContext ctxt; 649d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 65050696a6eSStefan Eßer 651d101cdd6SStefan Eßer BC_CHECK_CTXT(vm, ctxt); 65250696a6eSStefan Eßer 653175a4d10SStefan Eßer BCL_CHECK_NUM_VALID(ctxt, s); 654175a4d10SStefan Eßer 655d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 65650696a6eSStefan Eßer 657175a4d10SStefan Eßer BCL_GROW_NUMS(ctxt); 65850696a6eSStefan Eßer 659175a4d10SStefan Eßer assert(BCL_NO_GEN(s) < ctxt->nums.len); 66050696a6eSStefan Eßer 661175a4d10SStefan Eßer src = BCL_NUM(ctxt, s); 66250696a6eSStefan Eßer 663175a4d10SStefan Eßer assert(src != NULL && BCL_NUM_NUM(src) != NULL); 66450696a6eSStefan Eßer 66544d4804dSStefan Eßer // Copy the number. 666175a4d10SStefan Eßer bc_num_clear(BCL_NUM_NUM(&dest)); 667175a4d10SStefan Eßer bc_num_createCopy(BCL_NUM_NUM(&dest), BCL_NUM_NUM(src)); 66850696a6eSStefan Eßer 66950696a6eSStefan Eßer err: 670175a4d10SStefan Eßer 671d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 67250696a6eSStefan Eßer BC_MAYBE_SETUP(ctxt, e, dest, idx); 67350696a6eSStefan Eßer 67450696a6eSStefan Eßer return idx; 67550696a6eSStefan Eßer } 67650696a6eSStefan Eßer 67778bc019dSStefan Eßer void 67878bc019dSStefan Eßer bcl_num_destruct(void* num) 67978bc019dSStefan Eßer { 680175a4d10SStefan Eßer BclNum* n = (BclNum*) num; 68150696a6eSStefan Eßer 68250696a6eSStefan Eßer assert(n != NULL); 68350696a6eSStefan Eßer 684175a4d10SStefan Eßer if (BCL_NUM_ARRAY(n) == NULL) return; 68550696a6eSStefan Eßer 686175a4d10SStefan Eßer bc_num_free(BCL_NUM_NUM(n)); 687175a4d10SStefan Eßer bc_num_clear(BCL_NUM_NUM(n)); 68850696a6eSStefan Eßer } 68950696a6eSStefan Eßer 69078bc019dSStefan Eßer bool 69178bc019dSStefan Eßer bcl_num_neg(BclNumber n) 69278bc019dSStefan Eßer { 693175a4d10SStefan Eßer BclNum* num; 69450696a6eSStefan Eßer BclContext ctxt; 695d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 69650696a6eSStefan Eßer 697d101cdd6SStefan Eßer BC_CHECK_CTXT_ASSERT(vm, ctxt); 69850696a6eSStefan Eßer 699175a4d10SStefan Eßer BCL_CHECK_NUM_VALID(ctxt, n); 70050696a6eSStefan Eßer 701175a4d10SStefan Eßer assert(BCL_NO_GEN(n) < ctxt->nums.len); 70250696a6eSStefan Eßer 703175a4d10SStefan Eßer num = BCL_NUM(ctxt, n); 70450696a6eSStefan Eßer 705175a4d10SStefan Eßer assert(num != NULL && BCL_NUM_ARRAY(num) != NULL); 706175a4d10SStefan Eßer 707175a4d10SStefan Eßer return BC_NUM_NEG(BCL_NUM_NUM(num)) != 0; 70850696a6eSStefan Eßer } 70950696a6eSStefan Eßer 71078bc019dSStefan Eßer void 71178bc019dSStefan Eßer bcl_num_setNeg(BclNumber n, bool neg) 71278bc019dSStefan Eßer { 713175a4d10SStefan Eßer BclNum* num; 71450696a6eSStefan Eßer BclContext ctxt; 715d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 71650696a6eSStefan Eßer 717d101cdd6SStefan Eßer BC_CHECK_CTXT_ASSERT(vm, ctxt); 71850696a6eSStefan Eßer 719175a4d10SStefan Eßer BCL_CHECK_NUM_VALID(ctxt, n); 72050696a6eSStefan Eßer 721175a4d10SStefan Eßer assert(BCL_NO_GEN(n) < ctxt->nums.len); 72250696a6eSStefan Eßer 723175a4d10SStefan Eßer num = BCL_NUM(ctxt, n); 72450696a6eSStefan Eßer 725175a4d10SStefan Eßer assert(num != NULL && BCL_NUM_ARRAY(num) != NULL); 726175a4d10SStefan Eßer 727175a4d10SStefan Eßer BCL_NUM_NUM(num)->rdx = BC_NUM_NEG_VAL(BCL_NUM_NUM(num), neg); 72850696a6eSStefan Eßer } 72950696a6eSStefan Eßer 73078bc019dSStefan Eßer size_t 73178bc019dSStefan Eßer bcl_num_scale(BclNumber n) 73278bc019dSStefan Eßer { 733175a4d10SStefan Eßer BclNum* num; 73450696a6eSStefan Eßer BclContext ctxt; 735d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 73650696a6eSStefan Eßer 737d101cdd6SStefan Eßer BC_CHECK_CTXT_ASSERT(vm, ctxt); 73850696a6eSStefan Eßer 739175a4d10SStefan Eßer BCL_CHECK_NUM_VALID(ctxt, n); 74050696a6eSStefan Eßer 741175a4d10SStefan Eßer assert(BCL_NO_GEN(n) < ctxt->nums.len); 74250696a6eSStefan Eßer 743175a4d10SStefan Eßer num = BCL_NUM(ctxt, n); 74450696a6eSStefan Eßer 745175a4d10SStefan Eßer assert(num != NULL && BCL_NUM_ARRAY(num) != NULL); 746175a4d10SStefan Eßer 747175a4d10SStefan Eßer return bc_num_scale(BCL_NUM_NUM(num)); 74850696a6eSStefan Eßer } 74950696a6eSStefan Eßer 75078bc019dSStefan Eßer BclError 75178bc019dSStefan Eßer bcl_num_setScale(BclNumber n, size_t scale) 75278bc019dSStefan Eßer { 75350696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 754175a4d10SStefan Eßer BclNum* nptr; 75550696a6eSStefan Eßer BclContext ctxt; 756d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 75750696a6eSStefan Eßer 758d101cdd6SStefan Eßer BC_CHECK_CTXT_ERR(vm, ctxt); 75950696a6eSStefan Eßer 76050696a6eSStefan Eßer BC_CHECK_NUM_ERR(ctxt, n); 76150696a6eSStefan Eßer 762175a4d10SStefan Eßer BCL_CHECK_NUM_VALID(ctxt, n); 763175a4d10SStefan Eßer 764d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 76550696a6eSStefan Eßer 766175a4d10SStefan Eßer assert(BCL_NO_GEN(n) < ctxt->nums.len); 76750696a6eSStefan Eßer 768175a4d10SStefan Eßer nptr = BCL_NUM(ctxt, n); 76950696a6eSStefan Eßer 770175a4d10SStefan Eßer assert(nptr != NULL && BCL_NUM_ARRAY(nptr) != NULL); 77150696a6eSStefan Eßer 772175a4d10SStefan Eßer if (scale > BCL_NUM_NUM(nptr)->scale) 773175a4d10SStefan Eßer { 774175a4d10SStefan Eßer bc_num_extend(BCL_NUM_NUM(nptr), scale - BCL_NUM_NUM(nptr)->scale); 775175a4d10SStefan Eßer } 776175a4d10SStefan Eßer else if (scale < BCL_NUM_NUM(nptr)->scale) 777175a4d10SStefan Eßer { 778175a4d10SStefan Eßer bc_num_truncate(BCL_NUM_NUM(nptr), BCL_NUM_NUM(nptr)->scale - scale); 779175a4d10SStefan Eßer } 78050696a6eSStefan Eßer 78150696a6eSStefan Eßer err: 782175a4d10SStefan Eßer 783d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 78450696a6eSStefan Eßer 78550696a6eSStefan Eßer return e; 78650696a6eSStefan Eßer } 78750696a6eSStefan Eßer 78878bc019dSStefan Eßer size_t 78978bc019dSStefan Eßer bcl_num_len(BclNumber n) 79078bc019dSStefan Eßer { 791175a4d10SStefan Eßer BclNum* num; 79250696a6eSStefan Eßer BclContext ctxt; 793d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 79450696a6eSStefan Eßer 795d101cdd6SStefan Eßer BC_CHECK_CTXT_ASSERT(vm, ctxt); 79650696a6eSStefan Eßer 797175a4d10SStefan Eßer BCL_CHECK_NUM_VALID(ctxt, n); 79850696a6eSStefan Eßer 799175a4d10SStefan Eßer assert(BCL_NO_GEN(n) < ctxt->nums.len); 80050696a6eSStefan Eßer 801175a4d10SStefan Eßer num = BCL_NUM(ctxt, n); 80250696a6eSStefan Eßer 803175a4d10SStefan Eßer assert(num != NULL && BCL_NUM_ARRAY(num) != NULL); 804175a4d10SStefan Eßer 805175a4d10SStefan Eßer return bc_num_len(BCL_NUM_NUM(num)); 80650696a6eSStefan Eßer } 80750696a6eSStefan Eßer 808175a4d10SStefan Eßer static BclError 809175a4d10SStefan Eßer bcl_bigdig_helper(BclNumber n, BclBigDig* result, bool destruct) 81078bc019dSStefan Eßer { 81150696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 812175a4d10SStefan Eßer BclNum* num; 81350696a6eSStefan Eßer BclContext ctxt; 814d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 81550696a6eSStefan Eßer 816d101cdd6SStefan Eßer BC_CHECK_CTXT_ERR(vm, ctxt); 81750696a6eSStefan Eßer 818175a4d10SStefan Eßer BCL_CHECK_NUM_VALID(ctxt, n); 819175a4d10SStefan Eßer 820d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 82150696a6eSStefan Eßer 822175a4d10SStefan Eßer assert(BCL_NO_GEN(n) < ctxt->nums.len); 82350696a6eSStefan Eßer assert(result != NULL); 82450696a6eSStefan Eßer 825175a4d10SStefan Eßer num = BCL_NUM(ctxt, n); 82650696a6eSStefan Eßer 827175a4d10SStefan Eßer assert(num != NULL && BCL_NUM_ARRAY(num) != NULL); 82850696a6eSStefan Eßer 829175a4d10SStefan Eßer *result = bc_num_bigdig(BCL_NUM_NUM(num)); 83050696a6eSStefan Eßer 83150696a6eSStefan Eßer err: 832175a4d10SStefan Eßer 833175a4d10SStefan Eßer if (destruct) 834175a4d10SStefan Eßer { 83550696a6eSStefan Eßer bcl_num_dtor(ctxt, n, num); 836175a4d10SStefan Eßer } 837175a4d10SStefan Eßer 838d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 83950696a6eSStefan Eßer 84050696a6eSStefan Eßer return e; 84150696a6eSStefan Eßer } 84250696a6eSStefan Eßer 843175a4d10SStefan Eßer BclError 844175a4d10SStefan Eßer bcl_bigdig(BclNumber n, BclBigDig* result) 845175a4d10SStefan Eßer { 846175a4d10SStefan Eßer return bcl_bigdig_helper(n, result, true); 847175a4d10SStefan Eßer } 848175a4d10SStefan Eßer 849175a4d10SStefan Eßer BclError 850175a4d10SStefan Eßer bcl_bigdig_keep(BclNumber n, BclBigDig* result) 851175a4d10SStefan Eßer { 852175a4d10SStefan Eßer return bcl_bigdig_helper(n, result, false); 853175a4d10SStefan Eßer } 854175a4d10SStefan Eßer 85578bc019dSStefan Eßer BclNumber 85678bc019dSStefan Eßer bcl_bigdig2num(BclBigDig val) 85778bc019dSStefan Eßer { 85850696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 859175a4d10SStefan Eßer BclNum n; 86050696a6eSStefan Eßer BclNumber idx; 86150696a6eSStefan Eßer BclContext ctxt; 862d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 86350696a6eSStefan Eßer 864d101cdd6SStefan Eßer BC_CHECK_CTXT(vm, ctxt); 86550696a6eSStefan Eßer 866d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 86750696a6eSStefan Eßer 868175a4d10SStefan Eßer BCL_GROW_NUMS(ctxt); 86950696a6eSStefan Eßer 870175a4d10SStefan Eßer bc_num_createFromBigdig(BCL_NUM_NUM_NP(n), val); 87150696a6eSStefan Eßer 87250696a6eSStefan Eßer err: 873175a4d10SStefan Eßer 874d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 87550696a6eSStefan Eßer BC_MAYBE_SETUP(ctxt, e, n, idx); 87650696a6eSStefan Eßer 87750696a6eSStefan Eßer return idx; 87850696a6eSStefan Eßer } 87950696a6eSStefan Eßer 88044d4804dSStefan Eßer /** 88144d4804dSStefan Eßer * Sets up and executes a binary operator operation. 88244d4804dSStefan Eßer * @param a The first operand. 88344d4804dSStefan Eßer * @param b The second operand. 88444d4804dSStefan Eßer * @param op The operation. 885175a4d10SStefan Eßer * @param req The function to get the size of the result for 886175a4d10SStefan Eßer * preallocation. 887175a4d10SStefan Eßer * @param destruct True if the parameters should be consumed, false otherwise. 88844d4804dSStefan Eßer * @return The result of the operation. 88944d4804dSStefan Eßer */ 89078bc019dSStefan Eßer static BclNumber 89178bc019dSStefan Eßer bcl_binary(BclNumber a, BclNumber b, const BcNumBinaryOp op, 892175a4d10SStefan Eßer const BcNumBinaryOpReq req, bool destruct) 89350696a6eSStefan Eßer { 89450696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 895175a4d10SStefan Eßer BclNum* aptr; 896175a4d10SStefan Eßer BclNum* bptr; 897175a4d10SStefan Eßer BclNum c; 89850696a6eSStefan Eßer BclNumber idx; 89950696a6eSStefan Eßer BclContext ctxt; 900d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 90150696a6eSStefan Eßer 902d101cdd6SStefan Eßer BC_CHECK_CTXT(vm, ctxt); 90350696a6eSStefan Eßer 90450696a6eSStefan Eßer BC_CHECK_NUM(ctxt, a); 90550696a6eSStefan Eßer BC_CHECK_NUM(ctxt, b); 90650696a6eSStefan Eßer 907d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 90850696a6eSStefan Eßer 909175a4d10SStefan Eßer BCL_GROW_NUMS(ctxt); 91050696a6eSStefan Eßer 911175a4d10SStefan Eßer assert(BCL_NO_GEN(a) < ctxt->nums.len && BCL_NO_GEN(b) < ctxt->nums.len); 91250696a6eSStefan Eßer 913175a4d10SStefan Eßer aptr = BCL_NUM(ctxt, a); 914175a4d10SStefan Eßer bptr = BCL_NUM(ctxt, b); 91550696a6eSStefan Eßer 91650696a6eSStefan Eßer assert(aptr != NULL && bptr != NULL); 917175a4d10SStefan Eßer assert(BCL_NUM_ARRAY(aptr) != NULL && BCL_NUM_ARRAY(bptr) != NULL); 91850696a6eSStefan Eßer 91944d4804dSStefan Eßer // Clear and initialize the result. 920175a4d10SStefan Eßer bc_num_clear(BCL_NUM_NUM_NP(c)); 921175a4d10SStefan Eßer bc_num_init(BCL_NUM_NUM_NP(c), 922175a4d10SStefan Eßer req(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), ctxt->scale)); 92350696a6eSStefan Eßer 924175a4d10SStefan Eßer op(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM_NP(c), ctxt->scale); 92550696a6eSStefan Eßer 92650696a6eSStefan Eßer err: 92744d4804dSStefan Eßer 928175a4d10SStefan Eßer if (destruct) 929175a4d10SStefan Eßer { 93044d4804dSStefan Eßer // Eat the operands. 93150696a6eSStefan Eßer bcl_num_dtor(ctxt, a, aptr); 93250696a6eSStefan Eßer if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); 933175a4d10SStefan Eßer } 93444d4804dSStefan Eßer 935d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 93650696a6eSStefan Eßer BC_MAYBE_SETUP(ctxt, e, c, idx); 93750696a6eSStefan Eßer 93850696a6eSStefan Eßer return idx; 93950696a6eSStefan Eßer } 94050696a6eSStefan Eßer 94178bc019dSStefan Eßer BclNumber 94278bc019dSStefan Eßer bcl_add(BclNumber a, BclNumber b) 94378bc019dSStefan Eßer { 944175a4d10SStefan Eßer return bcl_binary(a, b, bc_num_add, bc_num_addReq, true); 945175a4d10SStefan Eßer } 946175a4d10SStefan Eßer 947175a4d10SStefan Eßer BclNumber 948175a4d10SStefan Eßer bcl_add_keep(BclNumber a, BclNumber b) 949175a4d10SStefan Eßer { 950175a4d10SStefan Eßer return bcl_binary(a, b, bc_num_add, bc_num_addReq, false); 95150696a6eSStefan Eßer } 95250696a6eSStefan Eßer 95378bc019dSStefan Eßer BclNumber 95478bc019dSStefan Eßer bcl_sub(BclNumber a, BclNumber b) 95578bc019dSStefan Eßer { 956175a4d10SStefan Eßer return bcl_binary(a, b, bc_num_sub, bc_num_addReq, true); 957175a4d10SStefan Eßer } 958175a4d10SStefan Eßer 959175a4d10SStefan Eßer BclNumber 960175a4d10SStefan Eßer bcl_sub_keep(BclNumber a, BclNumber b) 961175a4d10SStefan Eßer { 962175a4d10SStefan Eßer return bcl_binary(a, b, bc_num_sub, bc_num_addReq, false); 96350696a6eSStefan Eßer } 96450696a6eSStefan Eßer 96578bc019dSStefan Eßer BclNumber 96678bc019dSStefan Eßer bcl_mul(BclNumber a, BclNumber b) 96778bc019dSStefan Eßer { 968175a4d10SStefan Eßer return bcl_binary(a, b, bc_num_mul, bc_num_mulReq, true); 969175a4d10SStefan Eßer } 970175a4d10SStefan Eßer 971175a4d10SStefan Eßer BclNumber 972175a4d10SStefan Eßer bcl_mul_keep(BclNumber a, BclNumber b) 973175a4d10SStefan Eßer { 974175a4d10SStefan Eßer return bcl_binary(a, b, bc_num_mul, bc_num_mulReq, false); 97550696a6eSStefan Eßer } 97650696a6eSStefan Eßer 97778bc019dSStefan Eßer BclNumber 97878bc019dSStefan Eßer bcl_div(BclNumber a, BclNumber b) 97978bc019dSStefan Eßer { 980175a4d10SStefan Eßer return bcl_binary(a, b, bc_num_div, bc_num_divReq, true); 981175a4d10SStefan Eßer } 982175a4d10SStefan Eßer 983175a4d10SStefan Eßer BclNumber 984175a4d10SStefan Eßer bcl_div_keep(BclNumber a, BclNumber b) 985175a4d10SStefan Eßer { 986175a4d10SStefan Eßer return bcl_binary(a, b, bc_num_div, bc_num_divReq, false); 98750696a6eSStefan Eßer } 98850696a6eSStefan Eßer 98978bc019dSStefan Eßer BclNumber 99078bc019dSStefan Eßer bcl_mod(BclNumber a, BclNumber b) 99178bc019dSStefan Eßer { 992175a4d10SStefan Eßer return bcl_binary(a, b, bc_num_mod, bc_num_divReq, true); 993175a4d10SStefan Eßer } 994175a4d10SStefan Eßer 995175a4d10SStefan Eßer BclNumber 996175a4d10SStefan Eßer bcl_mod_keep(BclNumber a, BclNumber b) 997175a4d10SStefan Eßer { 998175a4d10SStefan Eßer return bcl_binary(a, b, bc_num_mod, bc_num_divReq, false); 99950696a6eSStefan Eßer } 100050696a6eSStefan Eßer 100178bc019dSStefan Eßer BclNumber 100278bc019dSStefan Eßer bcl_pow(BclNumber a, BclNumber b) 100378bc019dSStefan Eßer { 1004175a4d10SStefan Eßer return bcl_binary(a, b, bc_num_pow, bc_num_powReq, true); 1005175a4d10SStefan Eßer } 1006175a4d10SStefan Eßer 1007175a4d10SStefan Eßer BclNumber 1008175a4d10SStefan Eßer bcl_pow_keep(BclNumber a, BclNumber b) 1009175a4d10SStefan Eßer { 1010175a4d10SStefan Eßer return bcl_binary(a, b, bc_num_pow, bc_num_powReq, false); 101150696a6eSStefan Eßer } 101250696a6eSStefan Eßer 101378bc019dSStefan Eßer BclNumber 101478bc019dSStefan Eßer bcl_lshift(BclNumber a, BclNumber b) 101578bc019dSStefan Eßer { 1016175a4d10SStefan Eßer return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq, true); 1017175a4d10SStefan Eßer } 1018175a4d10SStefan Eßer 1019175a4d10SStefan Eßer BclNumber 1020175a4d10SStefan Eßer bcl_lshift_keep(BclNumber a, BclNumber b) 1021175a4d10SStefan Eßer { 1022175a4d10SStefan Eßer return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq, false); 102350696a6eSStefan Eßer } 102450696a6eSStefan Eßer 102578bc019dSStefan Eßer BclNumber 102678bc019dSStefan Eßer bcl_rshift(BclNumber a, BclNumber b) 102778bc019dSStefan Eßer { 1028175a4d10SStefan Eßer return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq, true); 102950696a6eSStefan Eßer } 103050696a6eSStefan Eßer 103178bc019dSStefan Eßer BclNumber 1032175a4d10SStefan Eßer bcl_rshift_keep(BclNumber a, BclNumber b) 1033175a4d10SStefan Eßer { 1034175a4d10SStefan Eßer return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq, false); 1035175a4d10SStefan Eßer } 1036175a4d10SStefan Eßer 1037175a4d10SStefan Eßer static BclNumber 1038175a4d10SStefan Eßer bcl_sqrt_helper(BclNumber a, bool destruct) 103978bc019dSStefan Eßer { 104050696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 1041175a4d10SStefan Eßer BclNum* aptr; 1042175a4d10SStefan Eßer BclNum b; 104350696a6eSStefan Eßer BclNumber idx; 104450696a6eSStefan Eßer BclContext ctxt; 1045d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 104650696a6eSStefan Eßer 1047d101cdd6SStefan Eßer BC_CHECK_CTXT(vm, ctxt); 104850696a6eSStefan Eßer 104950696a6eSStefan Eßer BC_CHECK_NUM(ctxt, a); 105050696a6eSStefan Eßer 1051d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 105250696a6eSStefan Eßer 1053175a4d10SStefan Eßer BCL_GROW_NUMS(ctxt); 105450696a6eSStefan Eßer 1055175a4d10SStefan Eßer assert(BCL_NO_GEN(a) < ctxt->nums.len); 105650696a6eSStefan Eßer 1057175a4d10SStefan Eßer aptr = BCL_NUM(ctxt, a); 105850696a6eSStefan Eßer 1059175a4d10SStefan Eßer bc_num_sqrt(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), ctxt->scale); 106050696a6eSStefan Eßer 106150696a6eSStefan Eßer err: 1062175a4d10SStefan Eßer 1063175a4d10SStefan Eßer if (destruct) 1064175a4d10SStefan Eßer { 106550696a6eSStefan Eßer bcl_num_dtor(ctxt, a, aptr); 1066175a4d10SStefan Eßer } 1067175a4d10SStefan Eßer 1068d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 106950696a6eSStefan Eßer BC_MAYBE_SETUP(ctxt, e, b, idx); 107050696a6eSStefan Eßer 107150696a6eSStefan Eßer return idx; 107250696a6eSStefan Eßer } 107350696a6eSStefan Eßer 1074175a4d10SStefan Eßer BclNumber 1075175a4d10SStefan Eßer bcl_sqrt(BclNumber a) 1076175a4d10SStefan Eßer { 1077175a4d10SStefan Eßer return bcl_sqrt_helper(a, true); 1078175a4d10SStefan Eßer } 1079175a4d10SStefan Eßer 1080175a4d10SStefan Eßer BclNumber 1081175a4d10SStefan Eßer bcl_sqrt_keep(BclNumber a) 1082175a4d10SStefan Eßer { 1083175a4d10SStefan Eßer return bcl_sqrt_helper(a, false); 1084175a4d10SStefan Eßer } 1085175a4d10SStefan Eßer 1086175a4d10SStefan Eßer static BclError 1087175a4d10SStefan Eßer bcl_divmod_helper(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d, 1088175a4d10SStefan Eßer bool destruct) 108978bc019dSStefan Eßer { 109050696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 109150696a6eSStefan Eßer size_t req; 1092175a4d10SStefan Eßer BclNum* aptr; 1093175a4d10SStefan Eßer BclNum* bptr; 1094175a4d10SStefan Eßer BclNum cnum, dnum; 109550696a6eSStefan Eßer BclContext ctxt; 1096d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 109750696a6eSStefan Eßer 1098d101cdd6SStefan Eßer BC_CHECK_CTXT_ERR(vm, ctxt); 109950696a6eSStefan Eßer 110050696a6eSStefan Eßer BC_CHECK_NUM_ERR(ctxt, a); 110150696a6eSStefan Eßer BC_CHECK_NUM_ERR(ctxt, b); 110250696a6eSStefan Eßer 1103d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 110450696a6eSStefan Eßer 1105175a4d10SStefan Eßer BCL_GROW_NUMS(ctxt); 110650696a6eSStefan Eßer 110750696a6eSStefan Eßer assert(c != NULL && d != NULL); 110850696a6eSStefan Eßer 1109175a4d10SStefan Eßer aptr = BCL_NUM(ctxt, a); 1110175a4d10SStefan Eßer bptr = BCL_NUM(ctxt, b); 111150696a6eSStefan Eßer 111250696a6eSStefan Eßer assert(aptr != NULL && bptr != NULL); 1113175a4d10SStefan Eßer assert(BCL_NUM_ARRAY(aptr) != NULL && BCL_NUM_ARRAY(bptr) != NULL); 111450696a6eSStefan Eßer 1115175a4d10SStefan Eßer bc_num_clear(BCL_NUM_NUM_NP(cnum)); 1116175a4d10SStefan Eßer bc_num_clear(BCL_NUM_NUM_NP(dnum)); 111750696a6eSStefan Eßer 1118175a4d10SStefan Eßer req = bc_num_divReq(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), ctxt->scale); 111950696a6eSStefan Eßer 112044d4804dSStefan Eßer // Initialize the numbers. 1121175a4d10SStefan Eßer bc_num_init(BCL_NUM_NUM_NP(cnum), req); 1122d101cdd6SStefan Eßer BC_UNSETJMP(vm); 1123d101cdd6SStefan Eßer BC_SETJMP(vm, err); 1124175a4d10SStefan Eßer bc_num_init(BCL_NUM_NUM_NP(dnum), req); 112550696a6eSStefan Eßer 1126175a4d10SStefan Eßer bc_num_divmod(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM_NP(cnum), 1127175a4d10SStefan Eßer BCL_NUM_NUM_NP(dnum), ctxt->scale); 112850696a6eSStefan Eßer 112950696a6eSStefan Eßer err: 113050696a6eSStefan Eßer 1131175a4d10SStefan Eßer if (destruct) 1132175a4d10SStefan Eßer { 113344d4804dSStefan Eßer // Eat the operands. 113450696a6eSStefan Eßer bcl_num_dtor(ctxt, a, aptr); 113550696a6eSStefan Eßer if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); 1136175a4d10SStefan Eßer } 113750696a6eSStefan Eßer 113844d4804dSStefan Eßer // If there was an error... 1139d101cdd6SStefan Eßer if (BC_ERR(vm->err)) 114078bc019dSStefan Eßer { 114144d4804dSStefan Eßer // Free the results. 1142175a4d10SStefan Eßer if (BCL_NUM_ARRAY_NP(cnum) != NULL) bc_num_free(&cnum); 1143175a4d10SStefan Eßer if (BCL_NUM_ARRAY_NP(cnum) != NULL) bc_num_free(&dnum); 114444d4804dSStefan Eßer 114544d4804dSStefan Eßer // Make sure the return values are invalid. 114650696a6eSStefan Eßer c->i = 0 - (size_t) BCL_ERROR_INVALID_NUM; 114750696a6eSStefan Eßer d->i = c->i; 114844d4804dSStefan Eßer 1149d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 115050696a6eSStefan Eßer } 115178bc019dSStefan Eßer else 115278bc019dSStefan Eßer { 1153d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 115444d4804dSStefan Eßer 115544d4804dSStefan Eßer // Insert the results into the context. 115650696a6eSStefan Eßer *c = bcl_num_insert(ctxt, &cnum); 115750696a6eSStefan Eßer *d = bcl_num_insert(ctxt, &dnum); 115850696a6eSStefan Eßer } 115950696a6eSStefan Eßer 116050696a6eSStefan Eßer return e; 116150696a6eSStefan Eßer } 116250696a6eSStefan Eßer 1163175a4d10SStefan Eßer BclError 1164175a4d10SStefan Eßer bcl_divmod(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d) 1165175a4d10SStefan Eßer { 1166175a4d10SStefan Eßer return bcl_divmod_helper(a, b, c, d, true); 1167175a4d10SStefan Eßer } 1168175a4d10SStefan Eßer 1169175a4d10SStefan Eßer BclError 1170175a4d10SStefan Eßer bcl_divmod_keep(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d) 1171175a4d10SStefan Eßer { 1172175a4d10SStefan Eßer return bcl_divmod_helper(a, b, c, d, false); 1173175a4d10SStefan Eßer } 1174175a4d10SStefan Eßer 1175175a4d10SStefan Eßer static BclNumber 1176175a4d10SStefan Eßer bcl_modexp_helper(BclNumber a, BclNumber b, BclNumber c, bool destruct) 117778bc019dSStefan Eßer { 117850696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 117950696a6eSStefan Eßer size_t req; 1180175a4d10SStefan Eßer BclNum* aptr; 1181175a4d10SStefan Eßer BclNum* bptr; 1182175a4d10SStefan Eßer BclNum* cptr; 1183175a4d10SStefan Eßer BclNum d; 118450696a6eSStefan Eßer BclNumber idx; 118550696a6eSStefan Eßer BclContext ctxt; 1186d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 118750696a6eSStefan Eßer 1188d101cdd6SStefan Eßer BC_CHECK_CTXT(vm, ctxt); 118950696a6eSStefan Eßer 119050696a6eSStefan Eßer BC_CHECK_NUM(ctxt, a); 119150696a6eSStefan Eßer BC_CHECK_NUM(ctxt, b); 119250696a6eSStefan Eßer BC_CHECK_NUM(ctxt, c); 119350696a6eSStefan Eßer 1194d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 119550696a6eSStefan Eßer 1196175a4d10SStefan Eßer BCL_GROW_NUMS(ctxt); 119750696a6eSStefan Eßer 1198175a4d10SStefan Eßer assert(BCL_NO_GEN(a) < ctxt->nums.len && BCL_NO_GEN(b) < ctxt->nums.len); 1199175a4d10SStefan Eßer assert(BCL_NO_GEN(c) < ctxt->nums.len); 120050696a6eSStefan Eßer 1201175a4d10SStefan Eßer aptr = BCL_NUM(ctxt, a); 1202175a4d10SStefan Eßer bptr = BCL_NUM(ctxt, b); 1203175a4d10SStefan Eßer cptr = BCL_NUM(ctxt, c); 120450696a6eSStefan Eßer 120550696a6eSStefan Eßer assert(aptr != NULL && bptr != NULL && cptr != NULL); 1206175a4d10SStefan Eßer assert(BCL_NUM_NUM(aptr) != NULL && BCL_NUM_NUM(bptr) != NULL && 1207175a4d10SStefan Eßer BCL_NUM_NUM(cptr) != NULL); 120850696a6eSStefan Eßer 120944d4804dSStefan Eßer // Prepare the result. 1210175a4d10SStefan Eßer bc_num_clear(BCL_NUM_NUM_NP(d)); 121150696a6eSStefan Eßer 1212175a4d10SStefan Eßer req = bc_num_divReq(BCL_NUM_NUM(aptr), BCL_NUM_NUM(cptr), 0); 121350696a6eSStefan Eßer 121444d4804dSStefan Eßer // Initialize the result. 1215175a4d10SStefan Eßer bc_num_init(BCL_NUM_NUM_NP(d), req); 121650696a6eSStefan Eßer 1217175a4d10SStefan Eßer bc_num_modexp(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM(cptr), 1218175a4d10SStefan Eßer BCL_NUM_NUM_NP(d)); 121950696a6eSStefan Eßer 122050696a6eSStefan Eßer err: 122150696a6eSStefan Eßer 1222175a4d10SStefan Eßer if (destruct) 1223175a4d10SStefan Eßer { 122444d4804dSStefan Eßer // Eat the operands. 122550696a6eSStefan Eßer bcl_num_dtor(ctxt, a, aptr); 122650696a6eSStefan Eßer if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); 122750696a6eSStefan Eßer if (c.i != a.i && c.i != b.i) bcl_num_dtor(ctxt, c, cptr); 1228175a4d10SStefan Eßer } 122950696a6eSStefan Eßer 1230d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 123150696a6eSStefan Eßer BC_MAYBE_SETUP(ctxt, e, d, idx); 123250696a6eSStefan Eßer 123350696a6eSStefan Eßer return idx; 123450696a6eSStefan Eßer } 123550696a6eSStefan Eßer 1236175a4d10SStefan Eßer BclNumber 1237175a4d10SStefan Eßer bcl_modexp(BclNumber a, BclNumber b, BclNumber c) 1238175a4d10SStefan Eßer { 1239175a4d10SStefan Eßer return bcl_modexp_helper(a, b, c, true); 1240175a4d10SStefan Eßer } 1241175a4d10SStefan Eßer 1242175a4d10SStefan Eßer BclNumber 1243175a4d10SStefan Eßer bcl_modexp_keep(BclNumber a, BclNumber b, BclNumber c) 1244175a4d10SStefan Eßer { 1245175a4d10SStefan Eßer return bcl_modexp_helper(a, b, c, false); 1246175a4d10SStefan Eßer } 1247175a4d10SStefan Eßer 124878bc019dSStefan Eßer ssize_t 124978bc019dSStefan Eßer bcl_cmp(BclNumber a, BclNumber b) 125078bc019dSStefan Eßer { 1251175a4d10SStefan Eßer BclNum* aptr; 1252175a4d10SStefan Eßer BclNum* bptr; 125350696a6eSStefan Eßer BclContext ctxt; 1254d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 125550696a6eSStefan Eßer 1256d101cdd6SStefan Eßer BC_CHECK_CTXT_ASSERT(vm, ctxt); 125750696a6eSStefan Eßer 1258175a4d10SStefan Eßer BCL_CHECK_NUM_VALID(ctxt, a); 1259175a4d10SStefan Eßer BCL_CHECK_NUM_VALID(ctxt, b); 126050696a6eSStefan Eßer 1261175a4d10SStefan Eßer assert(BCL_NO_GEN(a) < ctxt->nums.len && BCL_NO_GEN(b) < ctxt->nums.len); 1262175a4d10SStefan Eßer 1263175a4d10SStefan Eßer aptr = BCL_NUM(ctxt, a); 1264175a4d10SStefan Eßer bptr = BCL_NUM(ctxt, b); 126550696a6eSStefan Eßer 126650696a6eSStefan Eßer assert(aptr != NULL && bptr != NULL); 1267175a4d10SStefan Eßer assert(BCL_NUM_NUM(aptr) != NULL && BCL_NUM_NUM(bptr)); 126850696a6eSStefan Eßer 1269175a4d10SStefan Eßer return bc_num_cmp(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr)); 127050696a6eSStefan Eßer } 127150696a6eSStefan Eßer 127278bc019dSStefan Eßer void 127378bc019dSStefan Eßer bcl_zero(BclNumber n) 127478bc019dSStefan Eßer { 1275175a4d10SStefan Eßer BclNum* nptr; 127650696a6eSStefan Eßer BclContext ctxt; 1277d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 127850696a6eSStefan Eßer 1279d101cdd6SStefan Eßer BC_CHECK_CTXT_ASSERT(vm, ctxt); 128050696a6eSStefan Eßer 1281175a4d10SStefan Eßer BCL_CHECK_NUM_VALID(ctxt, n); 128250696a6eSStefan Eßer 1283175a4d10SStefan Eßer assert(BCL_NO_GEN(n) < ctxt->nums.len); 128450696a6eSStefan Eßer 1285175a4d10SStefan Eßer nptr = BCL_NUM(ctxt, n); 128650696a6eSStefan Eßer 1287175a4d10SStefan Eßer assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL); 1288175a4d10SStefan Eßer 1289175a4d10SStefan Eßer bc_num_zero(BCL_NUM_NUM(nptr)); 129050696a6eSStefan Eßer } 129150696a6eSStefan Eßer 129278bc019dSStefan Eßer void 129378bc019dSStefan Eßer bcl_one(BclNumber n) 129478bc019dSStefan Eßer { 1295175a4d10SStefan Eßer BclNum* nptr; 129650696a6eSStefan Eßer BclContext ctxt; 1297d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 129850696a6eSStefan Eßer 1299d101cdd6SStefan Eßer BC_CHECK_CTXT_ASSERT(vm, ctxt); 130050696a6eSStefan Eßer 1301175a4d10SStefan Eßer BCL_CHECK_NUM_VALID(ctxt, n); 130250696a6eSStefan Eßer 1303175a4d10SStefan Eßer assert(BCL_NO_GEN(n) < ctxt->nums.len); 130450696a6eSStefan Eßer 1305175a4d10SStefan Eßer nptr = BCL_NUM(ctxt, n); 130650696a6eSStefan Eßer 1307175a4d10SStefan Eßer assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL); 1308175a4d10SStefan Eßer 1309175a4d10SStefan Eßer bc_num_one(BCL_NUM_NUM(nptr)); 131050696a6eSStefan Eßer } 131150696a6eSStefan Eßer 131278bc019dSStefan Eßer BclNumber 131378bc019dSStefan Eßer bcl_parse(const char* restrict val) 131478bc019dSStefan Eßer { 131550696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 1316175a4d10SStefan Eßer BclNum n; 131750696a6eSStefan Eßer BclNumber idx; 131850696a6eSStefan Eßer BclContext ctxt; 1319d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 132050696a6eSStefan Eßer bool neg; 132150696a6eSStefan Eßer 1322d101cdd6SStefan Eßer BC_CHECK_CTXT(vm, ctxt); 132350696a6eSStefan Eßer 1324d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 132550696a6eSStefan Eßer 1326175a4d10SStefan Eßer BCL_GROW_NUMS(ctxt); 132750696a6eSStefan Eßer 132850696a6eSStefan Eßer assert(val != NULL); 132950696a6eSStefan Eßer 133044d4804dSStefan Eßer // We have to take care of negative here because bc's number parsing does 133144d4804dSStefan Eßer // not. 133250696a6eSStefan Eßer neg = (val[0] == '-'); 133350696a6eSStefan Eßer 133450696a6eSStefan Eßer if (neg) val += 1; 133550696a6eSStefan Eßer 133678bc019dSStefan Eßer if (!bc_num_strValid(val)) 133778bc019dSStefan Eßer { 1338d101cdd6SStefan Eßer vm->err = BCL_ERROR_PARSE_INVALID_STR; 133950696a6eSStefan Eßer goto err; 134050696a6eSStefan Eßer } 134150696a6eSStefan Eßer 134244d4804dSStefan Eßer // Clear and initialize the number. 1343175a4d10SStefan Eßer bc_num_clear(BCL_NUM_NUM_NP(n)); 1344175a4d10SStefan Eßer bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE); 134550696a6eSStefan Eßer 1346175a4d10SStefan Eßer bc_num_parse(BCL_NUM_NUM_NP(n), val, (BcBigDig) ctxt->ibase); 134750696a6eSStefan Eßer 134844d4804dSStefan Eßer // Set the negative. 1349175a4d10SStefan Eßer #if BC_ENABLE_MEMCHECK 1350175a4d10SStefan Eßer n.n.rdx = BC_NUM_NEG_VAL(BCL_NUM_NUM_NP(n), neg); 1351175a4d10SStefan Eßer #else // BC_ENABLE_MEMCHECK 135250696a6eSStefan Eßer n.rdx = BC_NUM_NEG_VAL_NP(n, neg); 1353175a4d10SStefan Eßer #endif // BC_ENABLE_MEMCHECK 135450696a6eSStefan Eßer 135550696a6eSStefan Eßer err: 1356175a4d10SStefan Eßer 1357d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 135850696a6eSStefan Eßer BC_MAYBE_SETUP(ctxt, e, n, idx); 135950696a6eSStefan Eßer 136050696a6eSStefan Eßer return idx; 136150696a6eSStefan Eßer } 136250696a6eSStefan Eßer 1363175a4d10SStefan Eßer static char* 1364175a4d10SStefan Eßer bcl_string_helper(BclNumber n, bool destruct) 136578bc019dSStefan Eßer { 1366175a4d10SStefan Eßer BclNum* nptr; 136750696a6eSStefan Eßer char* str = NULL; 136850696a6eSStefan Eßer BclContext ctxt; 1369d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 137050696a6eSStefan Eßer 1371d101cdd6SStefan Eßer BC_CHECK_CTXT_ASSERT(vm, ctxt); 137250696a6eSStefan Eßer 1373175a4d10SStefan Eßer BCL_CHECK_NUM_VALID(ctxt, n); 1374175a4d10SStefan Eßer 1375175a4d10SStefan Eßer if (BC_ERR(BCL_NO_GEN(n) >= ctxt->nums.len)) return str; 137650696a6eSStefan Eßer 1377d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 137850696a6eSStefan Eßer 1379175a4d10SStefan Eßer assert(BCL_NO_GEN(n) < ctxt->nums.len); 138050696a6eSStefan Eßer 1381175a4d10SStefan Eßer nptr = BCL_NUM(ctxt, n); 138250696a6eSStefan Eßer 1383175a4d10SStefan Eßer assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL); 138450696a6eSStefan Eßer 138544d4804dSStefan Eßer // Clear the buffer. 1386d101cdd6SStefan Eßer bc_vec_popAll(&vm->out); 138750696a6eSStefan Eßer 138844d4804dSStefan Eßer // Print to the buffer. 1389175a4d10SStefan Eßer bc_num_print(BCL_NUM_NUM(nptr), (BcBigDig) ctxt->obase, false); 1390d101cdd6SStefan Eßer bc_vec_pushByte(&vm->out, '\0'); 139144d4804dSStefan Eßer 139244d4804dSStefan Eßer // Just dup the string; the caller is responsible for it. 1393d101cdd6SStefan Eßer str = bc_vm_strdup(vm->out.v); 139450696a6eSStefan Eßer 139550696a6eSStefan Eßer err: 139644d4804dSStefan Eßer 1397175a4d10SStefan Eßer if (destruct) 1398175a4d10SStefan Eßer { 139944d4804dSStefan Eßer // Eat the operand. 140050696a6eSStefan Eßer bcl_num_dtor(ctxt, n, nptr); 1401175a4d10SStefan Eßer } 140250696a6eSStefan Eßer 1403d101cdd6SStefan Eßer BC_FUNC_FOOTER_NO_ERR(vm); 140450696a6eSStefan Eßer 140550696a6eSStefan Eßer return str; 140650696a6eSStefan Eßer } 140750696a6eSStefan Eßer 1408175a4d10SStefan Eßer char* 1409175a4d10SStefan Eßer bcl_string(BclNumber n) 1410175a4d10SStefan Eßer { 1411175a4d10SStefan Eßer return bcl_string_helper(n, true); 1412175a4d10SStefan Eßer } 1413175a4d10SStefan Eßer 1414175a4d10SStefan Eßer char* 1415175a4d10SStefan Eßer bcl_string_keep(BclNumber n) 1416175a4d10SStefan Eßer { 1417175a4d10SStefan Eßer return bcl_string_helper(n, false); 1418175a4d10SStefan Eßer } 1419175a4d10SStefan Eßer 1420175a4d10SStefan Eßer #if BC_ENABLE_EXTRA_MATH 1421175a4d10SStefan Eßer 1422175a4d10SStefan Eßer static BclNumber 1423175a4d10SStefan Eßer bcl_irand_helper(BclNumber a, bool destruct) 142478bc019dSStefan Eßer { 142550696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 1426175a4d10SStefan Eßer BclNum* aptr; 1427175a4d10SStefan Eßer BclNum b; 142850696a6eSStefan Eßer BclNumber idx; 142950696a6eSStefan Eßer BclContext ctxt; 1430d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 143150696a6eSStefan Eßer 1432d101cdd6SStefan Eßer BC_CHECK_CTXT(vm, ctxt); 143350696a6eSStefan Eßer 143450696a6eSStefan Eßer BC_CHECK_NUM(ctxt, a); 143550696a6eSStefan Eßer 1436d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 143750696a6eSStefan Eßer 1438175a4d10SStefan Eßer BCL_GROW_NUMS(ctxt); 143950696a6eSStefan Eßer 1440175a4d10SStefan Eßer assert(BCL_NO_GEN(a) < ctxt->nums.len); 144150696a6eSStefan Eßer 1442175a4d10SStefan Eßer aptr = BCL_NUM(ctxt, a); 144350696a6eSStefan Eßer 1444175a4d10SStefan Eßer assert(aptr != NULL && BCL_NUM_NUM(aptr) != NULL); 144550696a6eSStefan Eßer 144644d4804dSStefan Eßer // Clear and initialize the result. 1447175a4d10SStefan Eßer bc_num_clear(BCL_NUM_NUM_NP(b)); 1448175a4d10SStefan Eßer bc_num_init(BCL_NUM_NUM_NP(b), BC_NUM_DEF_SIZE); 144950696a6eSStefan Eßer 1450175a4d10SStefan Eßer bc_num_irand(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), &vm->rng); 145150696a6eSStefan Eßer 145250696a6eSStefan Eßer err: 145344d4804dSStefan Eßer 1454175a4d10SStefan Eßer if (destruct) 1455175a4d10SStefan Eßer { 145644d4804dSStefan Eßer // Eat the operand. 145750696a6eSStefan Eßer bcl_num_dtor(ctxt, a, aptr); 1458175a4d10SStefan Eßer } 145944d4804dSStefan Eßer 1460d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 146150696a6eSStefan Eßer BC_MAYBE_SETUP(ctxt, e, b, idx); 146250696a6eSStefan Eßer 146350696a6eSStefan Eßer return idx; 146450696a6eSStefan Eßer } 146550696a6eSStefan Eßer 1466175a4d10SStefan Eßer BclNumber 1467175a4d10SStefan Eßer bcl_irand(BclNumber a) 1468175a4d10SStefan Eßer { 1469175a4d10SStefan Eßer return bcl_irand_helper(a, true); 1470175a4d10SStefan Eßer } 1471175a4d10SStefan Eßer 1472175a4d10SStefan Eßer BclNumber 1473175a4d10SStefan Eßer bcl_irand_keep(BclNumber a) 1474175a4d10SStefan Eßer { 1475175a4d10SStefan Eßer return bcl_irand_helper(a, false); 1476175a4d10SStefan Eßer } 1477175a4d10SStefan Eßer 147844d4804dSStefan Eßer /** 147944d4804dSStefan Eßer * Helps bcl_frand(). This is separate because the error handling is easier that 148044d4804dSStefan Eßer * way. It is also easier to do ifrand that way. 148144d4804dSStefan Eßer * @param b The return parameter. 148244d4804dSStefan Eßer * @param places The number of decimal places to generate. 148344d4804dSStefan Eßer */ 148478bc019dSStefan Eßer static void 148578bc019dSStefan Eßer bcl_frandHelper(BcNum* restrict b, size_t places) 148678bc019dSStefan Eßer { 148750696a6eSStefan Eßer BcNum exp, pow, ten; 148850696a6eSStefan Eßer BcDig exp_digs[BC_NUM_BIGDIG_LOG10]; 148950696a6eSStefan Eßer BcDig ten_digs[BC_NUM_BIGDIG_LOG10]; 1490d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 149150696a6eSStefan Eßer 149244d4804dSStefan Eßer // Set up temporaries. 149350696a6eSStefan Eßer bc_num_setup(&exp, exp_digs, BC_NUM_BIGDIG_LOG10); 149450696a6eSStefan Eßer bc_num_setup(&ten, ten_digs, BC_NUM_BIGDIG_LOG10); 149550696a6eSStefan Eßer 149650696a6eSStefan Eßer ten.num[0] = 10; 149750696a6eSStefan Eßer ten.len = 1; 149850696a6eSStefan Eßer 149950696a6eSStefan Eßer bc_num_bigdig2num(&exp, (BcBigDig) places); 150050696a6eSStefan Eßer 150144d4804dSStefan Eßer // Clear the temporary that might need to grow. 150250696a6eSStefan Eßer bc_num_clear(&pow); 150350696a6eSStefan Eßer 150444d4804dSStefan Eßer // Initialize the temporary that might need to grow. 150550696a6eSStefan Eßer bc_num_init(&pow, bc_num_powReq(&ten, &exp, 0)); 150650696a6eSStefan Eßer 1507d101cdd6SStefan Eßer BC_SETJMP(vm, err); 150850696a6eSStefan Eßer 150944d4804dSStefan Eßer // Generate the number. 151050696a6eSStefan Eßer bc_num_pow(&ten, &exp, &pow, 0); 1511d101cdd6SStefan Eßer bc_num_irand(&pow, b, &vm->rng); 151250696a6eSStefan Eßer 151344d4804dSStefan Eßer // Make the number entirely fraction. 151450696a6eSStefan Eßer bc_num_shiftRight(b, places); 151550696a6eSStefan Eßer 151650696a6eSStefan Eßer err: 1517175a4d10SStefan Eßer 151850696a6eSStefan Eßer bc_num_free(&pow); 1519d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm); 152050696a6eSStefan Eßer } 152150696a6eSStefan Eßer 152278bc019dSStefan Eßer BclNumber 152378bc019dSStefan Eßer bcl_frand(size_t places) 152478bc019dSStefan Eßer { 152550696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 1526175a4d10SStefan Eßer BclNum n; 152750696a6eSStefan Eßer BclNumber idx; 152850696a6eSStefan Eßer BclContext ctxt; 1529d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 153050696a6eSStefan Eßer 1531d101cdd6SStefan Eßer BC_CHECK_CTXT(vm, ctxt); 153250696a6eSStefan Eßer 1533d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 153450696a6eSStefan Eßer 1535175a4d10SStefan Eßer BCL_GROW_NUMS(ctxt); 153650696a6eSStefan Eßer 153744d4804dSStefan Eßer // Clear and initialize the number. 1538175a4d10SStefan Eßer bc_num_clear(BCL_NUM_NUM_NP(n)); 1539175a4d10SStefan Eßer bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE); 154050696a6eSStefan Eßer 1541175a4d10SStefan Eßer bcl_frandHelper(BCL_NUM_NUM_NP(n), places); 154250696a6eSStefan Eßer 154350696a6eSStefan Eßer err: 154444d4804dSStefan Eßer 1545d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 154650696a6eSStefan Eßer BC_MAYBE_SETUP(ctxt, e, n, idx); 154750696a6eSStefan Eßer 154850696a6eSStefan Eßer return idx; 154950696a6eSStefan Eßer } 155050696a6eSStefan Eßer 155144d4804dSStefan Eßer /** 155244d4804dSStefan Eßer * Helps bc_ifrand(). This is separate because error handling is easier that 155344d4804dSStefan Eßer * way. 155444d4804dSStefan Eßer * @param a The limit for bc_num_irand(). 155544d4804dSStefan Eßer * @param b The return parameter. 155644d4804dSStefan Eßer * @param places The number of decimal places to generate. 155744d4804dSStefan Eßer */ 155878bc019dSStefan Eßer static void 155978bc019dSStefan Eßer bcl_ifrandHelper(BcNum* restrict a, BcNum* restrict b, size_t places) 156050696a6eSStefan Eßer { 156150696a6eSStefan Eßer BcNum ir, fr; 1562d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 156350696a6eSStefan Eßer 156444d4804dSStefan Eßer // Clear the integer and fractional numbers. 156550696a6eSStefan Eßer bc_num_clear(&ir); 156650696a6eSStefan Eßer bc_num_clear(&fr); 156750696a6eSStefan Eßer 156844d4804dSStefan Eßer // Initialize the integer and fractional numbers. 156950696a6eSStefan Eßer bc_num_init(&ir, BC_NUM_DEF_SIZE); 157050696a6eSStefan Eßer bc_num_init(&fr, BC_NUM_DEF_SIZE); 157150696a6eSStefan Eßer 1572d101cdd6SStefan Eßer BC_SETJMP(vm, err); 157344d4804dSStefan Eßer 1574d101cdd6SStefan Eßer bc_num_irand(a, &ir, &vm->rng); 157550696a6eSStefan Eßer bcl_frandHelper(&fr, places); 157650696a6eSStefan Eßer 157750696a6eSStefan Eßer bc_num_add(&ir, &fr, b, 0); 157850696a6eSStefan Eßer 157950696a6eSStefan Eßer err: 1580175a4d10SStefan Eßer 158150696a6eSStefan Eßer bc_num_free(&fr); 158250696a6eSStefan Eßer bc_num_free(&ir); 1583d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm); 158450696a6eSStefan Eßer } 158550696a6eSStefan Eßer 1586175a4d10SStefan Eßer static BclNumber 1587175a4d10SStefan Eßer bcl_ifrand_helper(BclNumber a, size_t places, bool destruct) 158878bc019dSStefan Eßer { 158950696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 1590175a4d10SStefan Eßer BclNum* aptr; 1591175a4d10SStefan Eßer BclNum b; 159250696a6eSStefan Eßer BclNumber idx; 159350696a6eSStefan Eßer BclContext ctxt; 1594d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 159550696a6eSStefan Eßer 1596d101cdd6SStefan Eßer BC_CHECK_CTXT(vm, ctxt); 159750696a6eSStefan Eßer BC_CHECK_NUM(ctxt, a); 159850696a6eSStefan Eßer 1599d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 160050696a6eSStefan Eßer 1601175a4d10SStefan Eßer BCL_GROW_NUMS(ctxt); 160250696a6eSStefan Eßer 1603175a4d10SStefan Eßer assert(BCL_NO_GEN(a) < ctxt->nums.len); 160450696a6eSStefan Eßer 1605175a4d10SStefan Eßer aptr = BCL_NUM(ctxt, a); 160650696a6eSStefan Eßer 1607175a4d10SStefan Eßer assert(aptr != NULL && BCL_NUM_NUM(aptr) != NULL); 160850696a6eSStefan Eßer 160944d4804dSStefan Eßer // Clear and initialize the number. 1610175a4d10SStefan Eßer bc_num_clear(BCL_NUM_NUM_NP(b)); 1611175a4d10SStefan Eßer bc_num_init(BCL_NUM_NUM_NP(b), BC_NUM_DEF_SIZE); 161250696a6eSStefan Eßer 1613175a4d10SStefan Eßer bcl_ifrandHelper(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), places); 161450696a6eSStefan Eßer 161550696a6eSStefan Eßer err: 161644d4804dSStefan Eßer 1617175a4d10SStefan Eßer if (destruct) 1618175a4d10SStefan Eßer { 161944d4804dSStefan Eßer // Eat the oprand. 162050696a6eSStefan Eßer bcl_num_dtor(ctxt, a, aptr); 1621175a4d10SStefan Eßer } 162244d4804dSStefan Eßer 1623d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 162450696a6eSStefan Eßer BC_MAYBE_SETUP(ctxt, e, b, idx); 162550696a6eSStefan Eßer 162650696a6eSStefan Eßer return idx; 162750696a6eSStefan Eßer } 162850696a6eSStefan Eßer 1629175a4d10SStefan Eßer BclNumber 1630175a4d10SStefan Eßer bcl_ifrand(BclNumber a, size_t places) 1631175a4d10SStefan Eßer { 1632175a4d10SStefan Eßer return bcl_ifrand_helper(a, places, true); 1633175a4d10SStefan Eßer } 1634175a4d10SStefan Eßer 1635175a4d10SStefan Eßer BclNumber 1636175a4d10SStefan Eßer bcl_ifrand_keep(BclNumber a, size_t places) 1637175a4d10SStefan Eßer { 1638175a4d10SStefan Eßer return bcl_ifrand_helper(a, places, false); 1639175a4d10SStefan Eßer } 1640175a4d10SStefan Eßer 1641175a4d10SStefan Eßer static BclError 1642175a4d10SStefan Eßer bcl_rand_seedWithNum_helper(BclNumber n, bool destruct) 164378bc019dSStefan Eßer { 164450696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 1645175a4d10SStefan Eßer BclNum* nptr; 164650696a6eSStefan Eßer BclContext ctxt; 1647d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 164850696a6eSStefan Eßer 1649d101cdd6SStefan Eßer BC_CHECK_CTXT_ERR(vm, ctxt); 165050696a6eSStefan Eßer BC_CHECK_NUM_ERR(ctxt, n); 165150696a6eSStefan Eßer 1652d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 165350696a6eSStefan Eßer 1654175a4d10SStefan Eßer assert(BCL_NO_GEN(n) < ctxt->nums.len); 165550696a6eSStefan Eßer 1656175a4d10SStefan Eßer nptr = BCL_NUM(ctxt, n); 165750696a6eSStefan Eßer 1658175a4d10SStefan Eßer assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL); 165950696a6eSStefan Eßer 1660175a4d10SStefan Eßer bc_num_rng(BCL_NUM_NUM(nptr), &vm->rng); 166150696a6eSStefan Eßer 166250696a6eSStefan Eßer err: 1663175a4d10SStefan Eßer 1664175a4d10SStefan Eßer if (destruct) 1665175a4d10SStefan Eßer { 1666175a4d10SStefan Eßer // Eat the oprand. 1667175a4d10SStefan Eßer bcl_num_dtor(ctxt, n, nptr); 1668175a4d10SStefan Eßer } 1669175a4d10SStefan Eßer 1670d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 1671175a4d10SStefan Eßer 167250696a6eSStefan Eßer return e; 167350696a6eSStefan Eßer } 167450696a6eSStefan Eßer 167578bc019dSStefan Eßer BclError 1676175a4d10SStefan Eßer bcl_rand_seedWithNum(BclNumber n) 1677175a4d10SStefan Eßer { 1678175a4d10SStefan Eßer return bcl_rand_seedWithNum_helper(n, true); 1679175a4d10SStefan Eßer } 1680175a4d10SStefan Eßer 1681175a4d10SStefan Eßer BclError 1682175a4d10SStefan Eßer bcl_rand_seedWithNum_keep(BclNumber n) 1683175a4d10SStefan Eßer { 1684175a4d10SStefan Eßer return bcl_rand_seedWithNum_helper(n, false); 1685175a4d10SStefan Eßer } 1686175a4d10SStefan Eßer 1687175a4d10SStefan Eßer BclError 168878bc019dSStefan Eßer bcl_rand_seed(unsigned char seed[BCL_SEED_SIZE]) 168978bc019dSStefan Eßer { 169050696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 169150696a6eSStefan Eßer size_t i; 169244d4804dSStefan Eßer ulong vals[BCL_SEED_ULONGS]; 1693d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 169450696a6eSStefan Eßer 1695d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 169650696a6eSStefan Eßer 169744d4804dSStefan Eßer // Fill the array. 169878bc019dSStefan Eßer for (i = 0; i < BCL_SEED_SIZE; ++i) 169978bc019dSStefan Eßer { 170078bc019dSStefan Eßer ulong val = ((ulong) seed[i]) 170178bc019dSStefan Eßer << (((ulong) CHAR_BIT) * (i % sizeof(ulong))); 170250696a6eSStefan Eßer vals[i / sizeof(long)] |= val; 170350696a6eSStefan Eßer } 170450696a6eSStefan Eßer 1705d101cdd6SStefan Eßer bc_rand_seed(&vm->rng, vals[0], vals[1], vals[2], vals[3]); 170650696a6eSStefan Eßer 170750696a6eSStefan Eßer err: 1708175a4d10SStefan Eßer 1709d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 1710175a4d10SStefan Eßer 171150696a6eSStefan Eßer return e; 171250696a6eSStefan Eßer } 171350696a6eSStefan Eßer 171478bc019dSStefan Eßer void 171578bc019dSStefan Eßer bcl_rand_reseed(void) 171678bc019dSStefan Eßer { 1717d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 1718d101cdd6SStefan Eßer 1719d101cdd6SStefan Eßer bc_rand_srand(bc_vec_top(&vm->rng.v)); 172050696a6eSStefan Eßer } 172150696a6eSStefan Eßer 172278bc019dSStefan Eßer BclNumber 172378bc019dSStefan Eßer bcl_rand_seed2num(void) 172478bc019dSStefan Eßer { 172550696a6eSStefan Eßer BclError e = BCL_ERROR_NONE; 1726175a4d10SStefan Eßer BclNum n; 172750696a6eSStefan Eßer BclNumber idx; 172850696a6eSStefan Eßer BclContext ctxt; 1729d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 173050696a6eSStefan Eßer 1731d101cdd6SStefan Eßer BC_CHECK_CTXT(vm, ctxt); 173250696a6eSStefan Eßer 1733d101cdd6SStefan Eßer BC_FUNC_HEADER(vm, err); 173450696a6eSStefan Eßer 173544d4804dSStefan Eßer // Clear and initialize the number. 1736175a4d10SStefan Eßer bc_num_clear(BCL_NUM_NUM_NP(n)); 1737175a4d10SStefan Eßer bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE); 173850696a6eSStefan Eßer 1739175a4d10SStefan Eßer bc_num_createFromRNG(BCL_NUM_NUM_NP(n), &vm->rng); 174050696a6eSStefan Eßer 174150696a6eSStefan Eßer err: 1742175a4d10SStefan Eßer 1743d101cdd6SStefan Eßer BC_FUNC_FOOTER(vm, e); 174450696a6eSStefan Eßer BC_MAYBE_SETUP(ctxt, e, n, idx); 174550696a6eSStefan Eßer 174650696a6eSStefan Eßer return idx; 174750696a6eSStefan Eßer } 174850696a6eSStefan Eßer 174978bc019dSStefan Eßer BclRandInt 175078bc019dSStefan Eßer bcl_rand_int(void) 175178bc019dSStefan Eßer { 1752d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 1753d101cdd6SStefan Eßer 1754d101cdd6SStefan Eßer return (BclRandInt) bc_rand_int(&vm->rng); 175550696a6eSStefan Eßer } 175650696a6eSStefan Eßer 175778bc019dSStefan Eßer BclRandInt 175878bc019dSStefan Eßer bcl_rand_bounded(BclRandInt bound) 175978bc019dSStefan Eßer { 1760d101cdd6SStefan Eßer BcVm* vm = bcl_getspecific(); 1761d101cdd6SStefan Eßer 176250696a6eSStefan Eßer if (bound <= 1) return 0; 1763d101cdd6SStefan Eßer return (BclRandInt) bc_rand_bounded(&vm->rng, (BcRand) bound); 176450696a6eSStefan Eßer } 176550696a6eSStefan Eßer 1766175a4d10SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 1767175a4d10SStefan Eßer 176850696a6eSStefan Eßer #endif // BC_ENABLE_LIBRARY 1769