2 * *****************************************************************************
4 * SPDX-License-Identifier: BSD-2-Clause
6 * Copyright (c) 2018-2021 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.
48 // The asserts in this file are important to testing; in many cases, the test
49 // would not work without the asserts, so don't remove them without reason.
51 // Also, there are many uses of bc_num_clear() here; that is because numbers are
52 // being reused, and a clean slate is required.
54 // Also, there are a bunch of BC_UNSETJMP and BC_SETJMP_LOCKED() between calls
55 // to bc_num_init(). That is because locals are being initialized, and unlike bc
56 // proper, this code cannot assume that allocation failures are fatal. So we
57 // have to reset the jumps every time to ensure that the locals will be correct
60 void bcl_handleSignal(void) {
62 // Signal already in flight, or bc is not executing.
63 if (vm.sig || !vm.running) return;
67 assert(vm.jmp_bufs.len);
69 if (!vm.sig_lock) BC_JMP;
72 bool bcl_running(void) {
73 return vm.running != 0;
76 BclError bcl_init(void) {
78 BclError e = BCL_ERROR_NONE;
82 if (vm.refs > 1) return e;
84 // Setting these to NULL ensures that if an error occurs, we only free what
94 // The jmp_bufs always has to be initialized first.
95 bc_vec_init(&vm.jmp_bufs, sizeof(sigjmp_buf), BC_DTOR_NONE);
97 BC_FUNC_HEADER_INIT(err);
101 bc_vec_init(&vm.ctxts, sizeof(BclContext), BC_DTOR_NONE);
102 bc_vec_init(&vm.out, sizeof(uchar), BC_DTOR_NONE);
104 // We need to seed this in case /dev/random and /dev/urandm don't work.
105 srand((unsigned int) time(NULL));
106 bc_rand_init(&vm.rng);
109 // This is why we had to set them to NULL.
110 if (BC_ERR(vm.err)) {
111 if (vm.out.v != NULL) bc_vec_free(&vm.out);
112 if (vm.jmp_bufs.v != NULL) bc_vec_free(&vm.jmp_bufs);
113 if (vm.ctxts.v != NULL) bc_vec_free(&vm.ctxts);
116 BC_FUNC_FOOTER_UNLOCK(e);
118 assert(!vm.running && !vm.sig && !vm.sig_lock);
123 BclError bcl_pushContext(BclContext ctxt) {
125 BclError e = BCL_ERROR_NONE;
127 BC_FUNC_HEADER_LOCK(err);
129 bc_vec_push(&vm.ctxts, &ctxt);
132 BC_FUNC_FOOTER_UNLOCK(e);
136 void bcl_popContext(void) {
137 if (vm.ctxts.len) bc_vec_pop(&vm.ctxts);
140 BclContext bcl_context(void) {
141 if (!vm.ctxts.len) return NULL;
142 return *((BclContext*) bc_vec_top(&vm.ctxts));
145 void bcl_free(void) {
155 bc_rand_free(&vm.rng);
156 bc_vec_free(&vm.out);
158 for (i = 0; i < vm.ctxts.len; ++i) {
159 BclContext ctxt = *((BclContext*) bc_vec_item(&vm.ctxts, i));
163 bc_vec_free(&vm.ctxts);
169 memset(&vm, 0, sizeof(BcVm));
171 assert(!vm.running && !vm.sig && !vm.sig_lock);
180 bool bcl_abortOnFatalError(void) {
184 void bcl_setAbortOnFatalError(bool abrt) {
188 bool bcl_leadingZeroes(void) {
189 return vm.leading_zeroes;
192 void bcl_setLeadingZeroes(bool leadingZeroes) {
193 vm.leading_zeroes = leadingZeroes;
196 BclContext bcl_ctxt_create(void) {
198 BclContext ctxt = NULL;
200 BC_FUNC_HEADER_LOCK(err);
202 // We want the context to be free of any interference of other parties, so
203 // malloc() is appropriate here.
204 ctxt = bc_vm_malloc(sizeof(BclCtxt));
206 bc_vec_init(&ctxt->nums, sizeof(BcNum), BC_DTOR_BCL_NUM);
207 bc_vec_init(&ctxt->free_nums, sizeof(BclNumber), BC_DTOR_NONE);
214 if (BC_ERR(vm.err && ctxt != NULL)) {
215 if (ctxt->nums.v != NULL) bc_vec_free(&ctxt->nums);
220 BC_FUNC_FOOTER_NO_ERR;
222 assert(!vm.running && !vm.sig && !vm.sig_lock);
227 void bcl_ctxt_free(BclContext ctxt) {
229 bc_vec_free(&ctxt->free_nums);
230 bc_vec_free(&ctxt->nums);
235 void bcl_ctxt_freeNums(BclContext ctxt) {
236 bc_vec_popAll(&ctxt->nums);
237 bc_vec_popAll(&ctxt->free_nums);
240 size_t bcl_ctxt_scale(BclContext ctxt) {
244 void bcl_ctxt_setScale(BclContext ctxt, size_t scale) {
248 size_t bcl_ctxt_ibase(BclContext ctxt) {
252 void bcl_ctxt_setIbase(BclContext ctxt, size_t ibase) {
253 if (ibase < BC_NUM_MIN_BASE) ibase = BC_NUM_MIN_BASE;
254 else if (ibase > BC_NUM_MAX_IBASE) ibase = BC_NUM_MAX_IBASE;
258 size_t bcl_ctxt_obase(BclContext ctxt) {
262 void bcl_ctxt_setObase(BclContext ctxt, size_t obase) {
266 BclError bcl_err(BclNumber n) {
270 BC_CHECK_CTXT_ERR(ctxt);
272 // Errors are encoded as (0 - error_code). If the index is in that range, it
273 // is an encoded error.
274 if (n.i >= ctxt->nums.len) {
275 if (n.i > 0 - (size_t) BCL_ERROR_NELEMS) return (BclError) (0 - n.i);
276 else return BCL_ERROR_INVALID_NUM;
278 else return BCL_ERROR_NONE;
282 * Inserts a BcNum into a context's list of numbers.
283 * @param ctxt The context to insert into.
284 * @param n The BcNum to insert.
285 * @return The resulting BclNumber from the insert.
287 static BclNumber bcl_num_insert(BclContext ctxt, BcNum *restrict n) {
291 // If there is a free spot...
292 if (ctxt->free_nums.len) {
296 // Get the index of the free spot and remove it.
297 idx = *((BclNumber*) bc_vec_top(&ctxt->free_nums));
298 bc_vec_pop(&ctxt->free_nums);
300 // Copy the number into the spot.
301 ptr = bc_vec_item(&ctxt->nums, idx.i);
302 memcpy(ptr, n, sizeof(BcNum));
305 // Just push the number onto the vector.
306 idx.i = ctxt->nums.len;
307 bc_vec_push(&ctxt->nums, n);
310 assert(!vm.running && !vm.sig && !vm.sig_lock);
315 BclNumber bcl_num_create(void) {
317 BclError e = BCL_ERROR_NONE;
324 BC_FUNC_HEADER_LOCK(err);
326 bc_vec_grow(&ctxt->nums, 1);
328 bc_num_init(&n, BC_NUM_DEF_SIZE);
331 BC_FUNC_FOOTER_UNLOCK(e);
332 BC_MAYBE_SETUP(ctxt, e, n, idx);
334 assert(!vm.running && !vm.sig && !vm.sig_lock);
340 * Destructs a number and marks its spot as free.
341 * @param ctxt The context.
342 * @param n The index of the number.
343 * @param num The number to destroy.
345 static void bcl_num_dtor(BclContext ctxt, BclNumber n, BcNum *restrict num) {
347 BC_SIG_ASSERT_LOCKED;
349 assert(num != NULL && num->num != NULL);
351 bcl_num_destruct(num);
352 bc_vec_push(&ctxt->free_nums, &n);
355 void bcl_num_free(BclNumber n) {
360 BC_CHECK_CTXT_ASSERT(ctxt);
364 assert(n.i < ctxt->nums.len);
366 num = BC_NUM(ctxt, n);
368 bcl_num_dtor(ctxt, n, num);
373 BclError bcl_copy(BclNumber d, BclNumber s) {
375 BclError e = BCL_ERROR_NONE;
379 BC_CHECK_CTXT_ERR(ctxt);
381 BC_FUNC_HEADER_LOCK(err);
383 assert(d.i < ctxt->nums.len && s.i < ctxt->nums.len);
385 dest = BC_NUM(ctxt, d);
386 src = BC_NUM(ctxt, s);
388 assert(dest != NULL && src != NULL);
389 assert(dest->num != NULL && src->num != NULL);
391 bc_num_copy(dest, src);
394 BC_FUNC_FOOTER_UNLOCK(e);
396 assert(!vm.running && !vm.sig && !vm.sig_lock);
401 BclNumber bcl_dup(BclNumber s) {
403 BclError e = BCL_ERROR_NONE;
410 BC_FUNC_HEADER_LOCK(err);
412 bc_vec_grow(&ctxt->nums, 1);
414 assert(s.i < ctxt->nums.len);
416 src = BC_NUM(ctxt, s);
418 assert(src != NULL && src->num != NULL);
422 bc_num_createCopy(&dest, src);
425 BC_FUNC_FOOTER_UNLOCK(e);
426 BC_MAYBE_SETUP(ctxt, e, dest, idx);
428 assert(!vm.running && !vm.sig && !vm.sig_lock);
433 void bcl_num_destruct(void *num) {
435 BcNum *n = (BcNum*) num;
439 if (n->num == NULL) return;
445 bool bcl_num_neg(BclNumber n) {
450 BC_CHECK_CTXT_ASSERT(ctxt);
452 assert(n.i < ctxt->nums.len);
454 num = BC_NUM(ctxt, n);
456 assert(num != NULL && num->num != NULL);
458 return BC_NUM_NEG(num) != 0;
461 void bcl_num_setNeg(BclNumber n, bool neg) {
466 BC_CHECK_CTXT_ASSERT(ctxt);
468 assert(n.i < ctxt->nums.len);
470 num = BC_NUM(ctxt, n);
472 assert(num != NULL && num->num != NULL);
474 num->rdx = BC_NUM_NEG_VAL(num, neg);
477 size_t bcl_num_scale(BclNumber n) {
482 BC_CHECK_CTXT_ASSERT(ctxt);
484 assert(n.i < ctxt->nums.len);
486 num = BC_NUM(ctxt, n);
488 assert(num != NULL && num->num != NULL);
490 return bc_num_scale(num);
493 BclError bcl_num_setScale(BclNumber n, size_t scale) {
495 BclError e = BCL_ERROR_NONE;
499 BC_CHECK_CTXT_ERR(ctxt);
501 BC_CHECK_NUM_ERR(ctxt, n);
505 assert(n.i < ctxt->nums.len);
507 nptr = BC_NUM(ctxt, n);
509 assert(nptr != NULL && nptr->num != NULL);
511 if (scale > nptr->scale) bc_num_extend(nptr, scale - nptr->scale);
512 else if (scale < nptr->scale) bc_num_truncate(nptr, nptr->scale - scale);
518 assert(!vm.running && !vm.sig && !vm.sig_lock);
523 size_t bcl_num_len(BclNumber n) {
528 BC_CHECK_CTXT_ASSERT(ctxt);
530 assert(n.i < ctxt->nums.len);
532 num = BC_NUM(ctxt, n);
534 assert(num != NULL && num->num != NULL);
536 return bc_num_len(num);
539 BclError bcl_bigdig(BclNumber n, BclBigDig *result) {
541 BclError e = BCL_ERROR_NONE;
545 BC_CHECK_CTXT_ERR(ctxt);
547 BC_FUNC_HEADER_LOCK(err);
549 assert(n.i < ctxt->nums.len);
550 assert(result != NULL);
552 num = BC_NUM(ctxt, n);
554 assert(num != NULL && num->num != NULL);
556 *result = bc_num_bigdig(num);
559 bcl_num_dtor(ctxt, n, num);
560 BC_FUNC_FOOTER_UNLOCK(e);
562 assert(!vm.running && !vm.sig && !vm.sig_lock);
567 BclNumber bcl_bigdig2num(BclBigDig val) {
569 BclError e = BCL_ERROR_NONE;
576 BC_FUNC_HEADER_LOCK(err);
578 bc_vec_grow(&ctxt->nums, 1);
580 bc_num_createFromBigdig(&n, val);
583 BC_FUNC_FOOTER_UNLOCK(e);
584 BC_MAYBE_SETUP(ctxt, e, n, idx);
586 assert(!vm.running && !vm.sig && !vm.sig_lock);
592 * Sets up and executes a binary operator operation.
593 * @param a The first operand.
594 * @param b The second operand.
595 * @param op The operation.
596 * @param req The function to get the size of the result for preallocation.
597 * @return The result of the operation.
599 static BclNumber bcl_binary(BclNumber a, BclNumber b, const BcNumBinaryOp op,
600 const BcNumBinaryOpReq req)
602 BclError e = BCL_ERROR_NONE;
610 BC_CHECK_NUM(ctxt, a);
611 BC_CHECK_NUM(ctxt, b);
613 BC_FUNC_HEADER_LOCK(err);
615 bc_vec_grow(&ctxt->nums, 1);
617 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
619 aptr = BC_NUM(ctxt, a);
620 bptr = BC_NUM(ctxt, b);
622 assert(aptr != NULL && bptr != NULL);
623 assert(aptr->num != NULL && bptr->num != NULL);
625 // Clear and initialize the result.
627 bc_num_init(&c, req(aptr, bptr, ctxt->scale));
631 op(aptr, bptr, &c, ctxt->scale);
638 bcl_num_dtor(ctxt, a, aptr);
639 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
642 BC_MAYBE_SETUP(ctxt, e, c, idx);
644 assert(!vm.running && !vm.sig && !vm.sig_lock);
649 BclNumber bcl_add(BclNumber a, BclNumber b) {
650 return bcl_binary(a, b, bc_num_add, bc_num_addReq);
653 BclNumber bcl_sub(BclNumber a, BclNumber b) {
654 return bcl_binary(a, b, bc_num_sub, bc_num_addReq);
657 BclNumber bcl_mul(BclNumber a, BclNumber b) {
658 return bcl_binary(a, b, bc_num_mul, bc_num_mulReq);
661 BclNumber bcl_div(BclNumber a, BclNumber b) {
662 return bcl_binary(a, b, bc_num_div, bc_num_divReq);
665 BclNumber bcl_mod(BclNumber a, BclNumber b) {
666 return bcl_binary(a, b, bc_num_mod, bc_num_divReq);
669 BclNumber bcl_pow(BclNumber a, BclNumber b) {
670 return bcl_binary(a, b, bc_num_pow, bc_num_powReq);
673 BclNumber bcl_lshift(BclNumber a, BclNumber b) {
674 return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq);
677 BclNumber bcl_rshift(BclNumber a, BclNumber b) {
678 return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq);
681 BclNumber bcl_sqrt(BclNumber a) {
683 BclError e = BCL_ERROR_NONE;
691 BC_CHECK_NUM(ctxt, a);
695 bc_vec_grow(&ctxt->nums, 1);
697 assert(a.i < ctxt->nums.len);
699 aptr = BC_NUM(ctxt, a);
701 bc_num_sqrt(aptr, &b, ctxt->scale);
705 bcl_num_dtor(ctxt, a, aptr);
707 BC_MAYBE_SETUP(ctxt, e, b, idx);
709 assert(!vm.running && !vm.sig && !vm.sig_lock);
714 BclError bcl_divmod(BclNumber a, BclNumber b, BclNumber *c, BclNumber *d) {
716 BclError e = BCL_ERROR_NONE;
722 BC_CHECK_CTXT_ERR(ctxt);
724 BC_CHECK_NUM_ERR(ctxt, a);
725 BC_CHECK_NUM_ERR(ctxt, b);
727 BC_FUNC_HEADER_LOCK(err);
729 bc_vec_grow(&ctxt->nums, 2);
731 assert(c != NULL && d != NULL);
733 aptr = BC_NUM(ctxt, a);
734 bptr = BC_NUM(ctxt, b);
736 assert(aptr != NULL && bptr != NULL);
737 assert(aptr->num != NULL && bptr->num != NULL);
742 req = bc_num_divReq(aptr, bptr, ctxt->scale);
744 // Initialize the numbers.
745 bc_num_init(&cnum, req);
747 BC_SETJMP_LOCKED(err);
748 bc_num_init(&dnum, req);
752 bc_num_divmod(aptr, bptr, &cnum, &dnum, ctxt->scale);
758 bcl_num_dtor(ctxt, a, aptr);
759 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
761 // If there was an error...
762 if (BC_ERR(vm.err)) {
765 if (cnum.num != NULL) bc_num_free(&cnum);
766 if (dnum.num != NULL) bc_num_free(&dnum);
768 // Make sure the return values are invalid.
769 c->i = 0 - (size_t) BCL_ERROR_INVALID_NUM;
778 // Insert the results into the context.
779 *c = bcl_num_insert(ctxt, &cnum);
780 *d = bcl_num_insert(ctxt, &dnum);
783 assert(!vm.running && !vm.sig && !vm.sig_lock);
788 BclNumber bcl_modexp(BclNumber a, BclNumber b, BclNumber c) {
790 BclError e = BCL_ERROR_NONE;
792 BcNum *aptr, *bptr, *cptr;
799 BC_CHECK_NUM(ctxt, a);
800 BC_CHECK_NUM(ctxt, b);
801 BC_CHECK_NUM(ctxt, c);
803 BC_FUNC_HEADER_LOCK(err);
805 bc_vec_grow(&ctxt->nums, 1);
807 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
808 assert(c.i < ctxt->nums.len);
810 aptr = BC_NUM(ctxt, a);
811 bptr = BC_NUM(ctxt, b);
812 cptr = BC_NUM(ctxt, c);
814 assert(aptr != NULL && bptr != NULL && cptr != NULL);
815 assert(aptr->num != NULL && bptr->num != NULL && cptr->num != NULL);
817 // Prepare the result.
820 req = bc_num_divReq(aptr, cptr, 0);
822 // Initialize the result.
823 bc_num_init(&d, req);
827 bc_num_modexp(aptr, bptr, cptr, &d);
833 bcl_num_dtor(ctxt, a, aptr);
834 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
835 if (c.i != a.i && c.i != b.i) bcl_num_dtor(ctxt, c, cptr);
838 BC_MAYBE_SETUP(ctxt, e, d, idx);
840 assert(!vm.running && !vm.sig && !vm.sig_lock);
845 ssize_t bcl_cmp(BclNumber a, BclNumber b) {
850 BC_CHECK_CTXT_ASSERT(ctxt);
852 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
854 aptr = BC_NUM(ctxt, a);
855 bptr = BC_NUM(ctxt, b);
857 assert(aptr != NULL && bptr != NULL);
858 assert(aptr->num != NULL && bptr->num != NULL);
860 return bc_num_cmp(aptr, bptr);
863 void bcl_zero(BclNumber n) {
868 BC_CHECK_CTXT_ASSERT(ctxt);
870 assert(n.i < ctxt->nums.len);
872 nptr = BC_NUM(ctxt, n);
874 assert(nptr != NULL && nptr->num != NULL);
879 void bcl_one(BclNumber n) {
884 BC_CHECK_CTXT_ASSERT(ctxt);
886 assert(n.i < ctxt->nums.len);
888 nptr = BC_NUM(ctxt, n);
890 assert(nptr != NULL && nptr->num != NULL);
895 BclNumber bcl_parse(const char *restrict val) {
897 BclError e = BCL_ERROR_NONE;
905 BC_FUNC_HEADER_LOCK(err);
907 bc_vec_grow(&ctxt->nums, 1);
911 // We have to take care of negative here because bc's number parsing does
913 neg = (val[0] == '-');
917 if (!bc_num_strValid(val)) {
918 vm.err = BCL_ERROR_PARSE_INVALID_STR;
922 // Clear and initialize the number.
924 bc_num_init(&n, BC_NUM_DEF_SIZE);
928 bc_num_parse(&n, val, (BcBigDig) ctxt->ibase);
931 n.rdx = BC_NUM_NEG_VAL_NP(n, neg);
936 BC_MAYBE_SETUP(ctxt, e, n, idx);
938 assert(!vm.running && !vm.sig && !vm.sig_lock);
943 char* bcl_string(BclNumber n) {
949 BC_CHECK_CTXT_ASSERT(ctxt);
951 if (BC_ERR(n.i >= ctxt->nums.len)) return str;
955 assert(n.i < ctxt->nums.len);
957 nptr = BC_NUM(ctxt, n);
959 assert(nptr != NULL && nptr->num != NULL);
962 bc_vec_popAll(&vm.out);
964 // Print to the buffer.
965 bc_num_print(nptr, (BcBigDig) ctxt->obase, false);
966 bc_vec_pushByte(&vm.out, '\0');
970 // Just dup the string; the caller is responsible for it.
971 str = bc_vm_strdup(vm.out.v);
976 bcl_num_dtor(ctxt, n, nptr);
978 BC_FUNC_FOOTER_NO_ERR;
980 assert(!vm.running && !vm.sig && !vm.sig_lock);
985 BclNumber bcl_irand(BclNumber a) {
987 BclError e = BCL_ERROR_NONE;
995 BC_CHECK_NUM(ctxt, a);
997 BC_FUNC_HEADER_LOCK(err);
999 bc_vec_grow(&ctxt->nums, 1);
1001 assert(a.i < ctxt->nums.len);
1003 aptr = BC_NUM(ctxt, a);
1005 assert(aptr != NULL && aptr->num != NULL);
1007 // Clear and initialize the result.
1009 bc_num_init(&b, BC_NUM_DEF_SIZE);
1013 bc_num_irand(aptr, &b, &vm.rng);
1019 bcl_num_dtor(ctxt, a, aptr);
1022 BC_MAYBE_SETUP(ctxt, e, b, idx);
1024 assert(!vm.running && !vm.sig && !vm.sig_lock);
1030 * Helps bcl_frand(). This is separate because the error handling is easier that
1031 * way. It is also easier to do ifrand that way.
1032 * @param b The return parameter.
1033 * @param places The number of decimal places to generate.
1035 static void bcl_frandHelper(BcNum *restrict b, size_t places) {
1037 BcNum exp, pow, ten;
1038 BcDig exp_digs[BC_NUM_BIGDIG_LOG10];
1039 BcDig ten_digs[BC_NUM_BIGDIG_LOG10];
1041 // Set up temporaries.
1042 bc_num_setup(&exp, exp_digs, BC_NUM_BIGDIG_LOG10);
1043 bc_num_setup(&ten, ten_digs, BC_NUM_BIGDIG_LOG10);
1048 bc_num_bigdig2num(&exp, (BcBigDig) places);
1050 // Clear the temporary that might need to grow.
1055 // Initialize the temporary that might need to grow.
1056 bc_num_init(&pow, bc_num_powReq(&ten, &exp, 0));
1058 BC_SETJMP_LOCKED(err);
1062 // Generate the number.
1063 bc_num_pow(&ten, &exp, &pow, 0);
1064 bc_num_irand(&pow, b, &vm.rng);
1066 // Make the number entirely fraction.
1067 bc_num_shiftRight(b, places);
1075 BclNumber bcl_frand(size_t places) {
1077 BclError e = BCL_ERROR_NONE;
1082 BC_CHECK_CTXT(ctxt);
1084 BC_FUNC_HEADER_LOCK(err);
1086 bc_vec_grow(&ctxt->nums, 1);
1088 // Clear and initialize the number.
1090 bc_num_init(&n, BC_NUM_DEF_SIZE);
1094 bcl_frandHelper(&n, places);
1100 BC_MAYBE_SETUP(ctxt, e, n, idx);
1102 assert(!vm.running && !vm.sig && !vm.sig_lock);
1108 * Helps bc_ifrand(). This is separate because error handling is easier that
1110 * @param a The limit for bc_num_irand().
1111 * @param b The return parameter.
1112 * @param places The number of decimal places to generate.
1114 static void bcl_ifrandHelper(BcNum *restrict a, BcNum *restrict b,
1119 // Clear the integer and fractional numbers.
1125 // Initialize the integer and fractional numbers.
1126 bc_num_init(&ir, BC_NUM_DEF_SIZE);
1127 bc_num_init(&fr, BC_NUM_DEF_SIZE);
1129 BC_SETJMP_LOCKED(err);
1133 bc_num_irand(a, &ir, &vm.rng);
1134 bcl_frandHelper(&fr, places);
1136 bc_num_add(&ir, &fr, b, 0);
1145 BclNumber bcl_ifrand(BclNumber a, size_t places) {
1147 BclError e = BCL_ERROR_NONE;
1153 BC_CHECK_CTXT(ctxt);
1154 BC_CHECK_NUM(ctxt, a);
1156 BC_FUNC_HEADER_LOCK(err);
1158 bc_vec_grow(&ctxt->nums, 1);
1160 assert(a.i < ctxt->nums.len);
1162 aptr = BC_NUM(ctxt, a);
1164 assert(aptr != NULL && aptr->num != NULL);
1166 // Clear and initialize the number.
1168 bc_num_init(&b, BC_NUM_DEF_SIZE);
1172 bcl_ifrandHelper(aptr, &b, places);
1178 bcl_num_dtor(ctxt, a, aptr);
1181 BC_MAYBE_SETUP(ctxt, e, b, idx);
1183 assert(!vm.running && !vm.sig && !vm.sig_lock);
1188 BclError bcl_rand_seedWithNum(BclNumber n) {
1190 BclError e = BCL_ERROR_NONE;
1194 BC_CHECK_CTXT_ERR(ctxt);
1195 BC_CHECK_NUM_ERR(ctxt, n);
1197 BC_FUNC_HEADER(err);
1199 assert(n.i < ctxt->nums.len);
1201 nptr = BC_NUM(ctxt, n);
1203 assert(nptr != NULL && nptr->num != NULL);
1205 bc_num_rng(nptr, &vm.rng);
1211 assert(!vm.running && !vm.sig && !vm.sig_lock);
1216 BclError bcl_rand_seed(unsigned char seed[BCL_SEED_SIZE]) {
1218 BclError e = BCL_ERROR_NONE;
1220 ulong vals[BCL_SEED_ULONGS];
1222 BC_FUNC_HEADER(err);
1225 for (i = 0; i < BCL_SEED_SIZE; ++i) {
1226 ulong val = ((ulong) seed[i]) << (((ulong) CHAR_BIT) *
1227 (i % sizeof(ulong)));
1228 vals[i / sizeof(long)] |= val;
1231 bc_rand_seed(&vm.rng, vals[0], vals[1], vals[2], vals[3]);
1239 void bcl_rand_reseed(void) {
1240 bc_rand_srand(bc_vec_top(&vm.rng.v));
1243 BclNumber bcl_rand_seed2num(void) {
1245 BclError e = BCL_ERROR_NONE;
1250 BC_CHECK_CTXT(ctxt);
1252 BC_FUNC_HEADER_LOCK(err);
1254 // Clear and initialize the number.
1256 bc_num_init(&n, BC_NUM_DEF_SIZE);
1260 bc_num_createFromRNG(&n, &vm.rng);
1265 BC_MAYBE_SETUP(ctxt, e, n, idx);
1267 assert(!vm.running && !vm.sig && !vm.sig_lock);
1272 BclRandInt bcl_rand_int(void) {
1273 return (BclRandInt) bc_rand_int(&vm.rng);
1276 BclRandInt bcl_rand_bounded(BclRandInt bound) {
1277 if (bound <= 1) return 0;
1278 return (BclRandInt) bc_rand_bounded(&vm.rng, (BcRand) bound);
1281 #endif // BC_ENABLE_LIBRARY