Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/bc/src/library.c
39507 views
1
/*
2
* *****************************************************************************
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*
6
* Copyright (c) 2018-2025 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
65
BC_NORETURN void
66
bcl_invalidGeneration(void)
67
{
68
abort();
69
}
70
71
BC_NORETURN void
72
bcl_nonexistentNum(void)
73
{
74
abort();
75
}
76
77
BC_NORETURN void
78
bcl_numIdxOutOfRange(void)
79
{
80
abort();
81
}
82
83
#endif // BC_ENABLE_MEMCHECK
84
85
static BclTls* tls = NULL;
86
static BclTls tls_real;
87
88
BclError
89
bcl_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
*/
122
static BclError
123
bcl_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
148
BcVm*
149
bcl_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
166
BclError
167
bcl_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
228
err:
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
245
BclError
246
bcl_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
255
err:
256
257
BC_FUNC_FOOTER(vm, e);
258
return e;
259
}
260
261
void
262
bcl_popContext(void)
263
{
264
BcVm* vm = bcl_getspecific();
265
266
if (vm->ctxts.len) bc_vec_pop(&vm->ctxts);
267
}
268
269
static BclContext
270
bcl_contextHelper(BcVm* vm)
271
{
272
if (!vm->ctxts.len) return NULL;
273
return *((BclContext*) bc_vec_top(&vm->ctxts));
274
}
275
276
BclContext
277
bcl_context(void)
278
{
279
BcVm* vm = bcl_getspecific();
280
return bcl_contextHelper(vm);
281
}
282
283
void
284
bcl_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
311
void
312
bcl_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
329
void
330
bcl_gc(void)
331
{
332
bc_vm_freeTemps();
333
}
334
335
bool
336
bcl_abortOnFatalError(void)
337
{
338
BcVm* vm = bcl_getspecific();
339
340
return vm->abrt;
341
}
342
343
void
344
bcl_setAbortOnFatalError(bool abrt)
345
{
346
BcVm* vm = bcl_getspecific();
347
348
vm->abrt = abrt;
349
}
350
351
bool
352
bcl_leadingZeroes(void)
353
{
354
BcVm* vm = bcl_getspecific();
355
356
return vm->leading_zeroes;
357
}
358
359
void
360
bcl_setLeadingZeroes(bool leadingZeroes)
361
{
362
BcVm* vm = bcl_getspecific();
363
364
vm->leading_zeroes = leadingZeroes;
365
}
366
367
bool
368
bcl_digitClamp(void)
369
{
370
BcVm* vm = bcl_getspecific();
371
372
return vm->digit_clamp;
373
}
374
375
void
376
bcl_setDigitClamp(bool digitClamp)
377
{
378
BcVm* vm = bcl_getspecific();
379
380
vm->digit_clamp = digitClamp;
381
}
382
383
BclContext
384
bcl_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
402
err:
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
416
void
417
bcl_ctxt_free(BclContext ctxt)
418
{
419
bc_vec_free(&ctxt->free_nums);
420
bc_vec_free(&ctxt->nums);
421
free(ctxt);
422
}
423
424
void
425
bcl_ctxt_freeNums(BclContext ctxt)
426
{
427
bc_vec_popAll(&ctxt->nums);
428
bc_vec_popAll(&ctxt->free_nums);
429
}
430
431
size_t
432
bcl_ctxt_scale(BclContext ctxt)
433
{
434
return ctxt->scale;
435
}
436
437
void
438
bcl_ctxt_setScale(BclContext ctxt, size_t scale)
439
{
440
ctxt->scale = scale;
441
}
442
443
size_t
444
bcl_ctxt_ibase(BclContext ctxt)
445
{
446
return ctxt->ibase;
447
}
448
449
void
450
bcl_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
457
size_t
458
bcl_ctxt_obase(BclContext ctxt)
459
{
460
return ctxt->obase;
461
}
462
463
void
464
bcl_ctxt_setObase(BclContext ctxt, size_t obase)
465
{
466
ctxt->obase = obase;
467
}
468
469
BclError
470
bcl_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
*/
497
static BclNumber
498
bcl_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
544
BclNumber
545
bcl_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
561
err:
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
*/
575
static void
576
bcl_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
590
void
591
bcl_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
608
BclError
609
bcl_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
635
err:
636
637
BC_FUNC_FOOTER(vm, e);
638
639
return e;
640
}
641
642
BclNumber
643
bcl_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
669
err:
670
671
BC_FUNC_FOOTER(vm, e);
672
BC_MAYBE_SETUP(ctxt, e, dest, idx);
673
674
return idx;
675
}
676
677
void
678
bcl_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
690
bool
691
bcl_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
710
void
711
bcl_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
730
size_t
731
bcl_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
750
BclError
751
bcl_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
781
err:
782
783
BC_FUNC_FOOTER(vm, e);
784
785
return e;
786
}
787
788
size_t
789
bcl_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
808
static BclError
809
bcl_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
831
err:
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
843
BclError
844
bcl_bigdig(BclNumber n, BclBigDig* result)
845
{
846
return bcl_bigdig_helper(n, result, true);
847
}
848
849
BclError
850
bcl_bigdig_keep(BclNumber n, BclBigDig* result)
851
{
852
return bcl_bigdig_helper(n, result, false);
853
}
854
855
BclNumber
856
bcl_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
872
err:
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
*/
890
static BclNumber
891
bcl_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
926
err:
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
941
BclNumber
942
bcl_add(BclNumber a, BclNumber b)
943
{
944
return bcl_binary(a, b, bc_num_add, bc_num_addReq, true);
945
}
946
947
BclNumber
948
bcl_add_keep(BclNumber a, BclNumber b)
949
{
950
return bcl_binary(a, b, bc_num_add, bc_num_addReq, false);
951
}
952
953
BclNumber
954
bcl_sub(BclNumber a, BclNumber b)
955
{
956
return bcl_binary(a, b, bc_num_sub, bc_num_addReq, true);
957
}
958
959
BclNumber
960
bcl_sub_keep(BclNumber a, BclNumber b)
961
{
962
return bcl_binary(a, b, bc_num_sub, bc_num_addReq, false);
963
}
964
965
BclNumber
966
bcl_mul(BclNumber a, BclNumber b)
967
{
968
return bcl_binary(a, b, bc_num_mul, bc_num_mulReq, true);
969
}
970
971
BclNumber
972
bcl_mul_keep(BclNumber a, BclNumber b)
973
{
974
return bcl_binary(a, b, bc_num_mul, bc_num_mulReq, false);
975
}
976
977
BclNumber
978
bcl_div(BclNumber a, BclNumber b)
979
{
980
return bcl_binary(a, b, bc_num_div, bc_num_divReq, true);
981
}
982
983
BclNumber
984
bcl_div_keep(BclNumber a, BclNumber b)
985
{
986
return bcl_binary(a, b, bc_num_div, bc_num_divReq, false);
987
}
988
989
BclNumber
990
bcl_mod(BclNumber a, BclNumber b)
991
{
992
return bcl_binary(a, b, bc_num_mod, bc_num_divReq, true);
993
}
994
995
BclNumber
996
bcl_mod_keep(BclNumber a, BclNumber b)
997
{
998
return bcl_binary(a, b, bc_num_mod, bc_num_divReq, false);
999
}
1000
1001
BclNumber
1002
bcl_pow(BclNumber a, BclNumber b)
1003
{
1004
return bcl_binary(a, b, bc_num_pow, bc_num_powReq, true);
1005
}
1006
1007
BclNumber
1008
bcl_pow_keep(BclNumber a, BclNumber b)
1009
{
1010
return bcl_binary(a, b, bc_num_pow, bc_num_powReq, false);
1011
}
1012
1013
BclNumber
1014
bcl_lshift(BclNumber a, BclNumber b)
1015
{
1016
return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq, true);
1017
}
1018
1019
BclNumber
1020
bcl_lshift_keep(BclNumber a, BclNumber b)
1021
{
1022
return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq, false);
1023
}
1024
1025
BclNumber
1026
bcl_rshift(BclNumber a, BclNumber b)
1027
{
1028
return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq, true);
1029
}
1030
1031
BclNumber
1032
bcl_rshift_keep(BclNumber a, BclNumber b)
1033
{
1034
return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq, false);
1035
}
1036
1037
static BclNumber
1038
bcl_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
1061
err:
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
1074
BclNumber
1075
bcl_sqrt(BclNumber a)
1076
{
1077
return bcl_sqrt_helper(a, true);
1078
}
1079
1080
BclNumber
1081
bcl_sqrt_keep(BclNumber a)
1082
{
1083
return bcl_sqrt_helper(a, false);
1084
}
1085
1086
static BclError
1087
bcl_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
1129
err:
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
1163
BclError
1164
bcl_divmod(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d)
1165
{
1166
return bcl_divmod_helper(a, b, c, d, true);
1167
}
1168
1169
BclError
1170
bcl_divmod_keep(BclNumber a, BclNumber b, BclNumber* c, BclNumber* d)
1171
{
1172
return bcl_divmod_helper(a, b, c, d, false);
1173
}
1174
1175
static BclNumber
1176
bcl_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
1220
err:
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
1236
BclNumber
1237
bcl_modexp(BclNumber a, BclNumber b, BclNumber c)
1238
{
1239
return bcl_modexp_helper(a, b, c, true);
1240
}
1241
1242
BclNumber
1243
bcl_modexp_keep(BclNumber a, BclNumber b, BclNumber c)
1244
{
1245
return bcl_modexp_helper(a, b, c, false);
1246
}
1247
1248
ssize_t
1249
bcl_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
1272
void
1273
bcl_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
1292
void
1293
bcl_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
1312
BclNumber
1313
bcl_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
1355
err:
1356
1357
BC_FUNC_FOOTER(vm, e);
1358
BC_MAYBE_SETUP(ctxt, e, n, idx);
1359
1360
return idx;
1361
}
1362
1363
static char*
1364
bcl_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
1395
err:
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
1408
char*
1409
bcl_string(BclNumber n)
1410
{
1411
return bcl_string_helper(n, true);
1412
}
1413
1414
char*
1415
bcl_string_keep(BclNumber n)
1416
{
1417
return bcl_string_helper(n, false);
1418
}
1419
1420
#if BC_ENABLE_EXTRA_MATH
1421
1422
static BclNumber
1423
bcl_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
1452
err:
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
1466
BclNumber
1467
bcl_irand(BclNumber a)
1468
{
1469
return bcl_irand_helper(a, true);
1470
}
1471
1472
BclNumber
1473
bcl_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
*/
1484
static void
1485
bcl_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
1516
err:
1517
1518
bc_num_free(&pow);
1519
BC_LONGJMP_CONT(vm);
1520
}
1521
1522
BclNumber
1523
bcl_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
1543
err:
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
*/
1558
static void
1559
bcl_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
1579
err:
1580
1581
bc_num_free(&fr);
1582
bc_num_free(&ir);
1583
BC_LONGJMP_CONT(vm);
1584
}
1585
1586
static BclNumber
1587
bcl_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
1615
err:
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
1629
BclNumber
1630
bcl_ifrand(BclNumber a, size_t places)
1631
{
1632
return bcl_ifrand_helper(a, places, true);
1633
}
1634
1635
BclNumber
1636
bcl_ifrand_keep(BclNumber a, size_t places)
1637
{
1638
return bcl_ifrand_helper(a, places, false);
1639
}
1640
1641
static BclError
1642
bcl_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
1662
err:
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
1675
BclError
1676
bcl_rand_seedWithNum(BclNumber n)
1677
{
1678
return bcl_rand_seedWithNum_helper(n, true);
1679
}
1680
1681
BclError
1682
bcl_rand_seedWithNum_keep(BclNumber n)
1683
{
1684
return bcl_rand_seedWithNum_helper(n, false);
1685
}
1686
1687
BclError
1688
bcl_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
1707
err:
1708
1709
BC_FUNC_FOOTER(vm, e);
1710
1711
return e;
1712
}
1713
1714
void
1715
bcl_rand_reseed(void)
1716
{
1717
BcVm* vm = bcl_getspecific();
1718
1719
bc_rand_srand(bc_vec_top(&vm->rng.v));
1720
}
1721
1722
BclNumber
1723
bcl_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
1741
err:
1742
1743
BC_FUNC_FOOTER(vm, e);
1744
BC_MAYBE_SETUP(ctxt, e, n, idx);
1745
1746
return idx;
1747
}
1748
1749
BclRandInt
1750
bcl_rand_int(void)
1751
{
1752
BcVm* vm = bcl_getspecific();
1753
1754
return (BclRandInt) bc_rand_int(&vm->rng);
1755
}
1756
1757
BclRandInt
1758
bcl_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
1770