/* This file was generated by "mtxrun --script "mtx-wtoc.lua" from the metapost cweb files but now maintained as C file. */ /* We cannot predefine (share) as much as we like because some numbers (constants) depend on the precission. Of course sharing doesn't really save much, it is more about abstraction and the (future) posibility to fetch some of these properties from the engine (as we do with \TEX). */ # include "mpmathdecimal.h" # define DECNUMDIGITS 1000 # include "decNumber.h" # define E_STRING "2.7182818284590452353602874713526624977572470936999595749669676277240766303535" # define PI_STRING "3.1415926535897932384626433832795028841971693993751058209749445923078164062862" # define EL_GORDO_STRING "1E1000000" # define NEGATIVE_EL_GORDO_STRING "-1E1000000" # define WARNING_LIMIT_STRING "1E1000000" # define mp_fraction_multiplier 4096 # define mp_angle_multiplier 16 # define mp_epsilon pow(2.0,-173.0) # define mp_epsilonf pow(2.0,-52.0) /* */ # define DECPRECISION_DEFAULT 34 # define FACTORIALS_CACHESIZE 50 # define too_precise(a) (a == (DEC_Inexact + DEC_Rounded)) # define too_large(a) (a & DEC_Overflow) # define odd(A) (abs(A) % 2 == 1) /* hm potrace defines this */ # define set_cur_cmd(A) mp->cur_mod_->type = (A) # define set_cur_mod(A) decNumberCopy((decNumber *) (mp->cur_mod_->data.n.data.num), A) /* This one saves some typing and also looks better: */ # define decNumberIsPositive(A) (! (decNumberIsZero(A) || decNumberIsNegative(A))) /*tex We have some more \quote {constants} that can go here so that we can use copies instead. I will do that when we have some performance critical example. In the end this only makes sense for number systems that stored numbers in allocated blobs. */ typedef struct mp_decimal_info { decContext set; decContext limitedset; decNumber zero; decNumber one; decNumber minusone; decNumber two; decNumber three; decNumber four; decNumber five; decNumber sixteen; decNumber fraction_multiplier; decNumber angle_multiplier; decNumber fraction_one; decNumber fraction_two; decNumber fraction_three; decNumber fraction_four; decNumber fraction_one_plus; decNumber fraction_half; // decNumber dp90; // decNumber dp180; // decNumber dp270; // decNumber dp360; // decNumber dm90; // decNumber dm180; // decNumber dm270; // decNumber dm360; // decNumber d16; // decNumber d64; // decNumber d256; // decNumber d4096; // decNumber d65536; decNumber pi; decNumber epsilon; decNumber EL_GORDO; decNumber negative_EL_GORDO; decNumber no_crossing; decNumber one_crossing; decNumber zero_crossing; /* */ decNumber **factorials; int last_cached_factorial; int initialized; } mp_decimal_info; static mp_decimal_info mp_decimal_data = { .factorials = NULL, .last_cached_factorial = 0, .initialized = 0, }; static void mp_decimal_make_fraction (MP mp, decNumber *ret, decNumber *p, decNumber *q); static void mp_decimal_take_fraction (MP mp, decNumber *ret, decNumber *p, decNumber *q); static void mp_decnumber_check(MP mp, decNumber *dec, decContext *context) { int test = 0; (void) mp; if (context->status & DEC_Overflow) { test = 1; context->status &= ~DEC_Overflow; } if (context->status & DEC_Underflow) { test = 1; context->status &= ~DEC_Underflow; } if (context->status & DEC_Errors) { test = 1; decNumberZero(dec); } context->status = 0; if (decNumberIsSpecial(dec)) { test = 1; if (decNumberIsInfinite(dec)) { if (decNumberIsNegative(dec)) { decNumberCopyNegate(dec, &mp_decimal_data.EL_GORDO); } else { decNumberCopy(dec, &mp_decimal_data.EL_GORDO); } } else { /* Nan */ decNumberZero(dec); } } if (decNumberIsZero(dec) && decNumberIsNegative(dec)) { decNumberZero(dec); } mp->arithmic_error = test; } /* See mpmathdouble for documentation. */ static void checkZero(decNumber *ret) { if (decNumberIsZero(ret) && decNumberIsNegative(ret)) { decNumberZero(ret); } } static int decNumberLess(decNumber *a, decNumber *b) { decNumber comp; decNumberCompare(&comp, a, b, &mp_decimal_data.set); return decNumberIsNegative(&comp); } static int decNumberGreater(decNumber *a, decNumber *b) { decNumber comp; decNumberCompare(&comp, a, b, &mp_decimal_data.set); return decNumberIsPositive(&comp); } static void decNumberFromDouble(decNumber *A, double B) { char buffer[1000]; char *c = buffer; snprintf(buffer, 1000, "%-650.325lf", B); while (*c++) { if (*c == ' ') { *c = '\0'; break; } } decNumberFromString(A, buffer, &mp_decimal_data.set); } static double decNumberToDouble(decNumber *A) { char *buffer = mp_memory_allocate(A->digits + 14); double res = 0.0; decNumberToString(A, buffer); if (sscanf(buffer, "%lf", &res)) { mp_memory_free(buffer); return res; } else { mp_memory_free(buffer); /* |mp->arithmic_error = mp_error_code(mp, 1);| */ return 0.0; } } /*tex \startformula \arctan(x) = x - \frac {x^3}{3} + \frac {x^5{5} - \frac {x^7}{7} + \ldots \stopformula This power series works well, if $x$ is close to zero ($|x|<0.5$). If x is larger, the series converges too slowly, so in order to get a smaller x, we apply the identity \startformula \arctan(x) = 2 \arctan \left (\frac {\sqrt{1 + x^2}-1} {x} \right) \stopformula twice. The first application gives us a new $x$ with $x < 1$. The second application gives us a new x with $x < 0.4142136$. For that $x$, we use the power series and multiply the result by four. */ static void decNumberAtan(decNumber *result, decNumber *x_orig, decContext *localset) { decNumber x; decNumberCopy(&x, x_orig); if (decNumberIsZero(&x)) { decNumberCopy(result, &x); } else { decNumber f, g, mx2, term; for (int i = 0; i < 2; i++) { decNumber y; decNumberMultiply(&y, &x, &x, localset); /* $ y = x^2 $ */ decNumberAdd(&y, &y, &mp_decimal_data.one, localset); /* $ y = y + 1 $ */ decNumberSquareRoot(&y, &y, localset); /* $ y = sqrt(y) $ */ decNumberSubtract(&y, &y, &mp_decimal_data.one, localset); /* $ y = y - 1 $ */ decNumberDivide(&x, &y, &x, localset); /* $ x = y / x $ */ if (decNumberIsZero(&x)) { decNumberCopy(result, &x); return; } } decNumberCopy(&f, &x); /* $ f(0) = x $ */ decNumberCopy(&g, &mp_decimal_data.one); /* $ g(0) = 1 $ */ decNumberCopy(&term, &x); /* $ term = x $ */ decNumberCopy(result, &x); /* $ sum = x $ */ decNumberMultiply(&mx2, &x, &x, localset); /* $ mx2 = x^2 $ */ decNumberMinus (&mx2, &mx2, localset); /* $ mx2 = -x^2 $ */ for (int i = 0; i < 2 * localset->digits; i++) { decNumberMultiply(&f, &f, &mx2, localset); decNumberAdd(&g, &g, &mp_decimal_data.two, localset); decNumberDivide(&term, &f, &g, localset); decNumberAdd(result, result, &term, localset); } decNumberAdd(result, result, result, localset); decNumberAdd(result, result, result, localset); } } static void decNumberAtan2(decNumber *result, decNumber *y, decNumber *x, decContext *localset) { if (! decNumberIsInfinite(x) && ! decNumberIsZero(y) && ! decNumberIsInfinite(y) && ! decNumberIsZero(x)) { decNumber temp; decNumberDivide(&temp, y, x, localset); decNumberAtan(result, &temp, localset); /* decNumberAtan doesn't quite return the values in the ranges we want for x < 0. So we need to do some correction */ if (decNumberIsNegative(x)) { if (decNumberIsNegative(y)) { decNumberSubtract(result, result, &mp_decimal_data.pi, localset); } else { decNumberAdd(result, result, &mp_decimal_data.pi, localset); } } } else { if (decNumberIsInfinite(y) && decNumberIsInfinite(x)) { /* If x and y are both inf, the result depends on the sign of x */ decNumberDivide(result, &mp_decimal_data.pi, &mp_decimal_data.four, localset); if (decNumberIsNegative(x) ) { decNumber a; decNumberFromDouble(&a, 3.0); decNumberMultiply(result, result, &a, localset); } } else if (! decNumberIsZero(y) && ! decNumberIsInfinite(x) ) { /* If y is non-zero and x is non-inf, the result is +-pi/2 */ decNumberDivide(result, &mp_decimal_data.pi, &mp_decimal_data.two, localset); } else { /* Otherwise it is +0 if x is positive, +pi if x is neg */ if (decNumberIsNegative(x)) { decNumberCopy(result, &mp_decimal_data.pi); } else { decNumberZero(result); } } /* Atan2 will be negative if y < 0 */ if (decNumberIsNegative(y)) { decNumberMinus(result, result, localset); } } } static void mp_decimal_allocate_number(MP mp, mp_number *n, mp_number_type t) { (void) mp; n->data.num = mp_memory_allocate(sizeof(decNumber)); n->type = t; decNumberZero(n->data.num); } static void mp_decimal_allocate_clone(MP mp, mp_number *n, mp_number_type t, mp_number *v) { (void) mp; n->data.num = mp_memory_allocate(sizeof(decNumber)); n->type = t; decNumberZero(n->data.num); decNumberCopy(n->data.num, v->data.num); } static void mp_decimal_allocate_abs(MP mp, mp_number *n, mp_number_type t, mp_number *v) { (void) mp; n->data.num = mp_memory_allocate(sizeof(decNumber)); n->type = t; decNumberZero(n->data.num); /* not needed */ decNumberAbs(n->data.num, v->data.num, &mp_decimal_data.set); } static void mp_decimal_allocate_div(MP mp, mp_number *n, mp_number_type t, mp_number *a, mp_number *b) { (void) mp; n->data.num = mp_memory_allocate(sizeof(decNumber)); n->type = t; decNumberZero(n->data.num); /* not needed */ decNumberDivide(n->data.num, a->data.num, b->data.num, &mp_decimal_data.set); } static void mp_decimal_allocate_mul(MP mp, mp_number *n, mp_number_type t, mp_number *a, mp_number *b) { (void) mp; n->data.num = mp_memory_allocate(sizeof(decNumber)); n->type = t; decNumberZero(n->data.num); /* not needed */ decNumberMultiply(n->data.num, a->data.num, b->data.num, &mp_decimal_data.set); } static void mp_decimal_allocate_add(MP mp, mp_number *n, mp_number_type t, mp_number *a, mp_number *b) { (void) mp; n->data.num = mp_memory_allocate(sizeof(decNumber)); n->type = t; decNumberZero(n->data.num); /* not needed */ decNumberAdd(n->data.num, a->data.num, b->data.num, &mp_decimal_data.set); } static void mp_decimal_allocate_sub(MP mp, mp_number *n, mp_number_type t, mp_number *a, mp_number *b) { (void) mp; n->data.num = mp_memory_allocate(sizeof(decNumber)); n->type = t; decNumberZero(n->data.num); /* not needed */ decNumberSubtract(n->data.num, a->data.num, b->data.num, &mp_decimal_data.set); } static void mp_decimal_allocate_double(MP mp, mp_number *n, double v) { (void) mp; n->data.num = mp_memory_allocate(sizeof(decNumber)); n->type = mp_scaled_type; decNumberZero(n->data.num); /* not needed */ decNumberFromDouble(n->data.num, v); } static void mp_decimal_free_number(MP mp, mp_number *n) { (void) mp; if (n->data.num) { mp_memory_free(n->data.num); n->data.num = NULL; n->type = mp_nan_type; } } static void mp_decimal_set_from_int(mp_number *A, mp_scaled_t B) { decNumberFromScaled(A->data.num, (int32_t) B); } static void mp_decimal_set_from_boolean(mp_number *A, mp_scaled_t B) { decNumberFromScaled(A->data.num, (int32_t) B); } static void mp_decimal_set_from_scaled(mp_number *A, mp_scaled_t B) { decNumber c; decNumberFromScaled(&c, 65536); /* can be copy */ decNumberFromScaled(A->data.num, (int32_t) B); decNumberDivide(A->data.num, A->data.num, &c, &mp_decimal_data.set); } static void mp_decimal_set_from_double(mp_number *A, double B) { decNumberFromDouble(A->data.num, B); } static void mp_decimal_set_from_addition(mp_number *A, mp_number *B, mp_number *C) { decNumberAdd(A->data.num, B->data.num, C->data.num, &mp_decimal_data.set); } static void mp_decimal_set_half_from_addition(mp_number *A, mp_number *B, mp_number *C) { decNumber c; decNumberAdd(A->data.num, B->data.num, C->data.num, &mp_decimal_data.set); decNumberFromScaled(&c, 2); /* can be copy */ decNumberDivide(A->data.num, A->data.num, &c, &mp_decimal_data.set); } static void mp_decimal_set_from_subtraction(mp_number *A, mp_number *B, mp_number *C) { decNumberSubtract(A->data.num, B->data.num, C->data.num, &mp_decimal_data.set); } static void mp_decimal_set_half_from_subtraction(mp_number *A, mp_number *B, mp_number *C) { decNumber c; decNumberSubtract(A->data.num, B->data.num, C->data.num, &mp_decimal_data.set); decNumberFromScaled(&c, 2); /* can be copy */ decNumberDivide(A->data.num, A->data.num, &c, &mp_decimal_data.set); } static void mp_decimal_set_from_div(mp_number *A, mp_number *B, mp_number *C) { decNumberDivide(A->data.num, B->data.num, C->data.num, &mp_decimal_data.set); } static void mp_decimal_set_from_mul(mp_number *A, mp_number *B, mp_number *C) { decNumberMultiply(A->data.num, B->data.num, C->data.num, &mp_decimal_data.set); } static void mp_decimal_set_from_int_div(mp_number *A, mp_number *B, mp_scaled_t C) { decNumber c; decNumberFromScaled(&c, (int32_t) C); decNumberDivide(A->data.num, B->data.num, &c, &mp_decimal_data.set); } static void mp_decimal_set_from_int_mul(mp_number *A, mp_number *B, mp_scaled_t C) { decNumber c; decNumberFromScaled(&c, (int32_t) C); decNumberMultiply(A->data.num, B->data.num, &c, &mp_decimal_data.set); } static void mp_decimal_set_from_of_the_way(MP mp, mp_number *A, mp_number *t, mp_number *B, mp_number *C) { decNumber c; decNumber r1; decNumberSubtract(&c, B->data.num, C->data.num, &mp_decimal_data.set); mp_decimal_take_fraction(mp, &r1, &c, t->data.num); decNumberSubtract(A->data.num, B->data.num, &r1, &mp_decimal_data.set); mp_decnumber_check(mp, A->data.num, &mp_decimal_data.set); } static void mp_decimal_negate(mp_number *A) { decNumberCopyNegate(A->data.num, A->data.num); checkZero(A->data.num); } static void mp_decimal_add(mp_number *A, mp_number *B) { decNumberAdd(A->data.num, A->data.num, B->data.num, &mp_decimal_data.set); } static void mp_decimal_subtract(mp_number *A, mp_number *B) { decNumberSubtract(A->data.num, A->data.num, B->data.num, &mp_decimal_data.set); } static void mp_decimal_half(mp_number *A) { decNumber c; decNumberFromScaled(&c, 2); /* can be copy */ decNumberDivide(A->data.num, A->data.num, &c, &mp_decimal_data.set); } static void mp_decimal_double(mp_number *A) { decNumber c; decNumberFromScaled(&c, 2); /* can be copy */ decNumberMultiply(A->data.num, A->data.num, &c, &mp_decimal_data.set); } static void mp_decimal_add_scaled(mp_number *A, mp_scaled_t B) { decNumber b, c; decNumberFromScaled(&c, 65536); /* can be copy */ decNumberFromScaled(&b, (int32_t) B); decNumberDivide(&b, &b, &c, &mp_decimal_data.set); decNumberAdd(A->data.num, A->data.num, &b, &mp_decimal_data.set); } static void mp_decimal_multiply_int(mp_number *A, mp_scaled_t B) { decNumber b; decNumberFromScaled(&b, (int32_t) B); decNumberMultiply(A->data.num, A->data.num, &b, &mp_decimal_data.set); } static void mp_decimal_divide_int(mp_number *A, mp_scaled_t B) { decNumber b; decNumberFromScaled(&b, (int32_t) B); decNumberDivide(A->data.num, A->data.num, &b, &mp_decimal_data.set); } static void mp_decimal_abs(mp_number *A) { decNumberAbs(A->data.num, A->data.num, &mp_decimal_data.set); } static void mp_decimal_clone(mp_number *A, mp_number *B) { decNumberCopy(A->data.num, B->data.num); } static void mp_decimal_negated_clone(mp_number *A, mp_number *B) { decNumberCopyNegate(A->data.num, B->data.num); checkZero(A->data.num); } static void mp_decimal_abs_clone(mp_number *A, mp_number *B) { decNumberAbs(A->data.num, B->data.num, &mp_decimal_data.set); } static void mp_decimal_swap(mp_number *A, mp_number *B) { decNumber swap_tmp; decNumberCopy(&swap_tmp, A->data.num); decNumberCopy(A->data.num, B->data.num); decNumberCopy(B->data.num, &swap_tmp); } static void mp_decimal_fraction_to_scaled(mp_number *A) { A->type = mp_scaled_type; decNumberDivide(A->data.num, A->data.num, &mp_decimal_data.fraction_multiplier, &mp_decimal_data.set); } static void mp_decimal_angle_to_scaled(mp_number *A) { A->type = mp_scaled_type; decNumberDivide(A->data.num, A->data.num, &mp_decimal_data.angle_multiplier, &mp_decimal_data.set); } static void mp_decimal_scaled_to_fraction(mp_number *A) { A->type = mp_fraction_type; decNumberMultiply(A->data.num, A->data.num, &mp_decimal_data.fraction_multiplier, &mp_decimal_data.set); } static void mp_decimal_scaled_to_angle(mp_number *A) { A->type = mp_angle_type; decNumberMultiply(A->data.num, A->data.num, &mp_decimal_data.angle_multiplier, &mp_decimal_data.set); } static mp_scaled_t mp_decimal_to_scaled(mp_number *A) { mp_scaled_t result; decNumber corrected; decNumberFromScaled(&corrected, 65536); /* can be copy */ decNumberMultiply(&corrected, &corrected, A->data.num, &mp_decimal_data.set); decNumberReduce(&corrected, &corrected, &mp_decimal_data.set); result = mpscaledround(decNumberToDouble(&corrected)); return result; } static mp_scaled_t mp_decimal_to_int(mp_number *A) { mp_scaled_t result; mp_decimal_data.set.status = 0; result = decNumberToScaled(A->data.num, &mp_decimal_data.set); if (mp_decimal_data.set.status == DEC_Invalid_operation) { mp_decimal_data.set.status = 0; /* |mp->arithmic_error = mp_error_code(mp, 2);| */ return 0; } else { return result; } } static mp_scaled_t mp_decimal_to_boolean(mp_number *A) { mp_scaled_t result; mp_decimal_data.set.status = 0; result = decNumberToScaled(A->data.num, &mp_decimal_data.set); if (mp_decimal_data.set.status == DEC_Invalid_operation) { mp_decimal_data.set.status = 0; /* |mp->arithmic_error = mp_error_code(mp, 3);| */ return 0; } else { return result; } } static double mp_decimal_to_double(mp_number *A) { char *buffer = mp_memory_allocate((size_t) ((decNumber *) A->data.num)->digits + 14); double res = 0.0; decNumberToString(A->data.num, buffer); if (sscanf(buffer, "%lf", &res)) { mp_memory_free(buffer); return res; } else { mp_memory_free(buffer); /* |mp->arithmic_error = mp_error_code(mp, 4);| */ return 0.0; } } static int mp_decimal_odd(mp_number *A) { decNumber r1, r2; decNumberAbs(&r1, A->data.num, &mp_decimal_data.set); decNumberRemainder(&r2, &r1, &mp_decimal_data.two, &mp_decimal_data.set); decNumberCompare(&r1, &r2, &mp_decimal_data.one, &mp_decimal_data.set); return decNumberIsZero(&r1); } static int mp_decimal_equal(mp_number *A, mp_number *B) { decNumber res; decNumberCompare(&res, A->data.num, B->data.num, &mp_decimal_data.set); return decNumberIsZero(&res); } static int mp_decimal_greater(mp_number *A, mp_number *B) { decNumber res; decNumberCompare(&res, A->data.num, B->data.num, &mp_decimal_data.set); return decNumberIsPositive(&res); } static int mp_decimal_less(mp_number *A, mp_number *B) { decNumber res; decNumberCompare(&res, A->data.num, B->data.num, &mp_decimal_data.set); return decNumberIsNegative(&res); } static int mp_decimal_non_equal_abs(mp_number *A, mp_number *B) { decNumber res, a, b; decNumberCopyAbs(&a, A->data.num); decNumberCopyAbs(&b, B->data.num); decNumberCompare(&res, &a, &b, &mp_decimal_data.set); return ! decNumberIsZero(&res); } static char *mp_decnumber_tostring(decNumber *n) { decNumber corrected; char *buffer = mp_memory_allocate((size_t) ((decNumber *) n)->digits + 14); decNumberCopy(&corrected, n); decNumberTrim(&corrected); decNumberToString(&corrected, buffer); return buffer; } static char *mp_decimal_number_tostring(MP mp, mp_number *n) { (void) mp; return mp_decnumber_tostring(n->data.num); } static void mp_decimal_print_number(MP mp, mp_number *n) { char *str = mp_decnumber_tostring(n->data.num); mp_print_e_str(mp, str); mp_memory_free(str); } static void mp_decimal_slow_add(MP mp, mp_number *ret, mp_number *A, mp_number *B) { (void) mp; decNumberAdd(ret->data.num, A->data.num, B->data.num, &mp_decimal_data.set); } static void mp_decimal_slow_sub(MP mp, mp_number *ret, mp_number *A, mp_number *B) { (void) mp; decNumberSubtract(ret->data.num, A->data.num, B->data.num, &mp_decimal_data.set); } static void mp_decimal_make_fraction(MP mp, decNumber *ret, decNumber *p, decNumber *q) { decNumberDivide(ret, p, q, &mp_decimal_data.set); mp_decnumber_check(mp, ret, &mp_decimal_data.set); decNumberMultiply(ret, ret, &mp_decimal_data.fraction_multiplier, &mp_decimal_data.set); } static void mp_decimal_number_make_fraction(MP mp, mp_number *ret, mp_number *p, mp_number *q) { mp_decimal_make_fraction(mp, ret->data.num, p->data.num, q->data.num); } static void mp_decimal_take_fraction(MP mp, decNumber *ret, decNumber *p, decNumber *q) { (void) mp; decNumberMultiply(ret, p, q, &mp_decimal_data.set); decNumberDivide(ret, ret, &mp_decimal_data.fraction_multiplier, &mp_decimal_data.set); } static void mp_decimal_number_take_fraction(MP mp, mp_number *ret, mp_number *p, mp_number *q) { mp_decimal_take_fraction(mp, ret->data.num, p->data.num, q->data.num); } static void mp_decimal_number_take_scaled(MP mp, mp_number *ret, mp_number *p_orig, mp_number *q_orig) { (void) mp; decNumberMultiply(ret->data.num, p_orig->data.num, q_orig->data.num, &mp_decimal_data.set); } static void mp_decimal_number_make_scaled(MP mp, mp_number *ret, mp_number *p_orig, mp_number *q_orig) { decNumberDivide(ret->data.num, p_orig->data.num, q_orig->data.num, &mp_decimal_data.set); mp_decnumber_check(mp, ret->data.num, &mp_decimal_data.set); } static void mp_decimal_aux_wrapup_numeric_token(MP mp, unsigned char *start, unsigned char *stop) { decNumber result; size_t l = stop-start+1; char *buf = mp_memory_allocate(l + 1); buf[l] = '\0'; (void) strncpy(buf, (const char *) start, l); mp_decimal_data.set.status = 0; decNumberFromString(&result,buf, &mp_decimal_data.set); mp_memory_free(buf); if (mp_decimal_data.set.status == 0) { set_cur_mod(&result); } else if (mp->scanner_status != mp_tex_flushing_state) { if (too_large(mp_decimal_data.set.status)) { mp_decnumber_check(mp, &result, &mp_decimal_data.set); set_cur_mod(&result); mp_error( mp, "Enormous number has been reduced", "I could not handle this number specification because it is out of range." ); } else if (too_precise(mp_decimal_data.set.status)) { set_cur_mod(&result); if (decNumberIsPositive((decNumber *) internal_value(mp_warning_check_internal).data.num) && (mp->scanner_status != mp_tex_flushing_state)) { char msg[256]; snprintf (msg, 256, "Number is too precise (numberprecision = %d)", mp_decimal_data.set.digits); mp_error( mp, msg, "Continue and I'll round the value until it fits the current numberprecision\n" "(Set warningcheck:=0 to suppress this message.)" ); } } else { /* this also captures underflow */ mp_error( mp, "Erroneous number specification changed to zero", "I could not handle this number specification" ); decNumberZero(&result); set_cur_mod(&result); } } set_cur_cmd((mp_variable_type) mp_numeric_command); } static void mp_decimal_aux_find_exponent(MP mp) { if (mp->buffer[mp->cur_input.loc_field] == 'e' || mp->buffer[mp->cur_input.loc_field] == 'E') { mp->cur_input.loc_field++; if (! (mp->buffer[mp->cur_input.loc_field] == '+' || mp->buffer[mp->cur_input.loc_field] == '-' || mp->char_class[mp->buffer[mp->cur_input.loc_field]] == mp_digit_class)) { mp->cur_input.loc_field--; return; } if (mp->buffer[mp->cur_input.loc_field] == '+' || mp->buffer[mp->cur_input.loc_field] == '-') { mp->cur_input.loc_field++; } while (mp->char_class[mp->buffer[mp->cur_input.loc_field]] == mp_digit_class) { mp->cur_input.loc_field++; } } } static void mp_decimal_scan_fractional_token(MP mp, mp_scaled_t n) { unsigned char *start = &mp->buffer[mp->cur_input.loc_field -1]; unsigned char *stop; (void) n; while (mp->char_class[mp->buffer[mp->cur_input.loc_field]] == mp_digit_class) { mp->cur_input.loc_field++; } mp_decimal_aux_find_exponent(mp); stop = &mp->buffer[mp->cur_input.loc_field-1]; mp_decimal_aux_wrapup_numeric_token(mp, start, stop); } static void mp_decimal_scan_numeric_token(MP mp, mp_scaled_t n) { unsigned char *start = &mp->buffer[mp->cur_input.loc_field -1]; unsigned char *stop; (void) n; while (mp->char_class[mp->buffer[mp->cur_input.loc_field]] == mp_digit_class) { mp->cur_input.loc_field++; } if (mp->buffer[mp->cur_input.loc_field] == '.' && mp->buffer[mp->cur_input.loc_field+1] != '.') { mp->cur_input.loc_field++; while (mp->char_class[mp->buffer[mp->cur_input.loc_field]] == mp_digit_class) { mp->cur_input.loc_field++; } } mp_decimal_aux_find_exponent(mp); stop = &mp->buffer[mp->cur_input.loc_field-1]; mp_decimal_aux_wrapup_numeric_token(mp, start, stop); } static void mp_decimal_velocity(MP mp, mp_number *ret, mp_number *st, mp_number *ct, mp_number *sf, mp_number *cf, mp_number *t) { decNumber acc, num, denom; /* registers for intermediate calculations */ decNumber r1, r2; decNumber arg1, arg2; decNumber i16, fone, fhalf, ftwo, sqrtfive; decNumberCopy(&i16, &mp_decimal_data.sixteen); decNumberCopy(&fone, &mp_decimal_data.fraction_one); decNumberCopy(&fhalf, &mp_decimal_data.fraction_half); decNumberCopy(&ftwo, &mp_decimal_data.fraction_two); decNumberCopy(&sqrtfive, &mp_decimal_data.sixteen); decNumberSquareRoot(&sqrtfive, &sqrtfive, &mp_decimal_data.set); decNumberDivide(&arg1, sf->data.num, &i16, &mp_decimal_data.set); /* arg1 = sf / 16*/ decNumberSubtract(&arg1, st->data.num,&arg1, &mp_decimal_data.set); /* arg1 = st - arg1*/ decNumberDivide(&arg2, st->data.num, &i16, &mp_decimal_data.set); /* arg2 = st / 16*/ decNumberSubtract(&arg2, sf->data.num,&arg2, &mp_decimal_data.set); /* arg2 = sf - arg2*/ mp_decimal_take_fraction(mp, &acc, &arg1, &arg2); /* acc = (arg1 * arg2) / fmul*/ decNumberCopy(&arg1, &acc); decNumberSubtract(&arg2, ct->data.num, cf->data.num, &mp_decimal_data.set); /* arg2 = ct - cf*/ mp_decimal_take_fraction(mp, &acc, &arg1, &arg2); /* acc = (arg1 * arg2 ) / fmul*/ decNumberSquareRoot(&arg1, &mp_decimal_data.two, &mp_decimal_data.set); /* arg1 = $\sqrt{2}$*/ decNumberMultiply(&arg1, &arg1, &fone, &mp_decimal_data.set); /* arg1 = arg1 * fmul*/ mp_decimal_take_fraction(mp, &r1, &acc, &arg1); /* r1 = (acc * arg1) / fmul*/ decNumberAdd(&num, &ftwo, &r1, &mp_decimal_data.set); /* num = ftwo + r1*/ decNumberSubtract(&arg1,&sqrtfive, &mp_decimal_data.one, &mp_decimal_data.set); /* arg1 = $\sqrt{5}$ - 1*/ decNumberMultiply(&arg1,&arg1,&fhalf, &mp_decimal_data.set); /* arg1 = arg1 * fmul/2*/ decNumberMultiply(&arg1,&arg1,&mp_decimal_data.three, &mp_decimal_data.set); /* arg1 = arg1 * 3*/ decNumberSubtract(&arg2,&mp_decimal_data.three, &sqrtfive, &mp_decimal_data.set); /* arg2 = 3 - $\sqrt{5}$*/ decNumberMultiply(&arg2,&arg2, &fhalf, &mp_decimal_data.set); /* arg2 = arg2 * fmul/2*/ decNumberMultiply(&arg2,&arg2, &mp_decimal_data.three, &mp_decimal_data.set); /* arg2 = arg2 * 3*/ mp_decimal_take_fraction(mp, &r1, ct->data.num, &arg1) ; /* r1 = (ct * arg1) / fmul*/ mp_decimal_take_fraction(mp, &r2, cf->data.num, &arg2); /* r2 = (cf * arg2) / fmul*/ decNumberCopy(&denom, &mp_decimal_data.fraction_three); /* denom = 3fmul*/ decNumberAdd(&denom, &denom, &r1, &mp_decimal_data.set); /* denom = denom + r1*/ decNumberAdd(&denom, &denom, &r2, &mp_decimal_data.set); /* denom = denom + r1*/ decNumberCompare(&arg1, t->data.num, &mp_decimal_data.one, &mp_decimal_data.set); if (! decNumberIsZero(&arg1)) { /* t != r1*/ decNumberDivide(&num, &num, t->data.num, &mp_decimal_data.set); /* num = num / t */ } decNumberCopy(&r2, &num); /* r2 = num / 4*/ decNumberDivide(&r2, &r2, &mp_decimal_data.four, &mp_decimal_data.set); if (decNumberLess(&denom, &r2)) { decNumberCopy(ret->data.num, &mp_decimal_data.fraction_four); /* num/4 >= denom => denom < num/4*/ } else { mp_decimal_make_fraction(mp, ret->data.num, &num, &denom); } mp_decnumber_check(mp, ret->data.num, &mp_decimal_data.set); } static int mp_decimal_ab_vs_cd (mp_number *a_orig, mp_number *b_orig, mp_number *c_orig, mp_number *d_orig) { decNumber a, b, c, d; decNumber ab, cd; decNumberCopy(&a, (decNumber *) a_orig->data.num); decNumberCopy(&b, (decNumber *) b_orig->data.num); decNumberCopy(&c, (decNumber *) c_orig->data.num); decNumberCopy(&d, (decNumber *) d_orig->data.num); decNumberMultiply(&ab, (decNumber *) a_orig->data.num, (decNumber *)b_orig->data.num, &mp_decimal_data.set); decNumberMultiply(&cd, (decNumber *) c_orig->data.num, (decNumber *)d_orig->data.num, &mp_decimal_data.set); if (decNumberLess(&ab, &cd)) { return -1; } else if (decNumberGreater(&ab, &cd)) { return 1; } else { return 0; } } static void mp_decimal_crossing_point(MP mp, mp_number *ret, mp_number *aa, mp_number *bb, mp_number *cc) { decNumber a, b, c; double d; /* recursive counter */ decNumber x, xx, x0, x1, x2; /* temporary registers for bisection */ decNumber scratch, scratch2; decNumberCopy(&a, (decNumber *) aa->data.num); decNumberCopy(&b, (decNumber *) bb->data.num); decNumberCopy(&c, (decNumber *) cc->data.num); if (decNumberIsNegative(&a)) { decNumberCopy(ret->data.num, &mp_decimal_data.zero_crossing); goto RETURN; } if (! decNumberIsNegative(&c)) { if (! decNumberIsNegative(&b)) { if (decNumberIsPositive(&c)) { decNumberCopy(ret->data.num, &mp_decimal_data.no_crossing); } else if (decNumberIsZero(&a) && decNumberIsZero(&b)) { decNumberCopy(ret->data.num, &mp_decimal_data.no_crossing); } else { decNumberCopy(ret->data.num, &mp_decimal_data.one_crossing); } goto RETURN; } if (decNumberIsZero(&a)) { decNumberCopy(ret->data.num, &mp_decimal_data.zero_crossing); goto RETURN; } } else if (decNumberIsZero(&a) && ! decNumberIsPositive(&b)) { decNumberCopy(ret->data.num, &mp_decimal_data.zero_crossing); goto RETURN; } /* Use bisection to find the crossing point... */ d = mp_epsilonf; decNumberCopy(&x0, &a); decNumberSubtract(&x1, &a, &b, &mp_decimal_data.set); decNumberSubtract(&x2, &b, &c, &mp_decimal_data.set); /* not sure why the error correction has to be >= 1E-12 */ decNumberFromDouble(&scratch2, 1E-12); do { decNumberAdd(&x, &x1, &x2, &mp_decimal_data.set); decNumberDivide(&x, &x, &mp_decimal_data.two, &mp_decimal_data.set); decNumberAdd(&x, &x, &scratch2, &mp_decimal_data.set); decNumberSubtract(&scratch, &x1, &x0, &mp_decimal_data.set); if (decNumberGreater(&scratch, &x0)) { decNumberCopy(&x2, &x); decNumberAdd(&x0, &x0, &x0, &mp_decimal_data.set); d += d; } else { decNumberAdd(&xx, &scratch, &x, &mp_decimal_data.set); if (decNumberGreater(&xx,&x0)) { decNumberCopy(&x2,&x); decNumberAdd(&x0, &x0, &x0, &mp_decimal_data.set); d += d; } else { decNumberSubtract(&x0, &x0, &xx, &mp_decimal_data.set); if (! decNumberGreater(&x,&x0)) { decNumberAdd(&scratch, &x, &x2, &mp_decimal_data.set); if (! decNumberGreater(&scratch, &x0)) { decNumberCopy(ret->data.num, &mp_decimal_data.no_crossing); goto RETURN; } } decNumberCopy(&x1,&x); d = d + d + mp_epsilonf; } } } while (d < mp_fraction_multiplier); decNumberFromDouble(&scratch, d); decNumberSubtract(ret->data.num,&scratch, &mp_decimal_data.fraction_one, &mp_decimal_data.set); RETURN: mp_decnumber_check(mp, ret->data.num, &mp_decimal_data.set); } static mp_scaled_t mp_decimal_round_unscaled(mp_number *x_orig) { return mpscaledround(mp_decimal_to_double(x_orig)); } static void mp_decimal_floor(mp_number *i) { int round = mp_decimal_data.set.round; mp_decimal_data.set.round = DEC_ROUND_FLOOR; decNumberToIntegralValue(i->data.num, i->data.num, &mp_decimal_data.set); mp_decimal_data.set.round = round; } static void mp_decimal_fraction_to_round_scaled(mp_number *x_orig) { x_orig->type = mp_scaled_type; decNumberDivide(x_orig->data.num, x_orig->data.num, &mp_decimal_data.fraction_multiplier, &mp_decimal_data.set); } static void mp_decimal_square_rt(MP mp, mp_number *ret, mp_number *x_orig) { decNumber x; decNumberCopy(&x, x_orig->data.num); if (! decNumberIsPositive(&x)) { if (decNumberIsNegative(&x)) { char msg[256]; char *xstr = mp_decimal_number_tostring(mp, x_orig); snprintf(msg, 256, "Square root of %s has been replaced by 0", xstr); mp_memory_free(xstr); mp_error( mp, msg, "Since I don't take square roots of negative numbers, I'm zeroing this one.\n" "Proceed, with fingers crossed." ); } decNumberZero(ret->data.num); } else { decNumberSquareRoot(ret->data.num, &x, &mp_decimal_data.set); } mp_decnumber_check(mp, ret->data.num, &mp_decimal_data.set); } static void mp_decimal_pyth_add(MP mp, mp_number *ret, mp_number *a_orig, mp_number *b_orig) { decNumber a, b; decNumber asq, bsq; decNumberCopyAbs(&a, a_orig->data.num); decNumberCopyAbs(&b, b_orig->data.num); decNumberMultiply(&asq, &a, &a, &mp_decimal_data.set); decNumberMultiply(&bsq, &b, &b, &mp_decimal_data.set); decNumberAdd(&a, &asq, &bsq, &mp_decimal_data.set); decNumberSquareRoot(ret->data.num, &a, &mp_decimal_data.set); /* if (set.status != 0) { mp->arithmic_error = mp_error_code(mp, 5); decNumberCopy(ret->data.num, &mp_decimal_data.EL_GORDO); } */ mp_decnumber_check(mp, ret->data.num, &mp_decimal_data.set); } static void mp_decimal_pyth_sub(MP mp, mp_number *ret, mp_number *a_orig, mp_number *b_orig) { decNumber a, b; decNumberCopyAbs(&a, a_orig->data.num); decNumberCopyAbs(&b, b_orig->data.num); if (! decNumberGreater(&a, &b)) { if (decNumberLess(&a, &b)) { char msg[256]; char *astr = mp_decimal_number_tostring(mp, a_orig); char *bstr = mp_decimal_number_tostring(mp, b_orig); snprintf(msg, 256, "Pythagorean subtraction %s+-+%s has been replaced by 0", astr, bstr); mp_memory_free(astr); mp_memory_free(bstr); mp_error( mp, msg, "Since I don't take square roots of negative numbers, I'm zeroing this one.\n" "Proceed, with fingers crossed." ); } decNumberZero(&a); } else { decNumber asq, bsq; decNumberMultiply(&asq, &a, &a, &mp_decimal_data.set); decNumberMultiply(&bsq, &b, &b, &mp_decimal_data.set); decNumberSubtract(&a, &asq, &bsq, &mp_decimal_data.set); decNumberSquareRoot(&a, &a, &mp_decimal_data.set); } decNumberCopy(ret->data.num, &a); mp_decnumber_check(mp, ret->data.num, &mp_decimal_data.set); } static void mp_decimal_power_of(MP mp, mp_number *ret, mp_number *a_orig, mp_number *b_orig) { decNumberPower(ret->data.num, a_orig->data.num, b_orig->data.num, &mp_decimal_data.set); mp_decnumber_check(mp, ret->data.num, &mp_decimal_data.set); } static void mp_decimal_m_log(MP mp, mp_number *ret, mp_number *x_orig) { if (! decNumberIsPositive((decNumber *) x_orig->data.num)) { char msg[256]; char *xstr = mp_decimal_number_tostring(mp, x_orig); snprintf(msg, 256, "Logarithm of %s has been replaced by 0", xstr); mp_memory_free(xstr); mp_error( mp, msg, "Since I don't take logs of non-positive numbers, I'm zeroing this one.\n" "Proceed, with fingers crossed." ); decNumberZero(ret->data.num); } else { decNumber twofivesix; decNumberFromScaled(&twofivesix, 256); /* can be copy */ decNumberLn(ret->data.num, x_orig->data.num, &mp_decimal_data.limitedset); mp_decnumber_check(mp, ret->data.num, &mp_decimal_data.limitedset); decNumberMultiply(ret->data.num, ret->data.num, &twofivesix, &mp_decimal_data.set); } mp_decnumber_check(mp, ret->data.num, &mp_decimal_data.set); } static void mp_decimal_m_exp(MP mp, mp_number *ret, mp_number *x_orig) { decNumber temp, twofivesix; decNumberFromScaled(&twofivesix, 256); /* can be copy */ decNumberDivide(&temp, x_orig->data.num, &twofivesix, &mp_decimal_data.set); mp_decimal_data.limitedset.status = 0; decNumberExp(ret->data.num, &temp, &mp_decimal_data.limitedset); if (mp_decimal_data.limitedset.status & DEC_Clamped) { if (decNumberIsPositive((decNumber *) x_orig->data.num)) { mp->arithmic_error = mp_error_code(mp, 6); decNumberCopy(ret->data.num, &mp_decimal_data.EL_GORDO); } else { decNumberZero(ret->data.num); } } mp_decnumber_check(mp, ret->data.num, &mp_decimal_data.limitedset); mp_decimal_data.limitedset.status = 0; } static void mp_decimal_n_arg(MP mp, mp_number *ret, mp_number *x_orig, mp_number *y_orig) { if (decNumberIsZero((decNumber *) x_orig->data.num) && decNumberIsZero((decNumber *) y_orig->data.num)) { if (decNumberIsNegative((decNumber *) internal_value(mp_default_zero_angle_internal).data.num)) { mp_error( mp, "angle(0,0) is taken as zero", "The 'angle' between two identical points is undefined. I'm zeroing this one.\n" "Proceed, with fingers crossed." ); decNumberZero(ret->data.num); } else { decNumberCopy(ret->data.num, internal_value(mp_default_zero_angle_internal).data.num); } } else { decNumber atan2val, oneeighty_angle; ret->type = mp_angle_type; decNumberFromScaled(&oneeighty_angle, 180 * mp_angle_multiplier); /* can be copy */ decNumberDivide(&oneeighty_angle, &oneeighty_angle, &mp_decimal_data.pi, &mp_decimal_data.set); checkZero(y_orig->data.num); checkZero(x_orig->data.num); decNumberAtan2(&atan2val, y_orig->data.num, x_orig->data.num, &mp_decimal_data.set); decNumberMultiply(ret->data.num,&atan2val, &oneeighty_angle, &mp_decimal_data.set); checkZero(ret->data.num); } mp_decnumber_check(mp, ret->data.num, &mp_decimal_data.set); } static void sinecosine(decNumber *theangle, decNumber *c, decNumber *s) { int prec = mp_decimal_data.set.digits/2; decNumber p, pxa, fac, cc; decNumber n1, n2, p1; decNumberZero(c); decNumberZero(s); if (prec < DECPRECISION_DEFAULT) { prec = DECPRECISION_DEFAULT; } for (int n = 0; n < prec; n++) { decNumberFromScaled(&p1, n); decNumberFromScaled(&n1, 2 * n); decNumberPower(&p, &mp_decimal_data.minusone, &p1, &mp_decimal_data.limitedset); if (n == 0) { decNumberCopy(&pxa, &mp_decimal_data.one); } else { decNumberPower(&pxa, theangle, &n1, &mp_decimal_data.limitedset); } if (2*n < mp_decimal_data.last_cached_factorial) { decNumberCopy(&fac,mp_decimal_data.factorials[2*n]); } else { decNumberCopy(&fac,mp_decimal_data.factorials[mp_decimal_data.last_cached_factorial]); for (int i = mp_decimal_data.last_cached_factorial+1; i <= 2*n; i++) { decNumberFromScaled(&cc, i); decNumberMultiply (&fac, &fac, &cc, &mp_decimal_data.set); if (i < FACTORIALS_CACHESIZE) { mp_decimal_data.factorials[i] = mp_memory_allocate(sizeof(decNumber)); decNumberCopy(mp_decimal_data.factorials[i], &fac); mp_decimal_data.last_cached_factorial = i; } } } decNumberDivide(&pxa, &pxa, &fac, &mp_decimal_data.set); decNumberMultiply(&pxa, &pxa, &p, &mp_decimal_data.set); decNumberAdd(s, s, &pxa, &mp_decimal_data.set); decNumberFromScaled(&n2, 2 * n + 1); decNumberMultiply(&fac, &fac, &n2, &mp_decimal_data.set); /* fac = fac * (2*n+1)*/ decNumberPower(&pxa, theangle, &n2, &mp_decimal_data.limitedset); decNumberDivide(&pxa, &pxa, &fac, &mp_decimal_data.set); decNumberMultiply(&pxa, &pxa, &p, &mp_decimal_data.set); decNumberAdd(c, c, &pxa, &mp_decimal_data.set); } } static void mp_decimal_sin_cos(MP mp, mp_number *z_orig, mp_number *n_cos, mp_number *n_sin) { decNumber rad; decNumber one_eighty; double tmp = mp_decimal_to_double(z_orig)/16.0; if ((tmp == 90.0)||(tmp == -270)){ decNumberZero(n_cos->data.num); decNumberCopy(n_sin->data.num, &mp_decimal_data.fraction_multiplier); } else if ((tmp == -90.0)||(tmp == 270.0)) { decNumberZero(n_cos->data.num); decNumberCopyNegate(n_sin->data.num, &mp_decimal_data.fraction_multiplier); } else if ((tmp == 180.0) || (tmp == -180.0)) { decNumberCopyNegate(n_cos->data.num, &mp_decimal_data.fraction_multiplier); decNumberZero(n_sin->data.num); } else { decNumberFromScaled(&one_eighty, 180 * 16); /* can be copy */ decNumberMultiply(&rad, z_orig->data.num, &mp_decimal_data.pi, &mp_decimal_data.set); decNumberDivide(&rad, &rad, &one_eighty, &mp_decimal_data.set); sinecosine(&rad, n_sin->data.num, n_cos->data.num); decNumberMultiply(n_cos->data.num, n_cos->data.num, &mp_decimal_data.fraction_multiplier, &mp_decimal_data.set); decNumberMultiply(n_sin->data.num, n_sin->data.num, &mp_decimal_data.fraction_multiplier, &mp_decimal_data.set); } mp_decnumber_check(mp, n_cos->data.num, &mp_decimal_data.set); mp_decnumber_check(mp, n_sin->data.num, &mp_decimal_data.set); } # define KK 100 /* the long lag */ # define LL 37 /* the short lag */ # define MM (1L<<30) /* the modulus */ # define mod_diff(x,y) (((x)-(y))&(MM-1)) /* subtraction mod MM */ # define QUALITY 1009 /* recommended quality level for high-res use */ # define TT 70 /* guaranteed separation between streams */ # define is_odd(x) ((x)&1) /* units bit of x */ typedef struct mp_decimal_random_info { long x[KK]; long buf[QUALITY]; long dummy; long started; long *ptr; } mp_decimal_random_info; static mp_decimal_random_info mp_decimal_random_data = { .dummy = -1, .started = -1, .ptr = &mp_decimal_random_data.dummy }; static void ran_array(long aa[],int n) { int i, j; for (j = 0; j < KK;j++) { aa[j] = mp_decimal_random_data.x[j]; } for (; j < n; j++) { aa[j] = mod_diff(aa[j - KK], aa[j - LL]); } for (i = 0; i < LL ; i++, j++) { mp_decimal_random_data.x[i] = mod_diff(aa[j - KK], aa[j - LL]); } for (;i < KK; i++, j++) { mp_decimal_random_data.x[i] = mod_diff(aa[j - KK], mp_decimal_random_data.x[i - LL]); } } static void ran_start(long seed) { int t, j; long x[KK+KK-1]; /* the preparation buffer */ long ss=(seed+2)&(MM-2); for (j = 0; j < KK; j++) { /* bootstrap the buffer */ x[j] = ss; ss <<= 1; if (ss >= MM) { /* cyclic shift 29 bits */ ss -= MM - 2; } } /* make x[1] (and only x[1]) odd */ x[1]++; for (ss = seed & (MM-1), t = TT - 1; t;) { for (j = KK - 1; j > 0; j--) { /* square */ x[j + j] = x[j]; x[j + j - 1] = 0; } for (j = KK + KK - 2; j >= KK; j--) { x[j - (KK - LL)] = mod_diff(x[j - (KK - LL)], x[j]); x[j - KK] = mod_diff(x[j - KK], x[j]); } if (is_odd(ss)) { /* "multiply by z" */ for (j = KK; j > 0; j--) { x[j] = x[j-1]; } x[0] = x[KK]; /* shift the buffer cyclically */ x[LL] = mod_diff(x[LL], x[KK]); } if (ss) { ss >>= 1; } else { t--; } } for (j = 0; j < LL; j++) { mp_decimal_random_data.x[j + KK -LL] = x[j]; } for (; j < KK; j++) { mp_decimal_random_data.x[j - LL] = x[j]; } for (j = 0; j < 10; j++) { /* warm things up */ ran_array(x, KK + KK - 1); } mp_decimal_random_data.ptr = &mp_decimal_random_data.started; } static long ran_arr_cycle(void) { if (mp_decimal_random_data.ptr == &mp_decimal_random_data.dummy) { /* the user forgot to initialize */ ran_start(314159L); } ran_array(mp_decimal_random_data.buf, QUALITY); mp_decimal_random_data.buf[KK] = -1; mp_decimal_random_data.ptr = mp_decimal_random_data.buf + 1; return mp_decimal_random_data.buf[0]; } static void mp_decimal_init_randoms(MP mp, int seed) { int k = 1; /* more or less random integers */ int j = abs(seed); while (j >= mp_fraction_multiplier) { j = j/2; } for (int i = 0; i <= 54; i++) { int jj = k; k = j - k; j = jj; if (k < 0) { k += mp_fraction_multiplier; } decNumberFromScaled(mp->randoms[(i * 21) % 55].data.num, j); } /* \quote {warm up} the array */ mp_new_randoms(mp); mp_new_randoms(mp); mp_new_randoms(mp); ran_start((unsigned long) seed); } static void mp_decimal_number_modulo(mp_number *a, mp_number *b) { decNumberRemainder(a->data.num, a->data.num, b->data.num, &mp_decimal_data.set); } static void mp_next_unif_random(MP mp, mp_number *ret) { decNumber a; decNumber b; unsigned long int op = (unsigned) (*mp_decimal_random_data.ptr >= 0? *mp_decimal_random_data.ptr++: ran_arr_cycle()); (void) mp; decNumberFromScaled(&a, op); decNumberFromScaled(&b, MM); decNumberDivide(&a, &a, &b, &mp_decimal_data.set); /* a = a/b */ decNumberCopy(ret->data.num, &a); mp_decnumber_check(mp, ret->data.num, &mp_decimal_data.set); } static void mp_next_random(MP mp, mp_number *ret) { if (mp->j_random == 0) { mp_new_randoms(mp); } else { mp->j_random = mp->j_random - 1; } mp_decimal_clone(ret, &(mp->randoms[mp->j_random])); } static void mp_decimal_m_unif_rand(MP mp, mp_number *ret, mp_number *x_orig) { mp_number x, abs_x, u, y; /* |y| is trial value */ mp_decimal_allocate_number(mp, &y, mp_fraction_type); mp_decimal_allocate_clone(mp, &x, mp_scaled_type, x_orig); mp_decimal_allocate_abs(mp, &abs_x, mp_scaled_type, &x); mp_decimal_allocate_number(mp, &u, mp_scaled_type); mp_next_unif_random(mp, &u); decNumberMultiply(y.data.num, abs_x.data.num, u.data.num, &mp_decimal_data.set); if (mp_decimal_equal(&y, &abs_x)) { mp_decimal_clone(ret, &((math_data *)mp->math)->md_zero_t); } else if (mp_decimal_greater(&x, &((math_data *)mp->math)->md_zero_t)) { mp_decimal_clone(ret, &y); } else { mp_decimal_negated_clone(ret, &y); } mp_decimal_free_number(mp, &x); mp_decimal_free_number(mp, &abs_x); mp_decimal_free_number(mp, &y); mp_decimal_free_number(mp, &u); } static void mp_decimal_m_norm_rand(MP mp, mp_number *ret) { mp_number abs_x, u, r, la, xa; mp_decimal_allocate_number(mp, &la, mp_scaled_type); mp_decimal_allocate_number(mp, &xa, mp_scaled_type); mp_decimal_allocate_number(mp, &abs_x, mp_scaled_type); mp_decimal_allocate_number(mp, &u, mp_scaled_type); mp_decimal_allocate_number(mp, &r, mp_scaled_type); do { do { mp_number v; /* maybe move outside loop */ mp_decimal_allocate_number(mp, &v, mp_scaled_type); mp_next_random(mp, &v); mp_decimal_subtract(&v, &((math_data *)mp->math)->md_fraction_half_t); mp_decimal_number_take_fraction(mp, &xa, &((math_data *)mp->math)->md_sqrt_8_e_k, &v); mp_decimal_free_number(mp, &v); mp_next_random(mp, &u); mp_decimal_clone(&abs_x, &xa); mp_decimal_abs(&abs_x); } while (! mp_decimal_less(&abs_x, &u)); mp_decimal_number_make_fraction(mp, &r, &xa, &u); mp_decimal_clone(&xa, &r); mp_decimal_m_log(mp, &la, &u); mp_decimal_set_from_subtraction(&la, &((math_data *)mp->math)->md_twelve_ln_2_k, &la); } while (mp_decimal_ab_vs_cd(&((math_data *)mp->math)->md_one_k, &la, &xa, &xa) < 0); mp_decimal_clone(ret, &xa); mp_decimal_free_number(mp, &r); mp_decimal_free_number(mp, &abs_x); mp_decimal_free_number(mp, &la); mp_decimal_free_number(mp, &xa); mp_decimal_free_number(mp, &u); } static void mp_decimal_set_precision(MP mp) { int i = decNumberToInt32((decNumber *) internal_value(mp_number_precision_internal).data.num, &mp_decimal_data.set); mp_decimal_data.set.digits = i; mp_decimal_data.limitedset.digits = i; } static void mp_decimal_free_math(MP mp) { mp_decimal_free_number(mp, &(mp->math->md_three_sixty_deg_t)); mp_decimal_free_number(mp, &(mp->math->md_one_eighty_deg_t)); mp_decimal_free_number(mp, &(mp->math->md_negative_one_eighty_deg_t)); mp_decimal_free_number(mp, &(mp->math->md_fraction_one_t)); mp_decimal_free_number(mp, &(mp->math->md_zero_t)); mp_decimal_free_number(mp, &(mp->math->md_half_unit_t)); mp_decimal_free_number(mp, &(mp->math->md_three_quarter_unit_t)); mp_decimal_free_number(mp, &(mp->math->md_unity_t)); mp_decimal_free_number(mp, &(mp->math->md_two_t)); mp_decimal_free_number(mp, &(mp->math->md_three_t)); mp_decimal_free_number(mp, &(mp->math->md_one_third_inf_t)); mp_decimal_free_number(mp, &(mp->math->md_inf_t)); mp_decimal_free_number(mp, &(mp->math->md_negative_inf_t)); mp_decimal_free_number(mp, &(mp->math->md_warning_limit_t)); mp_decimal_free_number(mp, &(mp->math->md_one_k)); mp_decimal_free_number(mp, &(mp->math->md_sqrt_8_e_k)); mp_decimal_free_number(mp, &(mp->math->md_twelve_ln_2_k)); mp_decimal_free_number(mp, &(mp->math->md_coef_bound_k)); mp_decimal_free_number(mp, &(mp->math->md_coef_bound_minus_1)); mp_decimal_free_number(mp, &(mp->math->md_fraction_threshold_t)); mp_decimal_free_number(mp, &(mp->math->md_half_fraction_threshold_t)); mp_decimal_free_number(mp, &(mp->math->md_scaled_threshold_t)); mp_decimal_free_number(mp, &(mp->math->md_half_scaled_threshold_t)); mp_decimal_free_number(mp, &(mp->math->md_near_zero_angle_t)); mp_decimal_free_number(mp, &(mp->math->md_p_over_v_threshold_t)); mp_decimal_free_number(mp, &(mp->math->md_equation_threshold_t)); /* For sake of speed, we accept this memory leak: for (i = 0; i <= mp_decimal_data.last_cached_factorial; i++) { mp_memory_free(mp_decimal_data.factorials[i]); } mp_memory_free(mp_decimal_data.factorials); */ mp_memory_free(mp->math); } math_data *mp_initialize_decimal_math(MP mp) { math_data *math = (math_data *) mp_memory_allocate(sizeof(math_data)); decContextDefault(&mp_decimal_data.set, DEC_INIT_BASE); /* initialize */ mp_decimal_data.set.traps = 0; /* no traps, thank you */ decContextDefault(&mp_decimal_data.limitedset, DEC_INIT_BASE); /* initialize */ mp_decimal_data.limitedset.traps = 0; /* no traps, thank you */ mp_decimal_data.limitedset.emax = 999999; mp_decimal_data.limitedset.emin = -999999; mp_decimal_data.set.digits = DECPRECISION_DEFAULT; mp_decimal_data.limitedset.digits = DECPRECISION_DEFAULT; if (! mp_decimal_data.initialized) { /* these are shared */ mp_decimal_data.initialized = 1 ; decNumberFromScaled(&mp_decimal_data.one, 1); decNumberFromScaled(&mp_decimal_data.minusone, -1); decNumberFromScaled(&mp_decimal_data.zero, 0); decNumberFromScaled(&mp_decimal_data.two, 2); decNumberFromScaled(&mp_decimal_data.three, 3); decNumberFromScaled(&mp_decimal_data.four, 4); decNumberFromScaled(&mp_decimal_data.five, 5); decNumberFromScaled(&mp_decimal_data.sixteen, 16); decNumberFromScaled(&mp_decimal_data.fraction_multiplier, mp_fraction_multiplier); decNumberFromScaled(&mp_decimal_data.fraction_one, mp_fraction_multiplier); decNumberFromScaled(&mp_decimal_data.fraction_two, 2 * mp_fraction_multiplier); decNumberFromScaled(&mp_decimal_data.fraction_three, 3 * mp_fraction_multiplier); decNumberFromScaled(&mp_decimal_data.fraction_four, 4 * mp_fraction_multiplier); decNumberFromScaled(&mp_decimal_data.fraction_half, mp_fraction_multiplier / 2); decNumberFromScaled(&mp_decimal_data.fraction_one_plus, mp_fraction_multiplier + 1); decNumberFromScaled(&mp_decimal_data.angle_multiplier, mp_angle_multiplier); decNumberFromString(&mp_decimal_data.pi, PI_STRING, &mp_decimal_data.set); decNumberFromDouble(&mp_decimal_data.epsilon, mp_epsilon); decNumberFromString(&mp_decimal_data.EL_GORDO, EL_GORDO_STRING, &mp_decimal_data.set); decNumberFromString(&mp_decimal_data.negative_EL_GORDO, NEGATIVE_EL_GORDO_STRING, &mp_decimal_data.set); decNumberFromScaled(&mp_decimal_data.no_crossing, mp_fraction_multiplier + 1); decNumberFromScaled(&mp_decimal_data.one_crossing, mp_fraction_multiplier); decNumberFromScaled(&mp_decimal_data.zero_crossing, 0); /* */ mp_decimal_data.factorials = (decNumber **) mp_memory_allocate(FACTORIALS_CACHESIZE * sizeof(decNumber *)); mp_decimal_data.factorials[0] = (decNumber *) mp_memory_allocate(sizeof(decNumber)); decNumberCopy(mp_decimal_data.factorials[0], &mp_decimal_data.one); } math->md_allocate = mp_decimal_allocate_number; math->md_free = mp_decimal_free_number; math->md_allocate_clone = mp_decimal_allocate_clone; math->md_allocate_abs = mp_decimal_allocate_abs; math->md_allocate_div = mp_decimal_allocate_div; math->md_allocate_mul = mp_decimal_allocate_mul; math->md_allocate_add = mp_decimal_allocate_add; math->md_allocate_sub = mp_decimal_allocate_sub; math->md_allocate_double = mp_decimal_allocate_double; mp_decimal_allocate_number(mp, &math->md_precision_default, mp_scaled_type); decNumberFromScaled(math->md_precision_default.data.num, DECPRECISION_DEFAULT); mp_decimal_allocate_number(mp, &math->md_precision_max, mp_scaled_type); decNumberFromScaled(math->md_precision_max.data.num, DECNUMDIGITS); mp_decimal_allocate_number(mp, &math->md_precision_min, mp_scaled_type); decNumberCopy(math->md_precision_min.data.num, &mp_decimal_data.two); /* here are the constants for scaled objects */ mp_decimal_allocate_number(mp, &math->md_epsilon_t, mp_scaled_type); decNumberCopy(math->md_epsilon_t.data.num, &mp_decimal_data.epsilon); mp_decimal_allocate_number(mp, &math->md_inf_t, mp_scaled_type); decNumberCopy(math->md_inf_t.data.num, &mp_decimal_data.EL_GORDO); mp_decimal_allocate_number(mp, &math->md_negative_inf_t, mp_scaled_type); decNumberCopy(math->md_negative_inf_t.data.num, &mp_decimal_data.negative_EL_GORDO); mp_decimal_allocate_number(mp, &math->md_warning_limit_t, mp_scaled_type); decNumberFromString(math->md_warning_limit_t.data.num, WARNING_LIMIT_STRING, &mp_decimal_data.set); mp_decimal_allocate_number(mp, &math->md_one_third_inf_t, mp_scaled_type); decNumberDivide(math->md_one_third_inf_t.data.num, math->md_inf_t.data.num, &mp_decimal_data.three, &mp_decimal_data.set); mp_decimal_allocate_number(mp, &math->md_unity_t, mp_scaled_type); decNumberCopy(math->md_unity_t.data.num, &mp_decimal_data.one); mp_decimal_allocate_number(mp, &math->md_two_t, mp_scaled_type); decNumberCopy(math->md_two_t.data.num, &mp_decimal_data.two); mp_decimal_allocate_number(mp, &math->md_three_t, mp_scaled_type); decNumberCopy(math->md_three_t.data.num, &mp_decimal_data.three); mp_decimal_allocate_number(mp, &math->md_half_unit_t, mp_scaled_type); decNumberFromString(math->md_half_unit_t.data.num, "0.5", &mp_decimal_data.set); mp_decimal_allocate_number(mp, &math->md_three_quarter_unit_t, mp_scaled_type); decNumberFromString(math->md_three_quarter_unit_t.data.num, "0.75", &mp_decimal_data.set); mp_decimal_allocate_number(mp, &math->md_zero_t, mp_scaled_type); decNumberZero(math->md_zero_t.data.num); /* fractions */ { decNumber fourzeroninesix; decNumberFromScaled(&fourzeroninesix, 4096); mp_decimal_allocate_number(mp, &math->md_arc_tol_k, mp_fraction_type); decNumberDivide(math->md_arc_tol_k.data.num, &mp_decimal_data.one, &fourzeroninesix, &mp_decimal_data.set); /* quit when change in arc length estimate reaches this */ } /* */ mp_decimal_allocate_number(mp, &math->md_fraction_one_t, mp_fraction_type); decNumberCopy(math->md_fraction_one_t.data.num, &mp_decimal_data.fraction_one); mp_decimal_allocate_number(mp, &math->md_fraction_half_t, mp_fraction_type); decNumberCopy(math->md_fraction_half_t.data.num, &mp_decimal_data.fraction_half); mp_decimal_allocate_number(mp, &math->md_fraction_three_t, mp_fraction_type); decNumberCopy(math->md_fraction_three_t.data.num, &mp_decimal_data.fraction_three); mp_decimal_allocate_number(mp, &math->md_fraction_four_t, mp_fraction_type); decNumberCopy(math->md_fraction_four_t.data.num, &mp_decimal_data.fraction_four); /* angles */ mp_decimal_allocate_number(mp, &math->md_three_sixty_deg_t, mp_angle_type); decNumberFromScaled(math->md_three_sixty_deg_t.data.num, 360 * mp_angle_multiplier); mp_decimal_allocate_number(mp, &math->md_one_eighty_deg_t, mp_angle_type); decNumberFromScaled(math->md_one_eighty_deg_t.data.num, 180 * mp_angle_multiplier); mp_decimal_allocate_number(mp, &math->md_negative_one_eighty_deg_t, mp_angle_type); decNumberFromScaled(math->md_negative_one_eighty_deg_t.data.num, -180 * mp_angle_multiplier); /* various approximations */ mp_decimal_allocate_number(mp, &math->md_one_k, mp_scaled_type); decNumberFromDouble(math->md_one_k.data.num, 1.0 / 64); mp_decimal_allocate_number(mp, &math->md_sqrt_8_e_k, mp_scaled_type); decNumberFromDouble(math->md_sqrt_8_e_k.data.num, 112428.82793 / 65536.0); /* $2^{16}\sqrt{8/e}\approx 112428.82793$ */ mp_decimal_allocate_number(mp, &math->md_twelve_ln_2_k, mp_fraction_type); decNumberFromDouble(math->md_twelve_ln_2_k.data.num, 139548959.6165 / 65536.0); /* $2^{24}\cdot12\ln2\approx139548959.6165$ */ mp_decimal_allocate_number(mp, &math->md_coef_bound_k, mp_fraction_type); # define mp_coef_bound ((7.0 / 3.0) * mp_fraction_multiplier) decNumberFromDouble(math->md_coef_bound_k.data.num, mp_coef_bound); mp_decimal_allocate_number(mp, &math->md_coef_bound_minus_1, mp_fraction_type); decNumberFromDouble(math->md_coef_bound_minus_1.data.num, mp_coef_bound - 1 / 65536.0); mp_decimal_allocate_number(mp, &math->md_twelvebits_3, mp_scaled_type); decNumberFromDouble(math->md_twelvebits_3.data.num, 1365 / 65536.0); /* $1365\approx 2^{12}/3$ */ mp_decimal_allocate_number(mp, &math->md_twentysixbits_sqrt2_t, mp_fraction_type); decNumberFromDouble(math->md_twentysixbits_sqrt2_t.data.num, 94906265.62 / 65536.0); /* $2^{26}\sqrt2\approx94906265.62$ */ mp_decimal_allocate_number(mp, &math->md_twentyeightbits_d_t, mp_fraction_type); decNumberFromDouble(math->md_twentyeightbits_d_t.data.num, 35596754.69 / 65536.0); /* $2^{28}d\approx35596754.69$ */ mp_decimal_allocate_number(mp, &math->md_twentysevenbits_sqrt2_d_t, mp_fraction_type); decNumberFromDouble(math->md_twentysevenbits_sqrt2_d_t.data.num, 25170706.63 / 65536.0); /* $2^{27}\sqrt2\,d\approx25170706.63$ */ /* thresholds */ mp_decimal_allocate_number(mp, &math->md_fraction_threshold_t, mp_fraction_type); decNumberFromDouble(math->md_fraction_threshold_t.data.num, 0.04096); mp_decimal_allocate_number(mp, &math->md_half_fraction_threshold_t, mp_fraction_type); decNumberFromDouble(math->md_half_fraction_threshold_t.data.num, 0.04096 / 2); mp_decimal_allocate_number(mp, &math->md_scaled_threshold_t, mp_scaled_type); decNumberFromDouble(math->md_scaled_threshold_t.data.num, 0.000122); mp_decimal_allocate_number(mp, &math->md_half_scaled_threshold_t, mp_scaled_type); decNumberFromDouble(math->md_half_scaled_threshold_t.data.num, 0.000122 / 2); mp_decimal_allocate_number(mp, &math->md_near_zero_angle_t, mp_angle_type); decNumberFromDouble(math->md_near_zero_angle_t.data.num, 0.0256 * mp_angle_multiplier); mp_decimal_allocate_number(mp, &math->md_p_over_v_threshold_t, mp_fraction_type); decNumberFromDouble(math->md_p_over_v_threshold_t.data.num, 0x80000); mp_decimal_allocate_number(mp, &math->md_equation_threshold_t, mp_scaled_type); decNumberFromDouble(math->md_equation_threshold_t.data.num, 0.001); /* functions */ math->md_from_int = mp_decimal_set_from_int; math->md_from_boolean = mp_decimal_set_from_boolean; math->md_from_scaled = mp_decimal_set_from_scaled; math->md_from_double = mp_decimal_set_from_double; math->md_from_addition = mp_decimal_set_from_addition; math->md_half_from_addition = mp_decimal_set_half_from_addition; math->md_from_subtraction = mp_decimal_set_from_subtraction; math->md_half_from_subtraction = mp_decimal_set_half_from_subtraction; math->md_from_of_the_way = mp_decimal_set_from_of_the_way; math->md_from_div = mp_decimal_set_from_div; math->md_from_mul = mp_decimal_set_from_mul; math->md_from_int_div = mp_decimal_set_from_int_div; math->md_from_int_mul = mp_decimal_set_from_int_mul; math->md_negate = mp_decimal_negate; math->md_add = mp_decimal_add; math->md_subtract = mp_decimal_subtract; math->md_half = mp_decimal_half; math->md_do_double = mp_decimal_double; math->md_abs = mp_decimal_abs; math->md_clone = mp_decimal_clone; math->md_negated_clone = mp_decimal_negated_clone; math->md_abs_clone = mp_decimal_abs_clone; math->md_swap = mp_decimal_swap; math->md_add_scaled = mp_decimal_add_scaled; math->md_multiply_int = mp_decimal_multiply_int; math->md_divide_int = mp_decimal_divide_int; math->md_to_int = mp_decimal_to_int; math->md_to_boolean = mp_decimal_to_boolean; math->md_to_scaled = mp_decimal_to_scaled; math->md_to_double = mp_decimal_to_double; math->md_odd = mp_decimal_odd; math->md_equal = mp_decimal_equal; math->md_less = mp_decimal_less; math->md_greater = mp_decimal_greater; math->md_non_equal_abs = mp_decimal_non_equal_abs; math->md_round_unscaled = mp_decimal_round_unscaled; math->md_floor_scaled = mp_decimal_floor; math->md_fraction_to_round_scaled = mp_decimal_fraction_to_round_scaled; math->md_make_scaled = mp_decimal_number_make_scaled; math->md_make_fraction = mp_decimal_number_make_fraction; math->md_take_fraction = mp_decimal_number_take_fraction; math->md_take_scaled = mp_decimal_number_take_scaled; math->md_velocity = mp_decimal_velocity; math->md_n_arg = mp_decimal_n_arg; math->md_m_log = mp_decimal_m_log; math->md_m_exp = mp_decimal_m_exp; math->md_m_unif_rand = mp_decimal_m_unif_rand; math->md_m_norm_rand = mp_decimal_m_norm_rand; math->md_pyth_add = mp_decimal_pyth_add; math->md_pyth_sub = mp_decimal_pyth_sub; math->md_power_of = mp_decimal_power_of; math->md_fraction_to_scaled = mp_decimal_fraction_to_scaled; math->md_scaled_to_fraction = mp_decimal_scaled_to_fraction; math->md_scaled_to_angle = mp_decimal_scaled_to_angle; math->md_angle_to_scaled = mp_decimal_angle_to_scaled; math->md_init_randoms = mp_decimal_init_randoms; math->md_sin_cos = mp_decimal_sin_cos; math->md_slow_add = mp_decimal_slow_add; math->md_slow_sub = mp_decimal_slow_sub; math->md_sqrt = mp_decimal_square_rt; math->md_print = mp_decimal_print_number; math->md_tostring = mp_decimal_number_tostring; math->md_modulo = mp_decimal_number_modulo; math->md_ab_vs_cd = mp_decimal_ab_vs_cd; math->md_crossing_point = mp_decimal_crossing_point; math->md_scan_numeric = mp_decimal_scan_numeric_token; math->md_scan_fractional = mp_decimal_scan_fractional_token; /* housekeeping */ math->md_free_math = mp_decimal_free_math; math->md_set_precision = mp_decimal_set_precision; return math; }