1 /* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2018-2021 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 static void bcl_num_destruct(void *num); 49 50 void bcl_handleSignal(void) { 51 52 // Signal already in flight, or bc is not executing. 53 if (vm.sig || !vm.running) return; 54 55 vm.sig = 1; 56 57 assert(vm.jmp_bufs.len); 58 59 if (!vm.sig_lock) BC_VM_JMP; 60 } 61 62 bool bcl_running(void) { 63 return vm.running != 0; 64 } 65 66 BclError bcl_init(void) { 67 68 BclError e = BCL_ERROR_NONE; 69 70 vm.refs += 1; 71 72 if (vm.refs > 1) return e; 73 74 vm.ctxts.v = NULL; 75 vm.jmp_bufs.v = NULL; 76 vm.out.v = NULL; 77 78 vm.abrt = false; 79 80 BC_SIG_LOCK; 81 82 bc_vec_init(&vm.jmp_bufs, sizeof(sigjmp_buf), NULL); 83 84 BC_FUNC_HEADER_INIT(err); 85 86 bc_vm_init(); 87 88 bc_vec_init(&vm.ctxts, sizeof(BclContext), NULL); 89 bc_vec_init(&vm.out, sizeof(uchar), NULL); 90 91 srand((unsigned int) time(NULL)); 92 bc_rand_init(&vm.rng); 93 94 err: 95 if (BC_ERR(vm.err)) { 96 if (vm.out.v != NULL) bc_vec_free(&vm.out); 97 if (vm.jmp_bufs.v != NULL) bc_vec_free(&vm.jmp_bufs); 98 if (vm.ctxts.v != NULL) bc_vec_free(&vm.ctxts); 99 } 100 101 BC_FUNC_FOOTER_UNLOCK(e); 102 103 assert(!vm.running && !vm.sig && !vm.sig_lock); 104 105 return e; 106 } 107 108 BclError bcl_pushContext(BclContext ctxt) { 109 110 BclError e = BCL_ERROR_NONE; 111 112 BC_FUNC_HEADER_LOCK(err); 113 114 bc_vec_push(&vm.ctxts, &ctxt); 115 116 err: 117 BC_FUNC_FOOTER_UNLOCK(e); 118 return e; 119 } 120 121 void bcl_popContext(void) { 122 if (vm.ctxts.len) bc_vec_pop(&vm.ctxts); 123 } 124 125 BclContext bcl_context(void) { 126 if (!vm.ctxts.len) return NULL; 127 return *((BclContext*) bc_vec_top(&vm.ctxts)); 128 } 129 130 void bcl_free(void) { 131 132 vm.refs -= 1; 133 134 if (vm.refs) return; 135 136 BC_SIG_LOCK; 137 138 #ifndef NDEBUG 139 bc_rand_free(&vm.rng); 140 bc_vec_free(&vm.out); 141 142 { 143 size_t i; 144 145 for (i = 0; i < vm.ctxts.len; ++i) { 146 BclContext ctxt = *((BclContext*) bc_vec_item(&vm.ctxts, i)); 147 bcl_ctxt_free(ctxt); 148 } 149 } 150 151 bc_vec_free(&vm.ctxts); 152 #endif // NDEBUG 153 154 bc_vm_atexit(); 155 156 BC_SIG_UNLOCK; 157 158 memset(&vm, 0, sizeof(BcVm)); 159 160 assert(!vm.running && !vm.sig && !vm.sig_lock); 161 } 162 163 void bcl_gc(void) { 164 bc_vm_freeTemps(); 165 vm.temps.len = 0; 166 } 167 168 bool bcl_abortOnFatalError(void) { 169 return vm.abrt; 170 } 171 172 void bcl_setAbortOnFatalError(bool abrt) { 173 vm.abrt = abrt; 174 } 175 176 BclContext bcl_ctxt_create(void) { 177 178 BclContext ctxt = NULL; 179 180 BC_FUNC_HEADER_LOCK(err); 181 182 ctxt = bc_vm_malloc(sizeof(BclCtxt)); 183 184 bc_vec_init(&ctxt->nums, sizeof(BcNum), bcl_num_destruct); 185 bc_vec_init(&ctxt->free_nums, sizeof(BclNumber), NULL); 186 187 ctxt->scale = 0; 188 ctxt->ibase = 10; 189 ctxt->obase= 10; 190 191 err: 192 if (BC_ERR(vm.err && ctxt != NULL)) { 193 if (ctxt->nums.v != NULL) bc_vec_free(&ctxt->nums); 194 free(ctxt); 195 ctxt = NULL; 196 } 197 198 BC_FUNC_FOOTER_NO_ERR; 199 200 assert(!vm.running && !vm.sig && !vm.sig_lock); 201 202 return ctxt; 203 } 204 205 void bcl_ctxt_free(BclContext ctxt) { 206 BC_SIG_LOCK; 207 bc_vec_free(&ctxt->free_nums); 208 bc_vec_free(&ctxt->nums); 209 free(ctxt); 210 BC_SIG_UNLOCK; 211 } 212 213 void bcl_ctxt_freeNums(BclContext ctxt) { 214 bc_vec_popAll(&ctxt->nums); 215 bc_vec_popAll(&ctxt->free_nums); 216 } 217 218 size_t bcl_ctxt_scale(BclContext ctxt) { 219 return ctxt->scale; 220 } 221 222 void bcl_ctxt_setScale(BclContext ctxt, size_t scale) { 223 ctxt->scale = scale; 224 } 225 226 size_t bcl_ctxt_ibase(BclContext ctxt) { 227 return ctxt->ibase; 228 } 229 230 void bcl_ctxt_setIbase(BclContext ctxt, size_t ibase) { 231 if (ibase < BC_NUM_MIN_BASE) ibase = BC_NUM_MIN_BASE; 232 else if (ibase > BC_NUM_MAX_IBASE) ibase = BC_NUM_MAX_IBASE; 233 ctxt->ibase = ibase; 234 } 235 236 size_t bcl_ctxt_obase(BclContext ctxt) { 237 return ctxt->obase; 238 } 239 240 void bcl_ctxt_setObase(BclContext ctxt, size_t obase) { 241 ctxt->obase = obase; 242 } 243 244 BclError bcl_err(BclNumber n) { 245 246 BclContext ctxt; 247 248 BC_CHECK_CTXT_ERR(ctxt); 249 250 if (n.i >= ctxt->nums.len) { 251 if (n.i > 0 - (size_t) BCL_ERROR_NELEMS) return (BclError) (0 - n.i); 252 else return BCL_ERROR_INVALID_NUM; 253 } 254 else return BCL_ERROR_NONE; 255 } 256 257 static BclNumber bcl_num_insert(BclContext ctxt, BcNum *restrict n) { 258 259 BclNumber idx; 260 261 if (ctxt->free_nums.len) { 262 263 BcNum *ptr; 264 265 idx = *((BclNumber*) bc_vec_top(&ctxt->free_nums)); 266 267 bc_vec_pop(&ctxt->free_nums); 268 269 ptr = bc_vec_item(&ctxt->nums, idx.i); 270 memcpy(ptr, n, sizeof(BcNum)); 271 } 272 else { 273 idx.i = ctxt->nums.len; 274 bc_vec_push(&ctxt->nums, n); 275 } 276 277 assert(!vm.running && !vm.sig && !vm.sig_lock); 278 279 return idx; 280 } 281 282 BclNumber bcl_num_create(void) { 283 284 BclError e = BCL_ERROR_NONE; 285 BcNum n; 286 BclNumber idx; 287 BclContext ctxt; 288 289 BC_CHECK_CTXT(ctxt); 290 291 BC_FUNC_HEADER_LOCK(err); 292 293 bc_vec_grow(&ctxt->nums, 1); 294 295 bc_num_init(&n, BC_NUM_DEF_SIZE); 296 297 err: 298 BC_FUNC_FOOTER_UNLOCK(e); 299 BC_MAYBE_SETUP(ctxt, e, n, idx); 300 301 assert(!vm.running && !vm.sig && !vm.sig_lock); 302 303 return idx; 304 } 305 306 static void bcl_num_dtor(BclContext ctxt, BclNumber n, BcNum *restrict num) { 307 308 BC_SIG_ASSERT_LOCKED; 309 310 assert(num != NULL && num->num != NULL); 311 312 bcl_num_destruct(num); 313 bc_vec_push(&ctxt->free_nums, &n); 314 } 315 316 void bcl_num_free(BclNumber n) { 317 318 BcNum *num; 319 BclContext ctxt; 320 321 BC_CHECK_CTXT_ASSERT(ctxt); 322 323 BC_SIG_LOCK; 324 325 assert(n.i < ctxt->nums.len); 326 327 num = BC_NUM(ctxt, n); 328 329 bcl_num_dtor(ctxt, n, num); 330 331 BC_SIG_UNLOCK; 332 } 333 334 BclError bcl_copy(BclNumber d, BclNumber s) { 335 336 BclError e = BCL_ERROR_NONE; 337 BcNum *dest, *src; 338 BclContext ctxt; 339 340 BC_CHECK_CTXT_ERR(ctxt); 341 342 BC_FUNC_HEADER_LOCK(err); 343 344 assert(d.i < ctxt->nums.len && s.i < ctxt->nums.len); 345 346 dest = BC_NUM(ctxt, d); 347 src = BC_NUM(ctxt, s); 348 349 assert(dest != NULL && src != NULL); 350 assert(dest->num != NULL && src->num != NULL); 351 352 bc_num_copy(dest, src); 353 354 err: 355 BC_FUNC_FOOTER_UNLOCK(e); 356 357 assert(!vm.running && !vm.sig && !vm.sig_lock); 358 359 return e; 360 } 361 362 BclNumber bcl_dup(BclNumber s) { 363 364 BclError e = BCL_ERROR_NONE; 365 BcNum *src, dest; 366 BclNumber idx; 367 BclContext ctxt; 368 369 BC_CHECK_CTXT(ctxt); 370 371 BC_FUNC_HEADER_LOCK(err); 372 373 bc_vec_grow(&ctxt->nums, 1); 374 375 assert(s.i < ctxt->nums.len); 376 377 src = BC_NUM(ctxt, s); 378 379 assert(src != NULL && src->num != NULL); 380 381 bc_num_clear(&dest); 382 383 bc_num_createCopy(&dest, src); 384 385 err: 386 BC_FUNC_FOOTER_UNLOCK(e); 387 BC_MAYBE_SETUP(ctxt, e, dest, idx); 388 389 assert(!vm.running && !vm.sig && !vm.sig_lock); 390 391 return idx; 392 } 393 394 static void bcl_num_destruct(void *num) { 395 396 BcNum *n = (BcNum*) num; 397 398 assert(n != NULL); 399 400 if (n->num == NULL) return; 401 402 bc_num_free(num); 403 bc_num_clear(num); 404 } 405 406 bool bcl_num_neg(BclNumber n) { 407 408 BcNum *num; 409 BclContext ctxt; 410 411 BC_CHECK_CTXT_ASSERT(ctxt); 412 413 assert(n.i < ctxt->nums.len); 414 415 num = BC_NUM(ctxt, n); 416 417 assert(num != NULL && num->num != NULL); 418 419 return BC_NUM_NEG(num) != 0; 420 } 421 422 void bcl_num_setNeg(BclNumber n, bool neg) { 423 424 BcNum *num; 425 BclContext ctxt; 426 427 BC_CHECK_CTXT_ASSERT(ctxt); 428 429 assert(n.i < ctxt->nums.len); 430 431 num = BC_NUM(ctxt, n); 432 433 assert(num != NULL && num->num != NULL); 434 435 num->rdx = BC_NUM_NEG_VAL(num, neg); 436 } 437 438 size_t bcl_num_scale(BclNumber n) { 439 440 BcNum *num; 441 BclContext ctxt; 442 443 BC_CHECK_CTXT_ASSERT(ctxt); 444 445 assert(n.i < ctxt->nums.len); 446 447 num = BC_NUM(ctxt, n); 448 449 assert(num != NULL && num->num != NULL); 450 451 return bc_num_scale(num); 452 } 453 454 BclError bcl_num_setScale(BclNumber n, size_t scale) { 455 456 BclError e = BCL_ERROR_NONE; 457 BcNum *nptr; 458 BclContext ctxt; 459 460 BC_CHECK_CTXT_ERR(ctxt); 461 462 BC_CHECK_NUM_ERR(ctxt, n); 463 464 BC_FUNC_HEADER(err); 465 466 assert(n.i < ctxt->nums.len); 467 468 nptr = BC_NUM(ctxt, n); 469 470 assert(nptr != NULL && nptr->num != NULL); 471 472 if (scale > nptr->scale) bc_num_extend(nptr, scale - nptr->scale); 473 else if (scale < nptr->scale) bc_num_truncate(nptr, nptr->scale - scale); 474 475 err: 476 BC_SIG_MAYLOCK; 477 BC_FUNC_FOOTER(e); 478 479 assert(!vm.running && !vm.sig && !vm.sig_lock); 480 481 return e; 482 } 483 484 size_t bcl_num_len(BclNumber n) { 485 486 BcNum *num; 487 BclContext ctxt; 488 489 BC_CHECK_CTXT_ASSERT(ctxt); 490 491 assert(n.i < ctxt->nums.len); 492 493 num = BC_NUM(ctxt, n); 494 495 assert(num != NULL && num->num != NULL); 496 497 return bc_num_len(num); 498 } 499 500 BclError bcl_bigdig(BclNumber n, BclBigDig *result) { 501 502 BclError e = BCL_ERROR_NONE; 503 BcNum *num; 504 BclContext ctxt; 505 506 BC_CHECK_CTXT_ERR(ctxt); 507 508 BC_FUNC_HEADER_LOCK(err); 509 510 assert(n.i < ctxt->nums.len); 511 assert(result != NULL); 512 513 num = BC_NUM(ctxt, n); 514 515 assert(num != NULL && num->num != NULL); 516 517 bc_num_bigdig(num, result); 518 519 err: 520 bcl_num_dtor(ctxt, n, num); 521 BC_FUNC_FOOTER_UNLOCK(e); 522 523 assert(!vm.running && !vm.sig && !vm.sig_lock); 524 525 return e; 526 } 527 528 BclNumber bcl_bigdig2num(BclBigDig val) { 529 530 BclError e = BCL_ERROR_NONE; 531 BcNum n; 532 BclNumber idx; 533 BclContext ctxt; 534 535 BC_CHECK_CTXT(ctxt); 536 537 BC_FUNC_HEADER_LOCK(err); 538 539 bc_vec_grow(&ctxt->nums, 1); 540 541 bc_num_createFromBigdig(&n, val); 542 543 err: 544 BC_FUNC_FOOTER_UNLOCK(e); 545 BC_MAYBE_SETUP(ctxt, e, n, idx); 546 547 assert(!vm.running && !vm.sig && !vm.sig_lock); 548 549 return idx; 550 } 551 552 static BclNumber bcl_binary(BclNumber a, BclNumber b, 553 const BcNumBinaryOp op, 554 const BcNumBinaryOpReq req) 555 { 556 BclError e = BCL_ERROR_NONE; 557 BcNum *aptr, *bptr; 558 BcNum c; 559 BclNumber idx; 560 BclContext ctxt; 561 562 BC_CHECK_CTXT(ctxt); 563 564 BC_CHECK_NUM(ctxt, a); 565 BC_CHECK_NUM(ctxt, b); 566 567 BC_FUNC_HEADER_LOCK(err); 568 569 bc_vec_grow(&ctxt->nums, 1); 570 571 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len); 572 573 aptr = BC_NUM(ctxt, a); 574 bptr = BC_NUM(ctxt, b); 575 576 assert(aptr != NULL && bptr != NULL); 577 assert(aptr->num != NULL && bptr->num != NULL); 578 579 bc_num_clear(&c); 580 581 bc_num_init(&c, req(aptr, bptr, ctxt->scale)); 582 583 BC_SIG_UNLOCK; 584 585 op(aptr, bptr, &c, ctxt->scale); 586 587 err: 588 BC_SIG_MAYLOCK; 589 bcl_num_dtor(ctxt, a, aptr); 590 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); 591 BC_FUNC_FOOTER(e); 592 BC_MAYBE_SETUP(ctxt, e, c, idx); 593 594 assert(!vm.running && !vm.sig && !vm.sig_lock); 595 596 return idx; 597 } 598 599 BclNumber bcl_add(BclNumber a, BclNumber b) { 600 return bcl_binary(a, b, bc_num_add, bc_num_addReq); 601 } 602 603 BclNumber bcl_sub(BclNumber a, BclNumber b) { 604 return bcl_binary(a, b, bc_num_sub, bc_num_addReq); 605 } 606 607 BclNumber bcl_mul(BclNumber a, BclNumber b) { 608 return bcl_binary(a, b, bc_num_mul, bc_num_mulReq); 609 } 610 611 BclNumber bcl_div(BclNumber a, BclNumber b) { 612 return bcl_binary(a, b, bc_num_div, bc_num_divReq); 613 } 614 615 BclNumber bcl_mod(BclNumber a, BclNumber b) { 616 return bcl_binary(a, b, bc_num_mod, bc_num_divReq); 617 } 618 619 BclNumber bcl_pow(BclNumber a, BclNumber b) { 620 return bcl_binary(a, b, bc_num_pow, bc_num_powReq); 621 } 622 623 BclNumber bcl_lshift(BclNumber a, BclNumber b) { 624 return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq); 625 } 626 627 BclNumber bcl_rshift(BclNumber a, BclNumber b) { 628 return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq); 629 } 630 631 BclNumber bcl_sqrt(BclNumber a) { 632 633 BclError e = BCL_ERROR_NONE; 634 BcNum *aptr; 635 BcNum b; 636 BclNumber idx; 637 BclContext ctxt; 638 639 BC_CHECK_CTXT(ctxt); 640 641 BC_CHECK_NUM(ctxt, a); 642 643 BC_FUNC_HEADER(err); 644 645 bc_vec_grow(&ctxt->nums, 1); 646 647 assert(a.i < ctxt->nums.len); 648 649 aptr = BC_NUM(ctxt, a); 650 651 bc_num_sqrt(aptr, &b, ctxt->scale); 652 653 err: 654 BC_SIG_MAYLOCK; 655 bcl_num_dtor(ctxt, a, aptr); 656 BC_FUNC_FOOTER(e); 657 BC_MAYBE_SETUP(ctxt, e, b, idx); 658 659 assert(!vm.running && !vm.sig && !vm.sig_lock); 660 661 return idx; 662 } 663 664 BclError bcl_divmod(BclNumber a, BclNumber b, BclNumber *c, BclNumber *d) { 665 666 BclError e = BCL_ERROR_NONE; 667 size_t req; 668 BcNum *aptr, *bptr; 669 BcNum cnum, dnum; 670 BclContext ctxt; 671 672 BC_CHECK_CTXT_ERR(ctxt); 673 674 BC_CHECK_NUM_ERR(ctxt, a); 675 BC_CHECK_NUM_ERR(ctxt, b); 676 677 BC_FUNC_HEADER_LOCK(err); 678 679 bc_vec_grow(&ctxt->nums, 2); 680 681 assert(c != NULL && d != NULL); 682 683 aptr = BC_NUM(ctxt, a); 684 bptr = BC_NUM(ctxt, b); 685 686 assert(aptr != NULL && bptr != NULL); 687 assert(aptr->num != NULL && bptr->num != NULL); 688 689 bc_num_clear(&cnum); 690 bc_num_clear(&dnum); 691 692 req = bc_num_divReq(aptr, bptr, ctxt->scale); 693 694 bc_num_init(&cnum, req); 695 bc_num_init(&dnum, req); 696 697 BC_SIG_UNLOCK; 698 699 bc_num_divmod(aptr, bptr, &cnum, &dnum, ctxt->scale); 700 701 err: 702 BC_SIG_MAYLOCK; 703 704 bcl_num_dtor(ctxt, a, aptr); 705 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); 706 707 if (BC_ERR(vm.err)) { 708 if (cnum.num != NULL) bc_num_free(&cnum); 709 if (dnum.num != NULL) bc_num_free(&dnum); 710 c->i = 0 - (size_t) BCL_ERROR_INVALID_NUM; 711 d->i = c->i; 712 BC_FUNC_FOOTER(e); 713 } 714 else { 715 BC_FUNC_FOOTER(e); 716 *c = bcl_num_insert(ctxt, &cnum); 717 *d = bcl_num_insert(ctxt, &dnum); 718 } 719 720 assert(!vm.running && !vm.sig && !vm.sig_lock); 721 722 return e; 723 } 724 725 BclNumber bcl_modexp(BclNumber a, BclNumber b, BclNumber c) { 726 727 BclError e = BCL_ERROR_NONE; 728 size_t req; 729 BcNum *aptr, *bptr, *cptr; 730 BcNum d; 731 BclNumber idx; 732 BclContext ctxt; 733 734 BC_CHECK_CTXT(ctxt); 735 736 BC_CHECK_NUM(ctxt, a); 737 BC_CHECK_NUM(ctxt, b); 738 BC_CHECK_NUM(ctxt, c); 739 740 BC_FUNC_HEADER_LOCK(err); 741 742 bc_vec_grow(&ctxt->nums, 1); 743 744 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len); 745 assert(c.i < ctxt->nums.len); 746 747 aptr = BC_NUM(ctxt, a); 748 bptr = BC_NUM(ctxt, b); 749 cptr = BC_NUM(ctxt, c); 750 751 assert(aptr != NULL && bptr != NULL && cptr != NULL); 752 assert(aptr->num != NULL && bptr->num != NULL && cptr->num != NULL); 753 754 bc_num_clear(&d); 755 756 req = bc_num_divReq(aptr, cptr, 0); 757 758 bc_num_init(&d, req); 759 760 BC_SIG_UNLOCK; 761 762 bc_num_modexp(aptr, bptr, cptr, &d); 763 764 err: 765 BC_SIG_MAYLOCK; 766 767 bcl_num_dtor(ctxt, a, aptr); 768 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr); 769 if (c.i != a.i && c.i != b.i) bcl_num_dtor(ctxt, c, cptr); 770 771 BC_FUNC_FOOTER(e); 772 BC_MAYBE_SETUP(ctxt, e, d, idx); 773 774 assert(!vm.running && !vm.sig && !vm.sig_lock); 775 776 return idx; 777 } 778 779 ssize_t bcl_cmp(BclNumber a, BclNumber b) { 780 781 BcNum *aptr, *bptr; 782 BclContext ctxt; 783 784 BC_CHECK_CTXT_ASSERT(ctxt); 785 786 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len); 787 788 aptr = BC_NUM(ctxt, a); 789 bptr = BC_NUM(ctxt, b); 790 791 assert(aptr != NULL && bptr != NULL); 792 assert(aptr->num != NULL && bptr->num != NULL); 793 794 return bc_num_cmp(aptr, bptr); 795 } 796 797 void bcl_zero(BclNumber n) { 798 799 BcNum *nptr; 800 BclContext ctxt; 801 802 BC_CHECK_CTXT_ASSERT(ctxt); 803 804 assert(n.i < ctxt->nums.len); 805 806 nptr = BC_NUM(ctxt, n); 807 808 assert(nptr != NULL && nptr->num != NULL); 809 810 bc_num_zero(nptr); 811 } 812 813 void bcl_one(BclNumber n) { 814 815 BcNum *nptr; 816 BclContext ctxt; 817 818 BC_CHECK_CTXT_ASSERT(ctxt); 819 820 assert(n.i < ctxt->nums.len); 821 822 nptr = BC_NUM(ctxt, n); 823 824 assert(nptr != NULL && nptr->num != NULL); 825 826 bc_num_one(nptr); 827 } 828 829 BclNumber bcl_parse(const char *restrict val) { 830 831 BclError e = BCL_ERROR_NONE; 832 BcNum n; 833 BclNumber idx; 834 BclContext ctxt; 835 bool neg; 836 837 BC_CHECK_CTXT(ctxt); 838 839 BC_FUNC_HEADER_LOCK(err); 840 841 bc_vec_grow(&ctxt->nums, 1); 842 843 assert(val != NULL); 844 845 neg = (val[0] == '-'); 846 847 if (neg) val += 1; 848 849 if (!bc_num_strValid(val)) { 850 vm.err = BCL_ERROR_PARSE_INVALID_STR; 851 goto err; 852 } 853 854 bc_num_clear(&n); 855 856 bc_num_init(&n, BC_NUM_DEF_SIZE); 857 858 BC_SIG_UNLOCK; 859 860 bc_num_parse(&n, val, (BcBigDig) ctxt->ibase); 861 862 n.rdx = BC_NUM_NEG_VAL_NP(n, neg); 863 864 err: 865 BC_SIG_MAYLOCK; 866 BC_FUNC_FOOTER(e); 867 BC_MAYBE_SETUP(ctxt, e, n, idx); 868 869 assert(!vm.running && !vm.sig && !vm.sig_lock); 870 871 return idx; 872 } 873 874 char* bcl_string(BclNumber n) { 875 876 BcNum *nptr; 877 char *str = NULL; 878 BclContext ctxt; 879 880 BC_CHECK_CTXT_ASSERT(ctxt); 881 882 if (BC_ERR(n.i >= ctxt->nums.len)) return str; 883 884 BC_FUNC_HEADER(err); 885 886 assert(n.i < ctxt->nums.len); 887 888 nptr = BC_NUM(ctxt, n); 889 890 assert(nptr != NULL && nptr->num != NULL); 891 892 bc_vec_popAll(&vm.out); 893 894 bc_num_print(nptr, (BcBigDig) ctxt->obase, false); 895 bc_vec_pushByte(&vm.out, '\0'); 896 897 BC_SIG_LOCK; 898 str = bc_vm_strdup(vm.out.v); 899 900 err: 901 bcl_num_dtor(ctxt, n, nptr); 902 903 BC_FUNC_FOOTER_NO_ERR; 904 905 assert(!vm.running && !vm.sig && !vm.sig_lock); 906 907 return str; 908 } 909 910 BclNumber bcl_irand(BclNumber a) { 911 912 BclError e = BCL_ERROR_NONE; 913 BcNum *aptr; 914 BcNum b; 915 BclNumber idx; 916 BclContext ctxt; 917 918 BC_CHECK_CTXT(ctxt); 919 920 BC_CHECK_NUM(ctxt, a); 921 922 BC_FUNC_HEADER_LOCK(err); 923 924 bc_vec_grow(&ctxt->nums, 1); 925 926 assert(a.i < ctxt->nums.len); 927 928 aptr = BC_NUM(ctxt, a); 929 930 assert(aptr != NULL && aptr->num != NULL); 931 932 bc_num_clear(&b); 933 934 bc_num_init(&b, BC_NUM_DEF_SIZE); 935 936 BC_SIG_UNLOCK; 937 938 bc_num_irand(aptr, &b, &vm.rng); 939 940 err: 941 BC_SIG_MAYLOCK; 942 bcl_num_dtor(ctxt, a, aptr); 943 BC_FUNC_FOOTER(e); 944 BC_MAYBE_SETUP(ctxt, e, b, idx); 945 946 assert(!vm.running && !vm.sig && !vm.sig_lock); 947 948 return idx; 949 } 950 951 static void bcl_frandHelper(BcNum *restrict b, size_t places) { 952 953 BcNum exp, pow, ten; 954 BcDig exp_digs[BC_NUM_BIGDIG_LOG10]; 955 BcDig ten_digs[BC_NUM_BIGDIG_LOG10]; 956 957 bc_num_setup(&exp, exp_digs, BC_NUM_BIGDIG_LOG10); 958 bc_num_setup(&ten, ten_digs, BC_NUM_BIGDIG_LOG10); 959 960 ten.num[0] = 10; 961 ten.len = 1; 962 963 bc_num_bigdig2num(&exp, (BcBigDig) places); 964 965 bc_num_clear(&pow); 966 967 BC_SIG_LOCK; 968 969 BC_SETJMP_LOCKED(err); 970 971 bc_num_init(&pow, bc_num_powReq(&ten, &exp, 0)); 972 973 BC_SIG_UNLOCK; 974 975 bc_num_pow(&ten, &exp, &pow, 0); 976 977 bc_num_irand(&pow, b, &vm.rng); 978 979 bc_num_shiftRight(b, places); 980 981 err: 982 BC_SIG_MAYLOCK; 983 bc_num_free(&pow); 984 BC_LONGJMP_CONT; 985 } 986 987 BclNumber bcl_frand(size_t places) { 988 989 BclError e = BCL_ERROR_NONE; 990 BcNum n; 991 BclNumber idx; 992 BclContext ctxt; 993 994 BC_CHECK_CTXT(ctxt); 995 996 BC_FUNC_HEADER_LOCK(err); 997 998 bc_vec_grow(&ctxt->nums, 1); 999 1000 bc_num_clear(&n); 1001 1002 bc_num_init(&n, BC_NUM_DEF_SIZE); 1003 1004 BC_SIG_UNLOCK; 1005 1006 bcl_frandHelper(&n, places); 1007 1008 err: 1009 BC_SIG_MAYLOCK; 1010 BC_FUNC_FOOTER(e); 1011 BC_MAYBE_SETUP(ctxt, e, n, idx); 1012 1013 assert(!vm.running && !vm.sig && !vm.sig_lock); 1014 1015 return idx; 1016 } 1017 1018 static void bcl_ifrandHelper(BcNum *restrict a, BcNum *restrict b, 1019 size_t places) 1020 { 1021 BcNum ir, fr; 1022 1023 bc_num_clear(&ir); 1024 bc_num_clear(&fr); 1025 1026 BC_SIG_LOCK; 1027 1028 BC_SETJMP_LOCKED(err); 1029 1030 bc_num_init(&ir, BC_NUM_DEF_SIZE); 1031 bc_num_init(&fr, BC_NUM_DEF_SIZE); 1032 1033 BC_SIG_UNLOCK; 1034 1035 bc_num_irand(a, &ir, &vm.rng); 1036 bcl_frandHelper(&fr, places); 1037 1038 bc_num_add(&ir, &fr, b, 0); 1039 1040 err: 1041 BC_SIG_MAYLOCK; 1042 bc_num_free(&fr); 1043 bc_num_free(&ir); 1044 BC_LONGJMP_CONT; 1045 } 1046 1047 BclNumber bcl_ifrand(BclNumber a, size_t places) { 1048 1049 BclError e = BCL_ERROR_NONE; 1050 BcNum *aptr; 1051 BcNum b; 1052 BclNumber idx; 1053 BclContext ctxt; 1054 1055 BC_CHECK_CTXT(ctxt); 1056 1057 BC_CHECK_NUM(ctxt, a); 1058 1059 BC_FUNC_HEADER_LOCK(err); 1060 1061 bc_vec_grow(&ctxt->nums, 1); 1062 1063 assert(a.i < ctxt->nums.len); 1064 1065 aptr = BC_NUM(ctxt, a); 1066 1067 assert(aptr != NULL && aptr->num != NULL); 1068 1069 bc_num_clear(&b); 1070 1071 bc_num_init(&b, BC_NUM_DEF_SIZE); 1072 1073 BC_SIG_UNLOCK; 1074 1075 bcl_ifrandHelper(aptr, &b, places); 1076 1077 err: 1078 BC_SIG_MAYLOCK; 1079 bcl_num_dtor(ctxt, a, aptr); 1080 BC_FUNC_FOOTER(e); 1081 BC_MAYBE_SETUP(ctxt, e, b, idx); 1082 1083 assert(!vm.running && !vm.sig && !vm.sig_lock); 1084 1085 return idx; 1086 } 1087 1088 BclError bcl_rand_seedWithNum(BclNumber n) { 1089 1090 BclError e = BCL_ERROR_NONE; 1091 BcNum *nptr; 1092 BclContext ctxt; 1093 1094 BC_CHECK_CTXT_ERR(ctxt); 1095 1096 BC_CHECK_NUM_ERR(ctxt, n); 1097 1098 BC_FUNC_HEADER(err); 1099 1100 assert(n.i < ctxt->nums.len); 1101 1102 nptr = BC_NUM(ctxt, n); 1103 1104 assert(nptr != NULL && nptr->num != NULL); 1105 1106 bc_num_rng(nptr, &vm.rng); 1107 1108 err: 1109 BC_SIG_MAYLOCK; 1110 BC_FUNC_FOOTER(e); 1111 1112 assert(!vm.running && !vm.sig && !vm.sig_lock); 1113 1114 return e; 1115 } 1116 1117 BclError bcl_rand_seed(unsigned char seed[BC_SEED_SIZE]) { 1118 1119 BclError e = BCL_ERROR_NONE; 1120 size_t i; 1121 ulong vals[BC_SEED_ULONGS]; 1122 1123 BC_FUNC_HEADER(err); 1124 1125 for (i = 0; i < BC_SEED_SIZE; ++i) { 1126 ulong val = ((ulong) seed[i]) << (((ulong) CHAR_BIT) * 1127 (i % sizeof(ulong))); 1128 vals[i / sizeof(long)] |= val; 1129 } 1130 1131 bc_rand_seed(&vm.rng, vals[0], vals[1], vals[2], vals[3]); 1132 1133 err: 1134 BC_SIG_MAYLOCK; 1135 BC_FUNC_FOOTER(e); 1136 return e; 1137 } 1138 1139 void bcl_rand_reseed(void) { 1140 bc_rand_srand(bc_vec_top(&vm.rng.v)); 1141 } 1142 1143 BclNumber bcl_rand_seed2num(void) { 1144 1145 BclError e = BCL_ERROR_NONE; 1146 BcNum n; 1147 BclNumber idx; 1148 BclContext ctxt; 1149 1150 BC_CHECK_CTXT(ctxt); 1151 1152 BC_FUNC_HEADER_LOCK(err); 1153 1154 bc_num_clear(&n); 1155 1156 bc_num_init(&n, BC_NUM_DEF_SIZE); 1157 1158 BC_SIG_UNLOCK; 1159 1160 bc_num_createFromRNG(&n, &vm.rng); 1161 1162 err: 1163 BC_SIG_MAYLOCK; 1164 BC_FUNC_FOOTER(e); 1165 BC_MAYBE_SETUP(ctxt, e, n, idx); 1166 1167 assert(!vm.running && !vm.sig && !vm.sig_lock); 1168 1169 return idx; 1170 } 1171 1172 BclRandInt bcl_rand_int(void) { 1173 return (BclRandInt) bc_rand_int(&vm.rng); 1174 } 1175 1176 BclRandInt bcl_rand_bounded(BclRandInt bound) { 1177 if (bound <= 1) return 0; 1178 return (BclRandInt) bc_rand_bounded(&vm.rng, (BcRand) bound); 1179 } 1180 1181 #endif // BC_ENABLE_LIBRARY 1182