1 /* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2018-2024 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