2 * *****************************************************************************
4 * SPDX-License-Identifier: BSD-2-Clause
6 * Copyright (c) 2018-2023 Gavin D. Howard and contributors.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 * *****************************************************************************
32 * The public functions for libbc.
52 // The asserts in this file are important to testing; in many cases, the test
53 // would not work without the asserts, so don't remove them without reason.
55 // Also, there are many uses of bc_num_clear() here; that is because numbers are
56 // being reused, and a clean slate is required.
58 // Also, there are a bunch of BC_UNSETJMP between calls to bc_num_init(). That
59 // is because locals are being initialized, and unlike bc proper, this code
60 // cannot assume that allocation failures are fatal. So we have to reset the
61 // jumps every time to ensure that the locals will be correct after jumping.
63 #if BC_ENABLE_MEMCHECK
66 bcl_invalidGeneration(void)
72 bcl_nonexistentNum(void)
78 bcl_numIdxOutOfRange(void)
83 #endif // BC_ENABLE_MEMCHECK
85 static BclTls* tls = NULL;
86 static BclTls tls_real;
95 if (tls != NULL) return BCL_ERROR_NONE;
97 r = pthread_key_create(&tls_real, NULL);
98 if (BC_ERR(r != 0)) return BCL_ERROR_FATAL_ALLOC_ERR;
102 if (tls != NULL) return BCL_ERROR_NONE;
104 tls_real = TlsAlloc();
105 if (BC_ERR(tls_real == TLS_OUT_OF_INDEXES))
107 return BCL_ERROR_FATAL_ALLOC_ERR;
114 return BCL_ERROR_NONE;
118 * Sets the thread-specific data for the thread.
119 * @param vm The @a BcVm to set as the thread data.
120 * @return An error code, if any.
123 bcl_setspecific(BcVm* vm)
131 r = pthread_setspecific(tls_real, vm);
132 if (BC_ERR(r != 0)) return BCL_ERROR_FATAL_ALLOC_ERR;
140 r = TlsSetValue(tls_real, vm);
141 if (BC_ERR(!r)) return BCL_ERROR_FATAL_ALLOC_ERR;
145 return BCL_ERROR_NONE;
149 bcl_getspecific(void)
155 vm = pthread_getspecific(tls_real);
159 vm = TlsGetValue(tls_real);
169 BclError e = BCL_ERROR_NONE;
174 vm = bcl_getspecific();
177 assert(vm->refs >= 1);
184 vm = bc_vm_malloc(sizeof(BcVm));
185 if (BC_ERR(vm == NULL)) return BCL_ERROR_FATAL_ALLOC_ERR;
187 e = bcl_setspecific(vm);
188 if (BC_ERR(e != BCL_ERROR_NONE))
194 memset(vm, 0, sizeof(BcVm));
198 assert(vm->refs == 1);
200 // Setting these to NULL ensures that if an error occurs, we only free what
203 vm->jmp_bufs.v = NULL;
207 vm->leading_zeroes = false;
208 vm->digit_clamp = true;
210 // The jmp_bufs always has to be initialized first.
211 bc_vec_init(&vm->jmp_bufs, sizeof(sigjmp_buf), BC_DTOR_NONE);
213 BC_FUNC_HEADER(vm, err);
217 bc_vec_init(&vm->ctxts, sizeof(BclContext), BC_DTOR_NONE);
218 bc_vec_init(&vm->out, sizeof(uchar), BC_DTOR_NONE);
220 #if BC_ENABLE_EXTRA_MATH
222 // We need to seed this in case /dev/random and /dev/urandom don't work.
223 srand((unsigned int) time(NULL));
224 bc_rand_init(&vm->rng);
226 #endif // BC_ENABLE_EXTRA_MATH
230 BC_FUNC_FOOTER(vm, e);
232 // This is why we had to set them to NULL.
233 if (BC_ERR(vm != NULL && vm->err))
235 if (vm->out.v != NULL) bc_vec_free(&vm->out);
236 if (vm->jmp_bufs.v != NULL) bc_vec_free(&vm->jmp_bufs);
237 if (vm->ctxts.v != NULL) bc_vec_free(&vm->ctxts);
238 bcl_setspecific(NULL);
246 bcl_pushContext(BclContext ctxt)
248 BclError e = BCL_ERROR_NONE;
249 BcVm* vm = bcl_getspecific();
251 BC_FUNC_HEADER(vm, err);
253 bc_vec_push(&vm->ctxts, &ctxt);
257 BC_FUNC_FOOTER(vm, e);
264 BcVm* vm = bcl_getspecific();
266 if (vm->ctxts.len) bc_vec_pop(&vm->ctxts);
270 bcl_contextHelper(BcVm* vm)
272 if (!vm->ctxts.len) return NULL;
273 return *((BclContext*) bc_vec_top(&vm->ctxts));
279 BcVm* vm = bcl_getspecific();
280 return bcl_contextHelper(vm);
287 BcVm* vm = bcl_getspecific();
290 if (vm->refs) return;
292 #if BC_ENABLE_EXTRA_MATH
293 bc_rand_free(&vm->rng);
294 #endif // BC_ENABLE_EXTRA_MATH
295 bc_vec_free(&vm->out);
297 for (i = 0; i < vm->ctxts.len; ++i)
299 BclContext ctxt = *((BclContext*) bc_vec_item(&vm->ctxts, i));
303 bc_vec_free(&vm->ctxts);
308 bcl_setspecific(NULL);
316 // We ignore the return value.
317 pthread_key_delete(tls_real);
321 // We ignore the return value.
336 bcl_abortOnFatalError(void)
338 BcVm* vm = bcl_getspecific();
344 bcl_setAbortOnFatalError(bool abrt)
346 BcVm* vm = bcl_getspecific();
352 bcl_leadingZeroes(void)
354 BcVm* vm = bcl_getspecific();
356 return vm->leading_zeroes;
360 bcl_setLeadingZeroes(bool leadingZeroes)
362 BcVm* vm = bcl_getspecific();
364 vm->leading_zeroes = leadingZeroes;
370 BcVm* vm = bcl_getspecific();
372 return vm->digit_clamp;
376 bcl_setDigitClamp(bool digitClamp)
378 BcVm* vm = bcl_getspecific();
380 vm->digit_clamp = digitClamp;
384 bcl_ctxt_create(void)
386 BcVm* vm = bcl_getspecific();
387 BclContext ctxt = NULL;
389 BC_FUNC_HEADER(vm, err);
391 // We want the context to be free of any interference of other parties, so
392 // malloc() is appropriate here.
393 ctxt = bc_vm_malloc(sizeof(BclCtxt));
395 bc_vec_init(&ctxt->nums, sizeof(BclNum), BC_DTOR_BCL_NUM);
396 bc_vec_init(&ctxt->free_nums, sizeof(BclNumber), BC_DTOR_NONE);
404 if (BC_ERR(vm->err && ctxt != NULL))
406 if (ctxt->nums.v != NULL) bc_vec_free(&ctxt->nums);
411 BC_FUNC_FOOTER_NO_ERR(vm);
417 bcl_ctxt_free(BclContext ctxt)
419 bc_vec_free(&ctxt->free_nums);
420 bc_vec_free(&ctxt->nums);
425 bcl_ctxt_freeNums(BclContext ctxt)
427 bc_vec_popAll(&ctxt->nums);
428 bc_vec_popAll(&ctxt->free_nums);
432 bcl_ctxt_scale(BclContext ctxt)
438 bcl_ctxt_setScale(BclContext ctxt, size_t scale)
444 bcl_ctxt_ibase(BclContext ctxt)
450 bcl_ctxt_setIbase(BclContext ctxt, size_t ibase)
452 if (ibase < BC_NUM_MIN_BASE) ibase = BC_NUM_MIN_BASE;
453 else if (ibase > BC_NUM_MAX_IBASE) ibase = BC_NUM_MAX_IBASE;
458 bcl_ctxt_obase(BclContext ctxt)
464 bcl_ctxt_setObase(BclContext ctxt, size_t obase)
473 BcVm* vm = bcl_getspecific();
475 BC_CHECK_CTXT_ERR(vm, ctxt);
477 // We need to clear the top byte in memcheck mode. We can do this because
478 // the parameter is a copy.
481 // Errors are encoded as (0 - error_code). If the index is in that range, it
482 // is an encoded error.
483 if (n.i >= ctxt->nums.len)
485 if (n.i > 0 - (size_t) BCL_ERROR_NELEMS) return (BclError) (0 - n.i);
486 else return BCL_ERROR_INVALID_NUM;
488 else return BCL_ERROR_NONE;
492 * Inserts a BcNum into a context's list of numbers.
493 * @param ctxt The context to insert into.
494 * @param n The BcNum to insert.
495 * @return The resulting BclNumber from the insert.
498 bcl_num_insert(BclContext ctxt, BclNum* restrict n)
502 // If there is a free spot...
503 if (ctxt->free_nums.len)
507 // Get the index of the free spot and remove it.
508 idx = *((BclNumber*) bc_vec_top(&ctxt->free_nums));
509 bc_vec_pop(&ctxt->free_nums);
511 // Copy the number into the spot.
512 ptr = bc_vec_item(&ctxt->nums, idx.i);
514 memcpy(BCL_NUM_NUM(ptr), n, sizeof(BcNum));
516 #if BC_ENABLE_MEMCHECK
520 if (ptr->gen_idx == UCHAR_MAX)
525 idx.i |= (ptr->gen_idx << ((sizeof(size_t) - 1) * CHAR_BIT));
527 #endif // BC_ENABLE_MEMCHECK
531 #if BC_ENABLE_MEMCHECK
533 #endif // BC_ENABLE_MEMCHECK
535 // Just push the number onto the vector because the generation index is
537 idx.i = ctxt->nums.len;
538 bc_vec_push(&ctxt->nums, n);
547 BclError e = BCL_ERROR_NONE;
551 BcVm* vm = bcl_getspecific();
553 BC_CHECK_CTXT(vm, ctxt);
555 BC_FUNC_HEADER(vm, err);
559 bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE);
563 BC_FUNC_FOOTER(vm, e);
564 BC_MAYBE_SETUP(ctxt, e, n, idx);
570 * Destructs a number and marks its spot as free.
571 * @param ctxt The context.
572 * @param n The index of the number.
573 * @param num The number to destroy.
576 bcl_num_dtor(BclContext ctxt, BclNumber n, BclNum* restrict num)
578 assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
582 bcl_num_destruct(num);
583 bc_vec_push(&ctxt->free_nums, &n);
585 #if BC_ENABLE_MEMCHECK
587 #endif // BC_ENABLE_MEMCHECK
591 bcl_num_free(BclNumber n)
595 BcVm* vm = bcl_getspecific();
597 BC_CHECK_CTXT_ASSERT(vm, ctxt);
599 BCL_CHECK_NUM_VALID(ctxt, n);
601 assert(BCL_NO_GEN(n) < ctxt->nums.len);
603 num = BCL_NUM(ctxt, n);
605 bcl_num_dtor(ctxt, n, num);
609 bcl_copy(BclNumber d, BclNumber s)
611 BclError e = BCL_ERROR_NONE;
615 BcVm* vm = bcl_getspecific();
617 BC_CHECK_CTXT_ERR(vm, ctxt);
619 BCL_CHECK_NUM_VALID(ctxt, d);
620 BCL_CHECK_NUM_VALID(ctxt, s);
622 BC_FUNC_HEADER(vm, err);
624 assert(BCL_NO_GEN(d) < ctxt->nums.len);
625 assert(BCL_NO_GEN(s) < ctxt->nums.len);
627 dest = BCL_NUM(ctxt, d);
628 src = BCL_NUM(ctxt, s);
630 assert(dest != NULL && src != NULL);
631 assert(BCL_NUM_ARRAY(dest) != NULL && BCL_NUM_ARRAY(src) != NULL);
633 bc_num_copy(BCL_NUM_NUM(dest), BCL_NUM_NUM(src));
637 BC_FUNC_FOOTER(vm, e);
645 BclError e = BCL_ERROR_NONE;
649 BcVm* vm = bcl_getspecific();
651 BC_CHECK_CTXT(vm, ctxt);
653 BCL_CHECK_NUM_VALID(ctxt, s);
655 BC_FUNC_HEADER(vm, err);
659 assert(BCL_NO_GEN(s) < ctxt->nums.len);
661 src = BCL_NUM(ctxt, s);
663 assert(src != NULL && BCL_NUM_NUM(src) != NULL);
666 bc_num_clear(BCL_NUM_NUM(&dest));
667 bc_num_createCopy(BCL_NUM_NUM(&dest), BCL_NUM_NUM(src));
671 BC_FUNC_FOOTER(vm, e);
672 BC_MAYBE_SETUP(ctxt, e, dest, idx);
678 bcl_num_destruct(void* num)
680 BclNum* n = (BclNum*) num;
684 if (BCL_NUM_ARRAY(n) == NULL) return;
686 bc_num_free(BCL_NUM_NUM(n));
687 bc_num_clear(BCL_NUM_NUM(n));
691 bcl_num_neg(BclNumber n)
695 BcVm* vm = bcl_getspecific();
697 BC_CHECK_CTXT_ASSERT(vm, ctxt);
699 BCL_CHECK_NUM_VALID(ctxt, n);
701 assert(BCL_NO_GEN(n) < ctxt->nums.len);
703 num = BCL_NUM(ctxt, n);
705 assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
707 return BC_NUM_NEG(BCL_NUM_NUM(num)) != 0;
711 bcl_num_setNeg(BclNumber n, bool neg)
715 BcVm* vm = bcl_getspecific();
717 BC_CHECK_CTXT_ASSERT(vm, ctxt);
719 BCL_CHECK_NUM_VALID(ctxt, n);
721 assert(BCL_NO_GEN(n) < ctxt->nums.len);
723 num = BCL_NUM(ctxt, n);
725 assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
727 BCL_NUM_NUM(num)->rdx = BC_NUM_NEG_VAL(BCL_NUM_NUM(num), neg);
731 bcl_num_scale(BclNumber n)
735 BcVm* vm = bcl_getspecific();
737 BC_CHECK_CTXT_ASSERT(vm, ctxt);
739 BCL_CHECK_NUM_VALID(ctxt, n);
741 assert(BCL_NO_GEN(n) < ctxt->nums.len);
743 num = BCL_NUM(ctxt, n);
745 assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
747 return bc_num_scale(BCL_NUM_NUM(num));
751 bcl_num_setScale(BclNumber n, size_t scale)
753 BclError e = BCL_ERROR_NONE;
756 BcVm* vm = bcl_getspecific();
758 BC_CHECK_CTXT_ERR(vm, ctxt);
760 BC_CHECK_NUM_ERR(ctxt, n);
762 BCL_CHECK_NUM_VALID(ctxt, n);
764 BC_FUNC_HEADER(vm, err);
766 assert(BCL_NO_GEN(n) < ctxt->nums.len);
768 nptr = BCL_NUM(ctxt, n);
770 assert(nptr != NULL && BCL_NUM_ARRAY(nptr) != NULL);
772 if (scale > BCL_NUM_NUM(nptr)->scale)
774 bc_num_extend(BCL_NUM_NUM(nptr), scale - BCL_NUM_NUM(nptr)->scale);
776 else if (scale < BCL_NUM_NUM(nptr)->scale)
778 bc_num_truncate(BCL_NUM_NUM(nptr), BCL_NUM_NUM(nptr)->scale - scale);
783 BC_FUNC_FOOTER(vm, e);
789 bcl_num_len(BclNumber n)
793 BcVm* vm = bcl_getspecific();
795 BC_CHECK_CTXT_ASSERT(vm, ctxt);
797 BCL_CHECK_NUM_VALID(ctxt, n);
799 assert(BCL_NO_GEN(n) < ctxt->nums.len);
801 num = BCL_NUM(ctxt, n);
803 assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
805 return bc_num_len(BCL_NUM_NUM(num));
809 bcl_bigdig_helper(BclNumber n, BclBigDig* result, bool destruct)
811 BclError e = BCL_ERROR_NONE;
814 BcVm* vm = bcl_getspecific();
816 BC_CHECK_CTXT_ERR(vm, ctxt);
818 BCL_CHECK_NUM_VALID(ctxt, n);
820 BC_FUNC_HEADER(vm, err);
822 assert(BCL_NO_GEN(n) < ctxt->nums.len);
823 assert(result != NULL);
825 num = BCL_NUM(ctxt, n);
827 assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
829 *result = bc_num_bigdig(BCL_NUM_NUM(num));
835 bcl_num_dtor(ctxt, n, num);
838 BC_FUNC_FOOTER(vm, e);
844 bcl_bigdig(BclNumber n, BclBigDig* result)
846 return bcl_bigdig_helper(n, result, true);
850 bcl_bigdig_keep(BclNumber n, BclBigDig* result)
852 return bcl_bigdig_helper(n, result, false);
856 bcl_bigdig2num(BclBigDig val)
858 BclError e = BCL_ERROR_NONE;
862 BcVm* vm = bcl_getspecific();
864 BC_CHECK_CTXT(vm, ctxt);
866 BC_FUNC_HEADER(vm, err);
870 bc_num_createFromBigdig(BCL_NUM_NUM_NP(n), val);
874 BC_FUNC_FOOTER(vm, e);
875 BC_MAYBE_SETUP(ctxt, e, n, idx);
881 * Sets up and executes a binary operator operation.
882 * @param a The first operand.
883 * @param b The second operand.
884 * @param op The operation.
885 * @param req The function to get the size of the result for
887 * @param destruct True if the parameters should be consumed, false otherwise.
888 * @return The result of the operation.
891 bcl_binary(BclNumber a, BclNumber b, const BcNumBinaryOp op,
892 const BcNumBinaryOpReq req, bool destruct)
894 BclError e = BCL_ERROR_NONE;
900 BcVm* vm = bcl_getspecific();
902 BC_CHECK_CTXT(vm, ctxt);
904 BC_CHECK_NUM(ctxt, a);
905 BC_CHECK_NUM(ctxt, b);
907 BC_FUNC_HEADER(vm, err);
911 assert(BCL_NO_GEN(a) < ctxt->nums.len && BCL_NO_GEN(b) < ctxt->nums.len);
913 aptr = BCL_NUM(ctxt, a);
914 bptr = BCL_NUM(ctxt, b);
916 assert(aptr != NULL && bptr != NULL);
917 assert(BCL_NUM_ARRAY(aptr) != NULL && BCL_NUM_ARRAY(bptr) != NULL);
919 // Clear and initialize the result.
920 bc_num_clear(BCL_NUM_NUM_NP(c));
921 bc_num_init(BCL_NUM_NUM_NP(c),
922 req(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), ctxt->scale));
924 op(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM_NP(c), ctxt->scale);
931 bcl_num_dtor(ctxt, a, aptr);
932 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
935 BC_FUNC_FOOTER(vm, e);
936 BC_MAYBE_SETUP(ctxt, e, c, idx);
942 bcl_add(BclNumber a, BclNumber b)
944 return bcl_binary(a, b, bc_num_add, bc_num_addReq, true);
948 bcl_add_keep(BclNumber a, BclNumber b)
950 return bcl_binary(a, b, bc_num_add, bc_num_addReq, false);
954 bcl_sub(BclNumber a, BclNumber b)
956 return bcl_binary(a, b, bc_num_sub, bc_num_addReq, true);
960 bcl_sub_keep(BclNumber a, BclNumber b)
962 return bcl_binary(a, b, bc_num_sub, bc_num_addReq, false);
966 bcl_mul(BclNumber a, BclNumber b)
968 return bcl_binary(a, b, bc_num_mul, bc_num_mulReq, true);
972 bcl_mul_keep(BclNumber a, BclNumber b)
974 return bcl_binary(a, b, bc_num_mul, bc_num_mulReq, false);
978 bcl_div(BclNumber a, BclNumber b)
980 return bcl_binary(a, b, bc_num_div, bc_num_divReq, true);
984 bcl_div_keep(BclNumber a, BclNumber b)
986 return bcl_binary(a, b, bc_num_div, bc_num_divReq, false);
990 bcl_mod(BclNumber a, BclNumber b)
992 return bcl_binary(a, b, bc_num_mod, bc_num_divReq, true);
996 bcl_mod_keep(BclNumber a, BclNumber b)
998 return bcl_binary(a, b, bc_num_mod, bc_num_divReq, false);
1002 bcl_pow(BclNumber a, BclNumber b)
1004 return bcl_binary(a, b, bc_num_pow, bc_num_powReq, true);
1008 bcl_pow_keep(BclNumber a, BclNumber b)
1010 return bcl_binary(a, b, bc_num_pow, bc_num_powReq, false);
1014 bcl_lshift(BclNumber a, BclNumber b)
1016 return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq, true);
1020 bcl_lshift_keep(BclNumber a, BclNumber b)
1022 return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq, false);
1026 bcl_rshift(BclNumber a, BclNumber b)
1028 return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq, true);
1032 bcl_rshift_keep(BclNumber a, BclNumber b)
1034 return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq, false);
1038 bcl_sqrt_helper(BclNumber a, bool destruct)
1040 BclError e = BCL_ERROR_NONE;
1045 BcVm* vm = bcl_getspecific();
1047 BC_CHECK_CTXT(vm, ctxt);
1049 BC_CHECK_NUM(ctxt, a);
1051 BC_FUNC_HEADER(vm, err);
1053 BCL_GROW_NUMS(ctxt);
1055 assert(BCL_NO_GEN(a) < ctxt->nums.len);
1057 aptr = BCL_NUM(ctxt, a);
1059 bc_num_sqrt(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), ctxt->scale);
1065 bcl_num_dtor(ctxt, a, aptr);
1068 BC_FUNC_FOOTER(vm, e);
1069 BC_MAYBE_SETUP(ctxt, e, b, idx);
1075 bcl_sqrt(BclNumber a)
1077 return bcl_sqrt_helper(a, true);
1081 bcl_sqrt_keep(BclNumber a)
1083 return bcl_sqrt_helper(a, false);
1087 bcl_divmod_helper(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d,
1090 BclError e = BCL_ERROR_NONE;
1096 BcVm* vm = bcl_getspecific();
1098 BC_CHECK_CTXT_ERR(vm, ctxt);
1100 BC_CHECK_NUM_ERR(ctxt, a);
1101 BC_CHECK_NUM_ERR(ctxt, b);
1103 BC_FUNC_HEADER(vm, err);
1105 BCL_GROW_NUMS(ctxt);
1107 assert(c != NULL && d != NULL);
1109 aptr = BCL_NUM(ctxt, a);
1110 bptr = BCL_NUM(ctxt, b);
1112 assert(aptr != NULL && bptr != NULL);
1113 assert(BCL_NUM_ARRAY(aptr) != NULL && BCL_NUM_ARRAY(bptr) != NULL);
1115 bc_num_clear(BCL_NUM_NUM_NP(cnum));
1116 bc_num_clear(BCL_NUM_NUM_NP(dnum));
1118 req = bc_num_divReq(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), ctxt->scale);
1120 // Initialize the numbers.
1121 bc_num_init(BCL_NUM_NUM_NP(cnum), req);
1124 bc_num_init(BCL_NUM_NUM_NP(dnum), req);
1126 bc_num_divmod(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM_NP(cnum),
1127 BCL_NUM_NUM_NP(dnum), ctxt->scale);
1133 // Eat the operands.
1134 bcl_num_dtor(ctxt, a, aptr);
1135 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
1138 // If there was an error...
1139 if (BC_ERR(vm->err))
1141 // Free the results.
1142 if (BCL_NUM_ARRAY_NP(cnum) != NULL) bc_num_free(&cnum);
1143 if (BCL_NUM_ARRAY_NP(cnum) != NULL) bc_num_free(&dnum);
1145 // Make sure the return values are invalid.
1146 c->i = 0 - (size_t) BCL_ERROR_INVALID_NUM;
1149 BC_FUNC_FOOTER(vm, e);
1153 BC_FUNC_FOOTER(vm, e);
1155 // Insert the results into the context.
1156 *c = bcl_num_insert(ctxt, &cnum);
1157 *d = bcl_num_insert(ctxt, &dnum);
1164 bcl_divmod(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d)
1166 return bcl_divmod_helper(a, b, c, d, true);
1170 bcl_divmod_keep(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d)
1172 return bcl_divmod_helper(a, b, c, d, false);
1176 bcl_modexp_helper(BclNumber a, BclNumber b, BclNumber c, bool destruct)
1178 BclError e = BCL_ERROR_NONE;
1186 BcVm* vm = bcl_getspecific();
1188 BC_CHECK_CTXT(vm, ctxt);
1190 BC_CHECK_NUM(ctxt, a);
1191 BC_CHECK_NUM(ctxt, b);
1192 BC_CHECK_NUM(ctxt, c);
1194 BC_FUNC_HEADER(vm, err);
1196 BCL_GROW_NUMS(ctxt);
1198 assert(BCL_NO_GEN(a) < ctxt->nums.len && BCL_NO_GEN(b) < ctxt->nums.len);
1199 assert(BCL_NO_GEN(c) < ctxt->nums.len);
1201 aptr = BCL_NUM(ctxt, a);
1202 bptr = BCL_NUM(ctxt, b);
1203 cptr = BCL_NUM(ctxt, c);
1205 assert(aptr != NULL && bptr != NULL && cptr != NULL);
1206 assert(BCL_NUM_NUM(aptr) != NULL && BCL_NUM_NUM(bptr) != NULL &&
1207 BCL_NUM_NUM(cptr) != NULL);
1209 // Prepare the result.
1210 bc_num_clear(BCL_NUM_NUM_NP(d));
1212 req = bc_num_divReq(BCL_NUM_NUM(aptr), BCL_NUM_NUM(cptr), 0);
1214 // Initialize the result.
1215 bc_num_init(BCL_NUM_NUM_NP(d), req);
1217 bc_num_modexp(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM(cptr),
1224 // Eat the operands.
1225 bcl_num_dtor(ctxt, a, aptr);
1226 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
1227 if (c.i != a.i && c.i != b.i) bcl_num_dtor(ctxt, c, cptr);
1230 BC_FUNC_FOOTER(vm, e);
1231 BC_MAYBE_SETUP(ctxt, e, d, idx);
1237 bcl_modexp(BclNumber a, BclNumber b, BclNumber c)
1239 return bcl_modexp_helper(a, b, c, true);
1243 bcl_modexp_keep(BclNumber a, BclNumber b, BclNumber c)
1245 return bcl_modexp_helper(a, b, c, false);
1249 bcl_cmp(BclNumber a, BclNumber b)
1254 BcVm* vm = bcl_getspecific();
1256 BC_CHECK_CTXT_ASSERT(vm, ctxt);
1258 BCL_CHECK_NUM_VALID(ctxt, a);
1259 BCL_CHECK_NUM_VALID(ctxt, b);
1261 assert(BCL_NO_GEN(a) < ctxt->nums.len && BCL_NO_GEN(b) < ctxt->nums.len);
1263 aptr = BCL_NUM(ctxt, a);
1264 bptr = BCL_NUM(ctxt, b);
1266 assert(aptr != NULL && bptr != NULL);
1267 assert(BCL_NUM_NUM(aptr) != NULL && BCL_NUM_NUM(bptr));
1269 return bc_num_cmp(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr));
1273 bcl_zero(BclNumber n)
1277 BcVm* vm = bcl_getspecific();
1279 BC_CHECK_CTXT_ASSERT(vm, ctxt);
1281 BCL_CHECK_NUM_VALID(ctxt, n);
1283 assert(BCL_NO_GEN(n) < ctxt->nums.len);
1285 nptr = BCL_NUM(ctxt, n);
1287 assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL);
1289 bc_num_zero(BCL_NUM_NUM(nptr));
1293 bcl_one(BclNumber n)
1297 BcVm* vm = bcl_getspecific();
1299 BC_CHECK_CTXT_ASSERT(vm, ctxt);
1301 BCL_CHECK_NUM_VALID(ctxt, n);
1303 assert(BCL_NO_GEN(n) < ctxt->nums.len);
1305 nptr = BCL_NUM(ctxt, n);
1307 assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL);
1309 bc_num_one(BCL_NUM_NUM(nptr));
1313 bcl_parse(const char* restrict val)
1315 BclError e = BCL_ERROR_NONE;
1319 BcVm* vm = bcl_getspecific();
1322 BC_CHECK_CTXT(vm, ctxt);
1324 BC_FUNC_HEADER(vm, err);
1326 BCL_GROW_NUMS(ctxt);
1328 assert(val != NULL);
1330 // We have to take care of negative here because bc's number parsing does
1332 neg = (val[0] == '-');
1336 if (!bc_num_strValid(val))
1338 vm->err = BCL_ERROR_PARSE_INVALID_STR;
1342 // Clear and initialize the number.
1343 bc_num_clear(BCL_NUM_NUM_NP(n));
1344 bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE);
1346 bc_num_parse(BCL_NUM_NUM_NP(n), val, (BcBigDig) ctxt->ibase);
1348 // Set the negative.
1349 #if BC_ENABLE_MEMCHECK
1350 n.n.rdx = BC_NUM_NEG_VAL(BCL_NUM_NUM_NP(n), neg);
1351 #else // BC_ENABLE_MEMCHECK
1352 n.rdx = BC_NUM_NEG_VAL_NP(n, neg);
1353 #endif // BC_ENABLE_MEMCHECK
1357 BC_FUNC_FOOTER(vm, e);
1358 BC_MAYBE_SETUP(ctxt, e, n, idx);
1364 bcl_string_helper(BclNumber n, bool destruct)
1369 BcVm* vm = bcl_getspecific();
1371 BC_CHECK_CTXT_ASSERT(vm, ctxt);
1373 BCL_CHECK_NUM_VALID(ctxt, n);
1375 if (BC_ERR(BCL_NO_GEN(n) >= ctxt->nums.len)) return str;
1377 BC_FUNC_HEADER(vm, err);
1379 assert(BCL_NO_GEN(n) < ctxt->nums.len);
1381 nptr = BCL_NUM(ctxt, n);
1383 assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL);
1385 // Clear the buffer.
1386 bc_vec_popAll(&vm->out);
1388 // Print to the buffer.
1389 bc_num_print(BCL_NUM_NUM(nptr), (BcBigDig) ctxt->obase, false);
1390 bc_vec_pushByte(&vm->out, '\0');
1392 // Just dup the string; the caller is responsible for it.
1393 str = bc_vm_strdup(vm->out.v);
1400 bcl_num_dtor(ctxt, n, nptr);
1403 BC_FUNC_FOOTER_NO_ERR(vm);
1409 bcl_string(BclNumber n)
1411 return bcl_string_helper(n, true);
1415 bcl_string_keep(BclNumber n)
1417 return bcl_string_helper(n, false);
1420 #if BC_ENABLE_EXTRA_MATH
1423 bcl_irand_helper(BclNumber a, bool destruct)
1425 BclError e = BCL_ERROR_NONE;
1430 BcVm* vm = bcl_getspecific();
1432 BC_CHECK_CTXT(vm, ctxt);
1434 BC_CHECK_NUM(ctxt, a);
1436 BC_FUNC_HEADER(vm, err);
1438 BCL_GROW_NUMS(ctxt);
1440 assert(BCL_NO_GEN(a) < ctxt->nums.len);
1442 aptr = BCL_NUM(ctxt, a);
1444 assert(aptr != NULL && BCL_NUM_NUM(aptr) != NULL);
1446 // Clear and initialize the result.
1447 bc_num_clear(BCL_NUM_NUM_NP(b));
1448 bc_num_init(BCL_NUM_NUM_NP(b), BC_NUM_DEF_SIZE);
1450 bc_num_irand(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), &vm->rng);
1457 bcl_num_dtor(ctxt, a, aptr);
1460 BC_FUNC_FOOTER(vm, e);
1461 BC_MAYBE_SETUP(ctxt, e, b, idx);
1467 bcl_irand(BclNumber a)
1469 return bcl_irand_helper(a, true);
1473 bcl_irand_keep(BclNumber a)
1475 return bcl_irand_helper(a, false);
1479 * Helps bcl_frand(). This is separate because the error handling is easier that
1480 * way. It is also easier to do ifrand that way.
1481 * @param b The return parameter.
1482 * @param places The number of decimal places to generate.
1485 bcl_frandHelper(BcNum* restrict b, size_t places)
1487 BcNum exp, pow, ten;
1488 BcDig exp_digs[BC_NUM_BIGDIG_LOG10];
1489 BcDig ten_digs[BC_NUM_BIGDIG_LOG10];
1490 BcVm* vm = bcl_getspecific();
1492 // Set up temporaries.
1493 bc_num_setup(&exp, exp_digs, BC_NUM_BIGDIG_LOG10);
1494 bc_num_setup(&ten, ten_digs, BC_NUM_BIGDIG_LOG10);
1499 bc_num_bigdig2num(&exp, (BcBigDig) places);
1501 // Clear the temporary that might need to grow.
1504 // Initialize the temporary that might need to grow.
1505 bc_num_init(&pow, bc_num_powReq(&ten, &exp, 0));
1509 // Generate the number.
1510 bc_num_pow(&ten, &exp, &pow, 0);
1511 bc_num_irand(&pow, b, &vm->rng);
1513 // Make the number entirely fraction.
1514 bc_num_shiftRight(b, places);
1519 BC_LONGJMP_CONT(vm);
1523 bcl_frand(size_t places)
1525 BclError e = BCL_ERROR_NONE;
1529 BcVm* vm = bcl_getspecific();
1531 BC_CHECK_CTXT(vm, ctxt);
1533 BC_FUNC_HEADER(vm, err);
1535 BCL_GROW_NUMS(ctxt);
1537 // Clear and initialize the number.
1538 bc_num_clear(BCL_NUM_NUM_NP(n));
1539 bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE);
1541 bcl_frandHelper(BCL_NUM_NUM_NP(n), places);
1545 BC_FUNC_FOOTER(vm, e);
1546 BC_MAYBE_SETUP(ctxt, e, n, idx);
1552 * Helps bc_ifrand(). This is separate because error handling is easier that
1554 * @param a The limit for bc_num_irand().
1555 * @param b The return parameter.
1556 * @param places The number of decimal places to generate.
1559 bcl_ifrandHelper(BcNum* restrict a, BcNum* restrict b, size_t places)
1562 BcVm* vm = bcl_getspecific();
1564 // Clear the integer and fractional numbers.
1568 // Initialize the integer and fractional numbers.
1569 bc_num_init(&ir, BC_NUM_DEF_SIZE);
1570 bc_num_init(&fr, BC_NUM_DEF_SIZE);
1574 bc_num_irand(a, &ir, &vm->rng);
1575 bcl_frandHelper(&fr, places);
1577 bc_num_add(&ir, &fr, b, 0);
1583 BC_LONGJMP_CONT(vm);
1587 bcl_ifrand_helper(BclNumber a, size_t places, bool destruct)
1589 BclError e = BCL_ERROR_NONE;
1594 BcVm* vm = bcl_getspecific();
1596 BC_CHECK_CTXT(vm, ctxt);
1597 BC_CHECK_NUM(ctxt, a);
1599 BC_FUNC_HEADER(vm, err);
1601 BCL_GROW_NUMS(ctxt);
1603 assert(BCL_NO_GEN(a) < ctxt->nums.len);
1605 aptr = BCL_NUM(ctxt, a);
1607 assert(aptr != NULL && BCL_NUM_NUM(aptr) != NULL);
1609 // Clear and initialize the number.
1610 bc_num_clear(BCL_NUM_NUM_NP(b));
1611 bc_num_init(BCL_NUM_NUM_NP(b), BC_NUM_DEF_SIZE);
1613 bcl_ifrandHelper(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), places);
1620 bcl_num_dtor(ctxt, a, aptr);
1623 BC_FUNC_FOOTER(vm, e);
1624 BC_MAYBE_SETUP(ctxt, e, b, idx);
1630 bcl_ifrand(BclNumber a, size_t places)
1632 return bcl_ifrand_helper(a, places, true);
1636 bcl_ifrand_keep(BclNumber a, size_t places)
1638 return bcl_ifrand_helper(a, places, false);
1642 bcl_rand_seedWithNum_helper(BclNumber n, bool destruct)
1644 BclError e = BCL_ERROR_NONE;
1647 BcVm* vm = bcl_getspecific();
1649 BC_CHECK_CTXT_ERR(vm, ctxt);
1650 BC_CHECK_NUM_ERR(ctxt, n);
1652 BC_FUNC_HEADER(vm, err);
1654 assert(BCL_NO_GEN(n) < ctxt->nums.len);
1656 nptr = BCL_NUM(ctxt, n);
1658 assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL);
1660 bc_num_rng(BCL_NUM_NUM(nptr), &vm->rng);
1667 bcl_num_dtor(ctxt, n, nptr);
1670 BC_FUNC_FOOTER(vm, e);
1676 bcl_rand_seedWithNum(BclNumber n)
1678 return bcl_rand_seedWithNum_helper(n, true);
1682 bcl_rand_seedWithNum_keep(BclNumber n)
1684 return bcl_rand_seedWithNum_helper(n, false);
1688 bcl_rand_seed(unsigned char seed[BCL_SEED_SIZE])
1690 BclError e = BCL_ERROR_NONE;
1692 ulong vals[BCL_SEED_ULONGS];
1693 BcVm* vm = bcl_getspecific();
1695 BC_FUNC_HEADER(vm, err);
1698 for (i = 0; i < BCL_SEED_SIZE; ++i)
1700 ulong val = ((ulong) seed[i])
1701 << (((ulong) CHAR_BIT) * (i % sizeof(ulong)));
1702 vals[i / sizeof(long)] |= val;
1705 bc_rand_seed(&vm->rng, vals[0], vals[1], vals[2], vals[3]);
1709 BC_FUNC_FOOTER(vm, e);
1715 bcl_rand_reseed(void)
1717 BcVm* vm = bcl_getspecific();
1719 bc_rand_srand(bc_vec_top(&vm->rng.v));
1723 bcl_rand_seed2num(void)
1725 BclError e = BCL_ERROR_NONE;
1729 BcVm* vm = bcl_getspecific();
1731 BC_CHECK_CTXT(vm, ctxt);
1733 BC_FUNC_HEADER(vm, err);
1735 // Clear and initialize the number.
1736 bc_num_clear(BCL_NUM_NUM_NP(n));
1737 bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE);
1739 bc_num_createFromRNG(BCL_NUM_NUM_NP(n), &vm->rng);
1743 BC_FUNC_FOOTER(vm, e);
1744 BC_MAYBE_SETUP(ctxt, e, n, idx);
1752 BcVm* vm = bcl_getspecific();
1754 return (BclRandInt) bc_rand_int(&vm->rng);
1758 bcl_rand_bounded(BclRandInt bound)
1760 BcVm* vm = bcl_getspecific();
1762 if (bound <= 1) return 0;
1763 return (BclRandInt) bc_rand_bounded(&vm->rng, (BcRand) bound);
1766 #endif // BC_ENABLE_EXTRA_MATH
1768 #endif // BC_ENABLE_LIBRARY