1/*
2 * *****************************************************************************
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 *
6 * Copyright (c) 2018-2023 Gavin D. Howard and contributors.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright notice, this
12 *   list of conditions and the following disclaimer.
13 *
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.
17 *
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.
29 *
30 * *****************************************************************************
31 *
32 * The public functions for libbc.
33 *
34 */
35
36#if BC_ENABLE_LIBRARY
37
38#include <setjmp.h>
39#include <string.h>
40#include <time.h>
41
42#include <bcl.h>
43
44#include <library.h>
45#include <num.h>
46#include <vm.h>
47
48#ifndef _WIN32
49#include <pthread.h>
50#endif // _WIN32
51
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.
54//
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.
57//
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.
62
63#if BC_ENABLE_MEMCHECK
64
65BC_NORETURN void
66bcl_invalidGeneration(void)
67{
68	abort();
69}
70
71BC_NORETURN void
72bcl_nonexistentNum(void)
73{
74	abort();
75}
76
77BC_NORETURN void
78bcl_numIdxOutOfRange(void)
79{
80	abort();
81}
82
83#endif // BC_ENABLE_MEMCHECK
84
85static BclTls* tls = NULL;
86static BclTls tls_real;
87
88BclError
89bcl_start(void)
90{
91#ifndef _WIN32
92
93	int r;
94
95	if (tls != NULL) return BCL_ERROR_NONE;
96
97	r = pthread_key_create(&tls_real, NULL);
98	if (BC_ERR(r != 0)) return BCL_ERROR_FATAL_ALLOC_ERR;
99
100#else // _WIN32
101
102	if (tls != NULL) return BCL_ERROR_NONE;
103
104	tls_real = TlsAlloc();
105	if (BC_ERR(tls_real == TLS_OUT_OF_INDEXES))
106	{
107		return BCL_ERROR_FATAL_ALLOC_ERR;
108	}
109
110#endif // _WIN32
111
112	tls = &tls_real;
113
114	return BCL_ERROR_NONE;
115}
116
117/**
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.
121 */
122static BclError
123bcl_setspecific(BcVm* vm)
124{
125#ifndef _WIN32
126
127	int r;
128
129	assert(tls != NULL);
130
131	r = pthread_setspecific(tls_real, vm);
132	if (BC_ERR(r != 0)) return BCL_ERROR_FATAL_ALLOC_ERR;
133
134#else // _WIN32
135
136	bool r;
137
138	assert(tls != NULL);
139
140	r = TlsSetValue(tls_real, vm);
141	if (BC_ERR(!r)) return BCL_ERROR_FATAL_ALLOC_ERR;
142
143#endif // _WIN32
144
145	return BCL_ERROR_NONE;
146}
147
148BcVm*
149bcl_getspecific(void)
150{
151	BcVm* vm;
152
153#ifndef _WIN32
154
155	vm = pthread_getspecific(tls_real);
156
157#else // _WIN32
158
159	vm = TlsGetValue(tls_real);
160
161#endif // _WIN32
162
163	return vm;
164}
165
166BclError
167bcl_init(void)
168{
169	BclError e = BCL_ERROR_NONE;
170	BcVm* vm;
171
172	assert(tls != NULL);
173
174	vm = bcl_getspecific();
175	if (vm != NULL)
176	{
177		assert(vm->refs >= 1);
178
179		vm->refs += 1;
180
181		return e;
182	}
183
184	vm = bc_vm_malloc(sizeof(BcVm));
185	if (BC_ERR(vm == NULL)) return BCL_ERROR_FATAL_ALLOC_ERR;
186
187	e = bcl_setspecific(vm);
188	if (BC_ERR(e != BCL_ERROR_NONE))
189	{
190		free(vm);
191		return e;
192	}
193
194	memset(vm, 0, sizeof(BcVm));
195
196	vm->refs += 1;
197
198	assert(vm->refs == 1);
199
200	// Setting these to NULL ensures that if an error occurs, we only free what
201	// is necessary.
202	vm->ctxts.v = NULL;
203	vm->jmp_bufs.v = NULL;
204	vm->out.v = NULL;
205
206	vm->abrt = false;
207	vm->leading_zeroes = false;
208	vm->digit_clamp = true;
209
210	// The jmp_bufs always has to be initialized first.
211	bc_vec_init(&vm->jmp_bufs, sizeof(sigjmp_buf), BC_DTOR_NONE);
212
213	BC_FUNC_HEADER(vm, err);
214
215	bc_vm_init();
216
217	bc_vec_init(&vm->ctxts, sizeof(BclContext), BC_DTOR_NONE);
218	bc_vec_init(&vm->out, sizeof(uchar), BC_DTOR_NONE);
219
220#if BC_ENABLE_EXTRA_MATH
221
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);
225
226#endif // BC_ENABLE_EXTRA_MATH
227
228err:
229
230	BC_FUNC_FOOTER(vm, e);
231
232	// This is why we had to set them to NULL.
233	if (BC_ERR(vm != NULL && vm->err))
234	{
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);
239		free(vm);
240	}
241
242	return e;
243}
244
245BclError
246bcl_pushContext(BclContext ctxt)
247{
248	BclError e = BCL_ERROR_NONE;
249	BcVm* vm = bcl_getspecific();
250
251	BC_FUNC_HEADER(vm, err);
252
253	bc_vec_push(&vm->ctxts, &ctxt);
254
255err:
256
257	BC_FUNC_FOOTER(vm, e);
258	return e;
259}
260
261void
262bcl_popContext(void)
263{
264	BcVm* vm = bcl_getspecific();
265
266	if (vm->ctxts.len) bc_vec_pop(&vm->ctxts);
267}
268
269static BclContext
270bcl_contextHelper(BcVm* vm)
271{
272	if (!vm->ctxts.len) return NULL;
273	return *((BclContext*) bc_vec_top(&vm->ctxts));
274}
275
276BclContext
277bcl_context(void)
278{
279	BcVm* vm = bcl_getspecific();
280	return bcl_contextHelper(vm);
281}
282
283void
284bcl_free(void)
285{
286	size_t i;
287	BcVm* vm = bcl_getspecific();
288
289	vm->refs -= 1;
290	if (vm->refs) return;
291
292#if BC_ENABLE_EXTRA_MATH
293	bc_rand_free(&vm->rng);
294#endif // BC_ENABLE_EXTRA_MATH
295	bc_vec_free(&vm->out);
296
297	for (i = 0; i < vm->ctxts.len; ++i)
298	{
299		BclContext ctxt = *((BclContext*) bc_vec_item(&vm->ctxts, i));
300		bcl_ctxt_free(ctxt);
301	}
302
303	bc_vec_free(&vm->ctxts);
304
305	bc_vm_atexit();
306
307	free(vm);
308	bcl_setspecific(NULL);
309}
310
311void
312bcl_end(void)
313{
314#ifndef _WIN32
315
316	// We ignore the return value.
317	pthread_key_delete(tls_real);
318
319#else // _WIN32
320
321	// We ignore the return value.
322	TlsFree(tls_real);
323
324#endif // _WIN32
325
326	tls = NULL;
327}
328
329void
330bcl_gc(void)
331{
332	bc_vm_freeTemps();
333}
334
335bool
336bcl_abortOnFatalError(void)
337{
338	BcVm* vm = bcl_getspecific();
339
340	return vm->abrt;
341}
342
343void
344bcl_setAbortOnFatalError(bool abrt)
345{
346	BcVm* vm = bcl_getspecific();
347
348	vm->abrt = abrt;
349}
350
351bool
352bcl_leadingZeroes(void)
353{
354	BcVm* vm = bcl_getspecific();
355
356	return vm->leading_zeroes;
357}
358
359void
360bcl_setLeadingZeroes(bool leadingZeroes)
361{
362	BcVm* vm = bcl_getspecific();
363
364	vm->leading_zeroes = leadingZeroes;
365}
366
367bool
368bcl_digitClamp(void)
369{
370	BcVm* vm = bcl_getspecific();
371
372	return vm->digit_clamp;
373}
374
375void
376bcl_setDigitClamp(bool digitClamp)
377{
378	BcVm* vm = bcl_getspecific();
379
380	vm->digit_clamp = digitClamp;
381}
382
383BclContext
384bcl_ctxt_create(void)
385{
386	BcVm* vm = bcl_getspecific();
387	BclContext ctxt = NULL;
388
389	BC_FUNC_HEADER(vm, err);
390
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));
394
395	bc_vec_init(&ctxt->nums, sizeof(BclNum), BC_DTOR_BCL_NUM);
396	bc_vec_init(&ctxt->free_nums, sizeof(BclNumber), BC_DTOR_NONE);
397
398	ctxt->scale = 0;
399	ctxt->ibase = 10;
400	ctxt->obase = 10;
401
402err:
403
404	if (BC_ERR(vm->err && ctxt != NULL))
405	{
406		if (ctxt->nums.v != NULL) bc_vec_free(&ctxt->nums);
407		free(ctxt);
408		ctxt = NULL;
409	}
410
411	BC_FUNC_FOOTER_NO_ERR(vm);
412
413	return ctxt;
414}
415
416void
417bcl_ctxt_free(BclContext ctxt)
418{
419	bc_vec_free(&ctxt->free_nums);
420	bc_vec_free(&ctxt->nums);
421	free(ctxt);
422}
423
424void
425bcl_ctxt_freeNums(BclContext ctxt)
426{
427	bc_vec_popAll(&ctxt->nums);
428	bc_vec_popAll(&ctxt->free_nums);
429}
430
431size_t
432bcl_ctxt_scale(BclContext ctxt)
433{
434	return ctxt->scale;
435}
436
437void
438bcl_ctxt_setScale(BclContext ctxt, size_t scale)
439{
440	ctxt->scale = scale;
441}
442
443size_t
444bcl_ctxt_ibase(BclContext ctxt)
445{
446	return ctxt->ibase;
447}
448
449void
450bcl_ctxt_setIbase(BclContext ctxt, size_t ibase)
451{
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;
454	ctxt->ibase = ibase;
455}
456
457size_t
458bcl_ctxt_obase(BclContext ctxt)
459{
460	return ctxt->obase;
461}
462
463void
464bcl_ctxt_setObase(BclContext ctxt, size_t obase)
465{
466	ctxt->obase = obase;
467}
468
469BclError
470bcl_err(BclNumber n)
471{
472	BclContext ctxt;
473	BcVm* vm = bcl_getspecific();
474
475	BC_CHECK_CTXT_ERR(vm, ctxt);
476
477	// We need to clear the top byte in memcheck mode. We can do this because
478	// the parameter is a copy.
479	BCL_CLEAR_GEN(n);
480
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)
484	{
485		if (n.i > 0 - (size_t) BCL_ERROR_NELEMS) return (BclError) (0 - n.i);
486		else return BCL_ERROR_INVALID_NUM;
487	}
488	else return BCL_ERROR_NONE;
489}
490
491/**
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.
496 */
497static BclNumber
498bcl_num_insert(BclContext ctxt, BclNum* restrict n)
499{
500	BclNumber idx;
501
502	// If there is a free spot...
503	if (ctxt->free_nums.len)
504	{
505		BclNum* ptr;
506
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);
510
511		// Copy the number into the spot.
512		ptr = bc_vec_item(&ctxt->nums, idx.i);
513
514		memcpy(BCL_NUM_NUM(ptr), n, sizeof(BcNum));
515
516#if BC_ENABLE_MEMCHECK
517
518		ptr->gen_idx += 1;
519
520		if (ptr->gen_idx == UCHAR_MAX)
521		{
522			ptr->gen_idx = 0;
523		}
524
525		idx.i |= (ptr->gen_idx << ((sizeof(size_t) - 1) * CHAR_BIT));
526
527#endif // BC_ENABLE_MEMCHECK
528	}
529	else
530	{
531#if BC_ENABLE_MEMCHECK
532		n->gen_idx = 0;
533#endif // BC_ENABLE_MEMCHECK
534
535		// Just push the number onto the vector because the generation index is
536		// 0.
537		idx.i = ctxt->nums.len;
538		bc_vec_push(&ctxt->nums, n);
539	}
540
541	return idx;
542}
543
544BclNumber
545bcl_num_create(void)
546{
547	BclError e = BCL_ERROR_NONE;
548	BclNum n;
549	BclNumber idx;
550	BclContext ctxt;
551	BcVm* vm = bcl_getspecific();
552
553	BC_CHECK_CTXT(vm, ctxt);
554
555	BC_FUNC_HEADER(vm, err);
556
557	BCL_GROW_NUMS(ctxt);
558
559	bc_num_init(BCL_NUM_NUM_NP(n), BC_NUM_DEF_SIZE);
560
561err:
562
563	BC_FUNC_FOOTER(vm, e);
564	BC_MAYBE_SETUP(ctxt, e, n, idx);
565
566	return idx;
567}
568
569/**
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.
574 */
575static void
576bcl_num_dtor(BclContext ctxt, BclNumber n, BclNum* restrict num)
577{
578	assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
579
580	BCL_CLEAR_GEN(n);
581
582	bcl_num_destruct(num);
583	bc_vec_push(&ctxt->free_nums, &n);
584
585#if BC_ENABLE_MEMCHECK
586	num->n.num = NULL;
587#endif // BC_ENABLE_MEMCHECK
588}
589
590void
591bcl_num_free(BclNumber n)
592{
593	BclNum* num;
594	BclContext ctxt;
595	BcVm* vm = bcl_getspecific();
596
597	BC_CHECK_CTXT_ASSERT(vm, ctxt);
598
599	BCL_CHECK_NUM_VALID(ctxt, n);
600
601	assert(BCL_NO_GEN(n) < ctxt->nums.len);
602
603	num = BCL_NUM(ctxt, n);
604
605	bcl_num_dtor(ctxt, n, num);
606}
607
608BclError
609bcl_copy(BclNumber d, BclNumber s)
610{
611	BclError e = BCL_ERROR_NONE;
612	BclNum* dest;
613	BclNum* src;
614	BclContext ctxt;
615	BcVm* vm = bcl_getspecific();
616
617	BC_CHECK_CTXT_ERR(vm, ctxt);
618
619	BCL_CHECK_NUM_VALID(ctxt, d);
620	BCL_CHECK_NUM_VALID(ctxt, s);
621
622	BC_FUNC_HEADER(vm, err);
623
624	assert(BCL_NO_GEN(d) < ctxt->nums.len);
625	assert(BCL_NO_GEN(s) < ctxt->nums.len);
626
627	dest = BCL_NUM(ctxt, d);
628	src = BCL_NUM(ctxt, s);
629
630	assert(dest != NULL && src != NULL);
631	assert(BCL_NUM_ARRAY(dest) != NULL && BCL_NUM_ARRAY(src) != NULL);
632
633	bc_num_copy(BCL_NUM_NUM(dest), BCL_NUM_NUM(src));
634
635err:
636
637	BC_FUNC_FOOTER(vm, e);
638
639	return e;
640}
641
642BclNumber
643bcl_dup(BclNumber s)
644{
645	BclError e = BCL_ERROR_NONE;
646	BclNum *src, dest;
647	BclNumber idx;
648	BclContext ctxt;
649	BcVm* vm = bcl_getspecific();
650
651	BC_CHECK_CTXT(vm, ctxt);
652
653	BCL_CHECK_NUM_VALID(ctxt, s);
654
655	BC_FUNC_HEADER(vm, err);
656
657	BCL_GROW_NUMS(ctxt);
658
659	assert(BCL_NO_GEN(s) < ctxt->nums.len);
660
661	src = BCL_NUM(ctxt, s);
662
663	assert(src != NULL && BCL_NUM_NUM(src) != NULL);
664
665	// Copy the number.
666	bc_num_clear(BCL_NUM_NUM(&dest));
667	bc_num_createCopy(BCL_NUM_NUM(&dest), BCL_NUM_NUM(src));
668
669err:
670
671	BC_FUNC_FOOTER(vm, e);
672	BC_MAYBE_SETUP(ctxt, e, dest, idx);
673
674	return idx;
675}
676
677void
678bcl_num_destruct(void* num)
679{
680	BclNum* n = (BclNum*) num;
681
682	assert(n != NULL);
683
684	if (BCL_NUM_ARRAY(n) == NULL) return;
685
686	bc_num_free(BCL_NUM_NUM(n));
687	bc_num_clear(BCL_NUM_NUM(n));
688}
689
690bool
691bcl_num_neg(BclNumber n)
692{
693	BclNum* num;
694	BclContext ctxt;
695	BcVm* vm = bcl_getspecific();
696
697	BC_CHECK_CTXT_ASSERT(vm, ctxt);
698
699	BCL_CHECK_NUM_VALID(ctxt, n);
700
701	assert(BCL_NO_GEN(n) < ctxt->nums.len);
702
703	num = BCL_NUM(ctxt, n);
704
705	assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
706
707	return BC_NUM_NEG(BCL_NUM_NUM(num)) != 0;
708}
709
710void
711bcl_num_setNeg(BclNumber n, bool neg)
712{
713	BclNum* num;
714	BclContext ctxt;
715	BcVm* vm = bcl_getspecific();
716
717	BC_CHECK_CTXT_ASSERT(vm, ctxt);
718
719	BCL_CHECK_NUM_VALID(ctxt, n);
720
721	assert(BCL_NO_GEN(n) < ctxt->nums.len);
722
723	num = BCL_NUM(ctxt, n);
724
725	assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
726
727	BCL_NUM_NUM(num)->rdx = BC_NUM_NEG_VAL(BCL_NUM_NUM(num), neg);
728}
729
730size_t
731bcl_num_scale(BclNumber n)
732{
733	BclNum* num;
734	BclContext ctxt;
735	BcVm* vm = bcl_getspecific();
736
737	BC_CHECK_CTXT_ASSERT(vm, ctxt);
738
739	BCL_CHECK_NUM_VALID(ctxt, n);
740
741	assert(BCL_NO_GEN(n) < ctxt->nums.len);
742
743	num = BCL_NUM(ctxt, n);
744
745	assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
746
747	return bc_num_scale(BCL_NUM_NUM(num));
748}
749
750BclError
751bcl_num_setScale(BclNumber n, size_t scale)
752{
753	BclError e = BCL_ERROR_NONE;
754	BclNum* nptr;
755	BclContext ctxt;
756	BcVm* vm = bcl_getspecific();
757
758	BC_CHECK_CTXT_ERR(vm, ctxt);
759
760	BC_CHECK_NUM_ERR(ctxt, n);
761
762	BCL_CHECK_NUM_VALID(ctxt, n);
763
764	BC_FUNC_HEADER(vm, err);
765
766	assert(BCL_NO_GEN(n) < ctxt->nums.len);
767
768	nptr = BCL_NUM(ctxt, n);
769
770	assert(nptr != NULL && BCL_NUM_ARRAY(nptr) != NULL);
771
772	if (scale > BCL_NUM_NUM(nptr)->scale)
773	{
774		bc_num_extend(BCL_NUM_NUM(nptr), scale - BCL_NUM_NUM(nptr)->scale);
775	}
776	else if (scale < BCL_NUM_NUM(nptr)->scale)
777	{
778		bc_num_truncate(BCL_NUM_NUM(nptr), BCL_NUM_NUM(nptr)->scale - scale);
779	}
780
781err:
782
783	BC_FUNC_FOOTER(vm, e);
784
785	return e;
786}
787
788size_t
789bcl_num_len(BclNumber n)
790{
791	BclNum* num;
792	BclContext ctxt;
793	BcVm* vm = bcl_getspecific();
794
795	BC_CHECK_CTXT_ASSERT(vm, ctxt);
796
797	BCL_CHECK_NUM_VALID(ctxt, n);
798
799	assert(BCL_NO_GEN(n) < ctxt->nums.len);
800
801	num = BCL_NUM(ctxt, n);
802
803	assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
804
805	return bc_num_len(BCL_NUM_NUM(num));
806}
807
808static BclError
809bcl_bigdig_helper(BclNumber n, BclBigDig* result, bool destruct)
810{
811	BclError e = BCL_ERROR_NONE;
812	BclNum* num;
813	BclContext ctxt;
814	BcVm* vm = bcl_getspecific();
815
816	BC_CHECK_CTXT_ERR(vm, ctxt);
817
818	BCL_CHECK_NUM_VALID(ctxt, n);
819
820	BC_FUNC_HEADER(vm, err);
821
822	assert(BCL_NO_GEN(n) < ctxt->nums.len);
823	assert(result != NULL);
824
825	num = BCL_NUM(ctxt, n);
826
827	assert(num != NULL && BCL_NUM_ARRAY(num) != NULL);
828
829	*result = bc_num_bigdig(BCL_NUM_NUM(num));
830
831err:
832
833	if (destruct)
834	{
835		bcl_num_dtor(ctxt, n, num);
836	}
837
838	BC_FUNC_FOOTER(vm, e);
839
840	return e;
841}
842
843BclError
844bcl_bigdig(BclNumber n, BclBigDig* result)
845{
846	return bcl_bigdig_helper(n, result, true);
847}
848
849BclError
850bcl_bigdig_keep(BclNumber n, BclBigDig* result)
851{
852	return bcl_bigdig_helper(n, result, false);
853}
854
855BclNumber
856bcl_bigdig2num(BclBigDig val)
857{
858	BclError e = BCL_ERROR_NONE;
859	BclNum n;
860	BclNumber idx;
861	BclContext ctxt;
862	BcVm* vm = bcl_getspecific();
863
864	BC_CHECK_CTXT(vm, ctxt);
865
866	BC_FUNC_HEADER(vm, err);
867
868	BCL_GROW_NUMS(ctxt);
869
870	bc_num_createFromBigdig(BCL_NUM_NUM_NP(n), val);
871
872err:
873
874	BC_FUNC_FOOTER(vm, e);
875	BC_MAYBE_SETUP(ctxt, e, n, idx);
876
877	return idx;
878}
879
880/**
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
886 *                  preallocation.
887 * @param destruct  True if the parameters should be consumed, false otherwise.
888 * @return          The result of the operation.
889 */
890static BclNumber
891bcl_binary(BclNumber a, BclNumber b, const BcNumBinaryOp op,
892           const BcNumBinaryOpReq req, bool destruct)
893{
894	BclError e = BCL_ERROR_NONE;
895	BclNum* aptr;
896	BclNum* bptr;
897	BclNum c;
898	BclNumber idx;
899	BclContext ctxt;
900	BcVm* vm = bcl_getspecific();
901
902	BC_CHECK_CTXT(vm, ctxt);
903
904	BC_CHECK_NUM(ctxt, a);
905	BC_CHECK_NUM(ctxt, b);
906
907	BC_FUNC_HEADER(vm, err);
908
909	BCL_GROW_NUMS(ctxt);
910
911	assert(BCL_NO_GEN(a) < ctxt->nums.len && BCL_NO_GEN(b) < ctxt->nums.len);
912
913	aptr = BCL_NUM(ctxt, a);
914	bptr = BCL_NUM(ctxt, b);
915
916	assert(aptr != NULL && bptr != NULL);
917	assert(BCL_NUM_ARRAY(aptr) != NULL && BCL_NUM_ARRAY(bptr) != NULL);
918
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));
923
924	op(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM_NP(c), ctxt->scale);
925
926err:
927
928	if (destruct)
929	{
930		// Eat the operands.
931		bcl_num_dtor(ctxt, a, aptr);
932		if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
933	}
934
935	BC_FUNC_FOOTER(vm, e);
936	BC_MAYBE_SETUP(ctxt, e, c, idx);
937
938	return idx;
939}
940
941BclNumber
942bcl_add(BclNumber a, BclNumber b)
943{
944	return bcl_binary(a, b, bc_num_add, bc_num_addReq, true);
945}
946
947BclNumber
948bcl_add_keep(BclNumber a, BclNumber b)
949{
950	return bcl_binary(a, b, bc_num_add, bc_num_addReq, false);
951}
952
953BclNumber
954bcl_sub(BclNumber a, BclNumber b)
955{
956	return bcl_binary(a, b, bc_num_sub, bc_num_addReq, true);
957}
958
959BclNumber
960bcl_sub_keep(BclNumber a, BclNumber b)
961{
962	return bcl_binary(a, b, bc_num_sub, bc_num_addReq, false);
963}
964
965BclNumber
966bcl_mul(BclNumber a, BclNumber b)
967{
968	return bcl_binary(a, b, bc_num_mul, bc_num_mulReq, true);
969}
970
971BclNumber
972bcl_mul_keep(BclNumber a, BclNumber b)
973{
974	return bcl_binary(a, b, bc_num_mul, bc_num_mulReq, false);
975}
976
977BclNumber
978bcl_div(BclNumber a, BclNumber b)
979{
980	return bcl_binary(a, b, bc_num_div, bc_num_divReq, true);
981}
982
983BclNumber
984bcl_div_keep(BclNumber a, BclNumber b)
985{
986	return bcl_binary(a, b, bc_num_div, bc_num_divReq, false);
987}
988
989BclNumber
990bcl_mod(BclNumber a, BclNumber b)
991{
992	return bcl_binary(a, b, bc_num_mod, bc_num_divReq, true);
993}
994
995BclNumber
996bcl_mod_keep(BclNumber a, BclNumber b)
997{
998	return bcl_binary(a, b, bc_num_mod, bc_num_divReq, false);
999}
1000
1001BclNumber
1002bcl_pow(BclNumber a, BclNumber b)
1003{
1004	return bcl_binary(a, b, bc_num_pow, bc_num_powReq, true);
1005}
1006
1007BclNumber
1008bcl_pow_keep(BclNumber a, BclNumber b)
1009{
1010	return bcl_binary(a, b, bc_num_pow, bc_num_powReq, false);
1011}
1012
1013BclNumber
1014bcl_lshift(BclNumber a, BclNumber b)
1015{
1016	return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq, true);
1017}
1018
1019BclNumber
1020bcl_lshift_keep(BclNumber a, BclNumber b)
1021{
1022	return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq, false);
1023}
1024
1025BclNumber
1026bcl_rshift(BclNumber a, BclNumber b)
1027{
1028	return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq, true);
1029}
1030
1031BclNumber
1032bcl_rshift_keep(BclNumber a, BclNumber b)
1033{
1034	return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq, false);
1035}
1036
1037static BclNumber
1038bcl_sqrt_helper(BclNumber a, bool destruct)
1039{
1040	BclError e = BCL_ERROR_NONE;
1041	BclNum* aptr;
1042	BclNum b;
1043	BclNumber idx;
1044	BclContext ctxt;
1045	BcVm* vm = bcl_getspecific();
1046
1047	BC_CHECK_CTXT(vm, ctxt);
1048
1049	BC_CHECK_NUM(ctxt, a);
1050
1051	BC_FUNC_HEADER(vm, err);
1052
1053	BCL_GROW_NUMS(ctxt);
1054
1055	assert(BCL_NO_GEN(a) < ctxt->nums.len);
1056
1057	aptr = BCL_NUM(ctxt, a);
1058
1059	bc_num_sqrt(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), ctxt->scale);
1060
1061err:
1062
1063	if (destruct)
1064	{
1065		bcl_num_dtor(ctxt, a, aptr);
1066	}
1067
1068	BC_FUNC_FOOTER(vm, e);
1069	BC_MAYBE_SETUP(ctxt, e, b, idx);
1070
1071	return idx;
1072}
1073
1074BclNumber
1075bcl_sqrt(BclNumber a)
1076{
1077	return bcl_sqrt_helper(a, true);
1078}
1079
1080BclNumber
1081bcl_sqrt_keep(BclNumber a)
1082{
1083	return bcl_sqrt_helper(a, false);
1084}
1085
1086static BclError
1087bcl_divmod_helper(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d,
1088                  bool destruct)
1089{
1090	BclError e = BCL_ERROR_NONE;
1091	size_t req;
1092	BclNum* aptr;
1093	BclNum* bptr;
1094	BclNum cnum, dnum;
1095	BclContext ctxt;
1096	BcVm* vm = bcl_getspecific();
1097
1098	BC_CHECK_CTXT_ERR(vm, ctxt);
1099
1100	BC_CHECK_NUM_ERR(ctxt, a);
1101	BC_CHECK_NUM_ERR(ctxt, b);
1102
1103	BC_FUNC_HEADER(vm, err);
1104
1105	BCL_GROW_NUMS(ctxt);
1106
1107	assert(c != NULL && d != NULL);
1108
1109	aptr = BCL_NUM(ctxt, a);
1110	bptr = BCL_NUM(ctxt, b);
1111
1112	assert(aptr != NULL && bptr != NULL);
1113	assert(BCL_NUM_ARRAY(aptr) != NULL && BCL_NUM_ARRAY(bptr) != NULL);
1114
1115	bc_num_clear(BCL_NUM_NUM_NP(cnum));
1116	bc_num_clear(BCL_NUM_NUM_NP(dnum));
1117
1118	req = bc_num_divReq(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), ctxt->scale);
1119
1120	// Initialize the numbers.
1121	bc_num_init(BCL_NUM_NUM_NP(cnum), req);
1122	BC_UNSETJMP(vm);
1123	BC_SETJMP(vm, err);
1124	bc_num_init(BCL_NUM_NUM_NP(dnum), req);
1125
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);
1128
1129err:
1130
1131	if (destruct)
1132	{
1133		// Eat the operands.
1134		bcl_num_dtor(ctxt, a, aptr);
1135		if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
1136	}
1137
1138	// If there was an error...
1139	if (BC_ERR(vm->err))
1140	{
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);
1144
1145		// Make sure the return values are invalid.
1146		c->i = 0 - (size_t) BCL_ERROR_INVALID_NUM;
1147		d->i = c->i;
1148
1149		BC_FUNC_FOOTER(vm, e);
1150	}
1151	else
1152	{
1153		BC_FUNC_FOOTER(vm, e);
1154
1155		// Insert the results into the context.
1156		*c = bcl_num_insert(ctxt, &cnum);
1157		*d = bcl_num_insert(ctxt, &dnum);
1158	}
1159
1160	return e;
1161}
1162
1163BclError
1164bcl_divmod(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d)
1165{
1166	return bcl_divmod_helper(a, b, c, d, true);
1167}
1168
1169BclError
1170bcl_divmod_keep(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d)
1171{
1172	return bcl_divmod_helper(a, b, c, d, false);
1173}
1174
1175static BclNumber
1176bcl_modexp_helper(BclNumber a, BclNumber b, BclNumber c, bool destruct)
1177{
1178	BclError e = BCL_ERROR_NONE;
1179	size_t req;
1180	BclNum* aptr;
1181	BclNum* bptr;
1182	BclNum* cptr;
1183	BclNum d;
1184	BclNumber idx;
1185	BclContext ctxt;
1186	BcVm* vm = bcl_getspecific();
1187
1188	BC_CHECK_CTXT(vm, ctxt);
1189
1190	BC_CHECK_NUM(ctxt, a);
1191	BC_CHECK_NUM(ctxt, b);
1192	BC_CHECK_NUM(ctxt, c);
1193
1194	BC_FUNC_HEADER(vm, err);
1195
1196	BCL_GROW_NUMS(ctxt);
1197
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);
1200
1201	aptr = BCL_NUM(ctxt, a);
1202	bptr = BCL_NUM(ctxt, b);
1203	cptr = BCL_NUM(ctxt, c);
1204
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);
1208
1209	// Prepare the result.
1210	bc_num_clear(BCL_NUM_NUM_NP(d));
1211
1212	req = bc_num_divReq(BCL_NUM_NUM(aptr), BCL_NUM_NUM(cptr), 0);
1213
1214	// Initialize the result.
1215	bc_num_init(BCL_NUM_NUM_NP(d), req);
1216
1217	bc_num_modexp(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr), BCL_NUM_NUM(cptr),
1218	              BCL_NUM_NUM_NP(d));
1219
1220err:
1221
1222	if (destruct)
1223	{
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);
1228	}
1229
1230	BC_FUNC_FOOTER(vm, e);
1231	BC_MAYBE_SETUP(ctxt, e, d, idx);
1232
1233	return idx;
1234}
1235
1236BclNumber
1237bcl_modexp(BclNumber a, BclNumber b, BclNumber c)
1238{
1239	return bcl_modexp_helper(a, b, c, true);
1240}
1241
1242BclNumber
1243bcl_modexp_keep(BclNumber a, BclNumber b, BclNumber c)
1244{
1245	return bcl_modexp_helper(a, b, c, false);
1246}
1247
1248ssize_t
1249bcl_cmp(BclNumber a, BclNumber b)
1250{
1251	BclNum* aptr;
1252	BclNum* bptr;
1253	BclContext ctxt;
1254	BcVm* vm = bcl_getspecific();
1255
1256	BC_CHECK_CTXT_ASSERT(vm, ctxt);
1257
1258	BCL_CHECK_NUM_VALID(ctxt, a);
1259	BCL_CHECK_NUM_VALID(ctxt, b);
1260
1261	assert(BCL_NO_GEN(a) < ctxt->nums.len && BCL_NO_GEN(b) < ctxt->nums.len);
1262
1263	aptr = BCL_NUM(ctxt, a);
1264	bptr = BCL_NUM(ctxt, b);
1265
1266	assert(aptr != NULL && bptr != NULL);
1267	assert(BCL_NUM_NUM(aptr) != NULL && BCL_NUM_NUM(bptr));
1268
1269	return bc_num_cmp(BCL_NUM_NUM(aptr), BCL_NUM_NUM(bptr));
1270}
1271
1272void
1273bcl_zero(BclNumber n)
1274{
1275	BclNum* nptr;
1276	BclContext ctxt;
1277	BcVm* vm = bcl_getspecific();
1278
1279	BC_CHECK_CTXT_ASSERT(vm, ctxt);
1280
1281	BCL_CHECK_NUM_VALID(ctxt, n);
1282
1283	assert(BCL_NO_GEN(n) < ctxt->nums.len);
1284
1285	nptr = BCL_NUM(ctxt, n);
1286
1287	assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL);
1288
1289	bc_num_zero(BCL_NUM_NUM(nptr));
1290}
1291
1292void
1293bcl_one(BclNumber n)
1294{
1295	BclNum* nptr;
1296	BclContext ctxt;
1297	BcVm* vm = bcl_getspecific();
1298
1299	BC_CHECK_CTXT_ASSERT(vm, ctxt);
1300
1301	BCL_CHECK_NUM_VALID(ctxt, n);
1302
1303	assert(BCL_NO_GEN(n) < ctxt->nums.len);
1304
1305	nptr = BCL_NUM(ctxt, n);
1306
1307	assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL);
1308
1309	bc_num_one(BCL_NUM_NUM(nptr));
1310}
1311
1312BclNumber
1313bcl_parse(const char* restrict val)
1314{
1315	BclError e = BCL_ERROR_NONE;
1316	BclNum n;
1317	BclNumber idx;
1318	BclContext ctxt;
1319	BcVm* vm = bcl_getspecific();
1320	bool neg;
1321
1322	BC_CHECK_CTXT(vm, ctxt);
1323
1324	BC_FUNC_HEADER(vm, err);
1325
1326	BCL_GROW_NUMS(ctxt);
1327
1328	assert(val != NULL);
1329
1330	// We have to take care of negative here because bc's number parsing does
1331	// not.
1332	neg = (val[0] == '-');
1333
1334	if (neg) val += 1;
1335
1336	if (!bc_num_strValid(val))
1337	{
1338		vm->err = BCL_ERROR_PARSE_INVALID_STR;
1339		goto err;
1340	}
1341
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);
1345
1346	bc_num_parse(BCL_NUM_NUM_NP(n), val, (BcBigDig) ctxt->ibase);
1347
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
1354
1355err:
1356
1357	BC_FUNC_FOOTER(vm, e);
1358	BC_MAYBE_SETUP(ctxt, e, n, idx);
1359
1360	return idx;
1361}
1362
1363static char*
1364bcl_string_helper(BclNumber n, bool destruct)
1365{
1366	BclNum* nptr;
1367	char* str = NULL;
1368	BclContext ctxt;
1369	BcVm* vm = bcl_getspecific();
1370
1371	BC_CHECK_CTXT_ASSERT(vm, ctxt);
1372
1373	BCL_CHECK_NUM_VALID(ctxt, n);
1374
1375	if (BC_ERR(BCL_NO_GEN(n) >= ctxt->nums.len)) return str;
1376
1377	BC_FUNC_HEADER(vm, err);
1378
1379	assert(BCL_NO_GEN(n) < ctxt->nums.len);
1380
1381	nptr = BCL_NUM(ctxt, n);
1382
1383	assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL);
1384
1385	// Clear the buffer.
1386	bc_vec_popAll(&vm->out);
1387
1388	// Print to the buffer.
1389	bc_num_print(BCL_NUM_NUM(nptr), (BcBigDig) ctxt->obase, false);
1390	bc_vec_pushByte(&vm->out, '\0');
1391
1392	// Just dup the string; the caller is responsible for it.
1393	str = bc_vm_strdup(vm->out.v);
1394
1395err:
1396
1397	if (destruct)
1398	{
1399		// Eat the operand.
1400		bcl_num_dtor(ctxt, n, nptr);
1401	}
1402
1403	BC_FUNC_FOOTER_NO_ERR(vm);
1404
1405	return str;
1406}
1407
1408char*
1409bcl_string(BclNumber n)
1410{
1411	return bcl_string_helper(n, true);
1412}
1413
1414char*
1415bcl_string_keep(BclNumber n)
1416{
1417	return bcl_string_helper(n, false);
1418}
1419
1420#if BC_ENABLE_EXTRA_MATH
1421
1422static BclNumber
1423bcl_irand_helper(BclNumber a, bool destruct)
1424{
1425	BclError e = BCL_ERROR_NONE;
1426	BclNum* aptr;
1427	BclNum b;
1428	BclNumber idx;
1429	BclContext ctxt;
1430	BcVm* vm = bcl_getspecific();
1431
1432	BC_CHECK_CTXT(vm, ctxt);
1433
1434	BC_CHECK_NUM(ctxt, a);
1435
1436	BC_FUNC_HEADER(vm, err);
1437
1438	BCL_GROW_NUMS(ctxt);
1439
1440	assert(BCL_NO_GEN(a) < ctxt->nums.len);
1441
1442	aptr = BCL_NUM(ctxt, a);
1443
1444	assert(aptr != NULL && BCL_NUM_NUM(aptr) != NULL);
1445
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);
1449
1450	bc_num_irand(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), &vm->rng);
1451
1452err:
1453
1454	if (destruct)
1455	{
1456		// Eat the operand.
1457		bcl_num_dtor(ctxt, a, aptr);
1458	}
1459
1460	BC_FUNC_FOOTER(vm, e);
1461	BC_MAYBE_SETUP(ctxt, e, b, idx);
1462
1463	return idx;
1464}
1465
1466BclNumber
1467bcl_irand(BclNumber a)
1468{
1469	return bcl_irand_helper(a, true);
1470}
1471
1472BclNumber
1473bcl_irand_keep(BclNumber a)
1474{
1475	return bcl_irand_helper(a, false);
1476}
1477
1478/**
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.
1483 */
1484static void
1485bcl_frandHelper(BcNum* restrict b, size_t places)
1486{
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();
1491
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);
1495
1496	ten.num[0] = 10;
1497	ten.len = 1;
1498
1499	bc_num_bigdig2num(&exp, (BcBigDig) places);
1500
1501	// Clear the temporary that might need to grow.
1502	bc_num_clear(&pow);
1503
1504	// Initialize the temporary that might need to grow.
1505	bc_num_init(&pow, bc_num_powReq(&ten, &exp, 0));
1506
1507	BC_SETJMP(vm, err);
1508
1509	// Generate the number.
1510	bc_num_pow(&ten, &exp, &pow, 0);
1511	bc_num_irand(&pow, b, &vm->rng);
1512
1513	// Make the number entirely fraction.
1514	bc_num_shiftRight(b, places);
1515
1516err:
1517
1518	bc_num_free(&pow);
1519	BC_LONGJMP_CONT(vm);
1520}
1521
1522BclNumber
1523bcl_frand(size_t places)
1524{
1525	BclError e = BCL_ERROR_NONE;
1526	BclNum n;
1527	BclNumber idx;
1528	BclContext ctxt;
1529	BcVm* vm = bcl_getspecific();
1530
1531	BC_CHECK_CTXT(vm, ctxt);
1532
1533	BC_FUNC_HEADER(vm, err);
1534
1535	BCL_GROW_NUMS(ctxt);
1536
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);
1540
1541	bcl_frandHelper(BCL_NUM_NUM_NP(n), places);
1542
1543err:
1544
1545	BC_FUNC_FOOTER(vm, e);
1546	BC_MAYBE_SETUP(ctxt, e, n, idx);
1547
1548	return idx;
1549}
1550
1551/**
1552 * Helps bc_ifrand(). This is separate because error handling is easier that
1553 * way.
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.
1557 */
1558static void
1559bcl_ifrandHelper(BcNum* restrict a, BcNum* restrict b, size_t places)
1560{
1561	BcNum ir, fr;
1562	BcVm* vm = bcl_getspecific();
1563
1564	// Clear the integer and fractional numbers.
1565	bc_num_clear(&ir);
1566	bc_num_clear(&fr);
1567
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);
1571
1572	BC_SETJMP(vm, err);
1573
1574	bc_num_irand(a, &ir, &vm->rng);
1575	bcl_frandHelper(&fr, places);
1576
1577	bc_num_add(&ir, &fr, b, 0);
1578
1579err:
1580
1581	bc_num_free(&fr);
1582	bc_num_free(&ir);
1583	BC_LONGJMP_CONT(vm);
1584}
1585
1586static BclNumber
1587bcl_ifrand_helper(BclNumber a, size_t places, bool destruct)
1588{
1589	BclError e = BCL_ERROR_NONE;
1590	BclNum* aptr;
1591	BclNum b;
1592	BclNumber idx;
1593	BclContext ctxt;
1594	BcVm* vm = bcl_getspecific();
1595
1596	BC_CHECK_CTXT(vm, ctxt);
1597	BC_CHECK_NUM(ctxt, a);
1598
1599	BC_FUNC_HEADER(vm, err);
1600
1601	BCL_GROW_NUMS(ctxt);
1602
1603	assert(BCL_NO_GEN(a) < ctxt->nums.len);
1604
1605	aptr = BCL_NUM(ctxt, a);
1606
1607	assert(aptr != NULL && BCL_NUM_NUM(aptr) != NULL);
1608
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);
1612
1613	bcl_ifrandHelper(BCL_NUM_NUM(aptr), BCL_NUM_NUM_NP(b), places);
1614
1615err:
1616
1617	if (destruct)
1618	{
1619		// Eat the oprand.
1620		bcl_num_dtor(ctxt, a, aptr);
1621	}
1622
1623	BC_FUNC_FOOTER(vm, e);
1624	BC_MAYBE_SETUP(ctxt, e, b, idx);
1625
1626	return idx;
1627}
1628
1629BclNumber
1630bcl_ifrand(BclNumber a, size_t places)
1631{
1632	return bcl_ifrand_helper(a, places, true);
1633}
1634
1635BclNumber
1636bcl_ifrand_keep(BclNumber a, size_t places)
1637{
1638	return bcl_ifrand_helper(a, places, false);
1639}
1640
1641static BclError
1642bcl_rand_seedWithNum_helper(BclNumber n, bool destruct)
1643{
1644	BclError e = BCL_ERROR_NONE;
1645	BclNum* nptr;
1646	BclContext ctxt;
1647	BcVm* vm = bcl_getspecific();
1648
1649	BC_CHECK_CTXT_ERR(vm, ctxt);
1650	BC_CHECK_NUM_ERR(ctxt, n);
1651
1652	BC_FUNC_HEADER(vm, err);
1653
1654	assert(BCL_NO_GEN(n) < ctxt->nums.len);
1655
1656	nptr = BCL_NUM(ctxt, n);
1657
1658	assert(nptr != NULL && BCL_NUM_NUM(nptr) != NULL);
1659
1660	bc_num_rng(BCL_NUM_NUM(nptr), &vm->rng);
1661
1662err:
1663
1664	if (destruct)
1665	{
1666		// Eat the oprand.
1667		bcl_num_dtor(ctxt, n, nptr);
1668	}
1669
1670	BC_FUNC_FOOTER(vm, e);
1671
1672	return e;
1673}
1674
1675BclError
1676bcl_rand_seedWithNum(BclNumber n)
1677{
1678	return bcl_rand_seedWithNum_helper(n, true);
1679}
1680
1681BclError
1682bcl_rand_seedWithNum_keep(BclNumber n)
1683{
1684	return bcl_rand_seedWithNum_helper(n, false);
1685}
1686
1687BclError
1688bcl_rand_seed(unsigned char seed[BCL_SEED_SIZE])
1689{
1690	BclError e = BCL_ERROR_NONE;
1691	size_t i;
1692	ulong vals[BCL_SEED_ULONGS];
1693	BcVm* vm = bcl_getspecific();
1694
1695	BC_FUNC_HEADER(vm, err);
1696
1697	// Fill the array.
1698	for (i = 0; i < BCL_SEED_SIZE; ++i)
1699	{
1700		ulong val = ((ulong) seed[i])
1701		            << (((ulong) CHAR_BIT) * (i % sizeof(ulong)));
1702		vals[i / sizeof(long)] |= val;
1703	}
1704
1705	bc_rand_seed(&vm->rng, vals[0], vals[1], vals[2], vals[3]);
1706
1707err:
1708
1709	BC_FUNC_FOOTER(vm, e);
1710
1711	return e;
1712}
1713
1714void
1715bcl_rand_reseed(void)
1716{
1717	BcVm* vm = bcl_getspecific();
1718
1719	bc_rand_srand(bc_vec_top(&vm->rng.v));
1720}
1721
1722BclNumber
1723bcl_rand_seed2num(void)
1724{
1725	BclError e = BCL_ERROR_NONE;
1726	BclNum n;
1727	BclNumber idx;
1728	BclContext ctxt;
1729	BcVm* vm = bcl_getspecific();
1730
1731	BC_CHECK_CTXT(vm, ctxt);
1732
1733	BC_FUNC_HEADER(vm, err);
1734
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);
1738
1739	bc_num_createFromRNG(BCL_NUM_NUM_NP(n), &vm->rng);
1740
1741err:
1742
1743	BC_FUNC_FOOTER(vm, e);
1744	BC_MAYBE_SETUP(ctxt, e, n, idx);
1745
1746	return idx;
1747}
1748
1749BclRandInt
1750bcl_rand_int(void)
1751{
1752	BcVm* vm = bcl_getspecific();
1753
1754	return (BclRandInt) bc_rand_int(&vm->rng);
1755}
1756
1757BclRandInt
1758bcl_rand_bounded(BclRandInt bound)
1759{
1760	BcVm* vm = bcl_getspecific();
1761
1762	if (bound <= 1) return 0;
1763	return (BclRandInt) bc_rand_bounded(&vm->rng, (BcRand) bound);
1764}
1765
1766#endif // BC_ENABLE_EXTRA_MATH
1767
1768#endif // BC_ENABLE_LIBRARY
1769