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