void _cos( floatnum x, int digits) { signed char sgn; float_abs(x); sgn = 1; if (float_cmp(x, &cPiDiv2) > 0) { sgn = -1; float_sub(x, &cPi, x, digits+1); } if (float_cmp(x, &cPiDiv4) <= 0) { if (2*float_getexponent(x)+2 < - digits) float_setzero(x); else _cosminus1ltPiDiv4(x, digits); float_add(x, x, &c1, digits); } else { float_sub(x, &cPiDiv2, x, digits+1); _sinltPiDiv4(x, digits); } float_setsign(x, sgn); }
/* evaluates tan x for |x| <= pi. A return value of 0 indicates that x = +/- pi/2 within small tolerances, so that tan x cannot be reliable computed */ char _tan( floatnum x, int digits) { signed char sgn; sgn = float_getsign(x); float_abs(x); if (float_cmp(x, &cPiDiv2) > 0) { float_sub(x, &cPi, x, digits+1); sgn = -sgn; } if (float_cmp(x, &cPiDiv4) <= 0) _tanltPiDiv4(x, digits); else { float_sub(x, &cPiDiv2, x, digits+1); if (float_iszero(x) || float_getexponent(x) < -digits) return 0; _tanltPiDiv4(x, digits); float_reciprocal(x, digits); } float_setsign(x, sgn); return 1; }
/* evaluates ln(Gamma(x)) for all those x big enough to let the asymptotic series converge directly. Returns 0, if the result overflows relative error for a 100 gigit calculation < 5e-100 */ static char _lngammabigx( floatnum x, int digits) { floatstruct tmp1, tmp2; char result; result = 0; float_create(&tmp1); float_create(&tmp2); /* compute (ln x-1) * (x-0.5) - 0.5 + ln(sqrt(2*pi)) */ float_copy(&tmp2, x, digits+1); _ln(&tmp2, digits+1); float_sub(&tmp2, &tmp2, &c1, digits+2); float_sub(&tmp1, x, &c1Div2, digits+2); if (float_mul(&tmp1, &tmp1, &tmp2, digits+2)) { /* no overflow */ lngammaasymptotic(x, digits); float_add(x, &tmp1, x, digits+3); float_add(x, x, &cLnSqrt2PiMinusHalf, digits+3); result = 1; } float_free(&tmp2); float_free(&tmp1); return result; }
static char _lngamma_prim( floatnum x, floatnum revfactor, int* infinity, int digits) { floatstruct tmp; char result; char odd; *infinity = 0; if (float_getsign(x) > 0) return _lngamma_prim_xgt0(x, revfactor, digits); float_copy(revfactor, x, digits + 2); float_sub(x, &c1, x, digits+2); float_create(&tmp); result = _lngamma_prim_xgt0(x, &tmp, digits); if (result) { float_neg(x); odd = float_isodd(revfactor); _sinpix(revfactor, digits); if (float_iszero(revfactor)) { *infinity = 1; float_setinteger(revfactor, odd? -1 : 1); } else float_mul(&tmp, &tmp, &cPi, digits+2); float_div(revfactor, revfactor, &tmp, digits+2); } float_free(&tmp); return result; }
char _trigreduce( floatnum x, int digits) { floatstruct tmp; int expx, save; signed char sgn; char odd; if (float_abscmp(x, &cPi) <= 0) return 1; expx = float_getexponent(x); if (expx > float_getlength(&cPi) - digits) return 0; save = float_setprecision(MAXDIGITS); float_create(&tmp); sgn = float_getsign(x); float_abs(x); float_divmod(&tmp, x, x, &cPi, INTQUOT); float_setprecision(save); odd = float_isodd(&tmp); if (odd) float_sub(x, x, &cPi, digits+1); if (sgn < 0) float_neg(x); float_free(&tmp); return 1; }
char _lngamma( floatnum x, int digits) { floatstruct factor; int infinity; char result; if (float_cmp(x, &c1) == 0 || float_cmp(x, &c2) == 0) return _setzero(x); float_create(&factor); result = _lngamma_prim(x, &factor, &infinity, digits) && infinity == 0; if (result) { float_abs(&factor); _ln(&factor, digits + 1); result = float_sub(x, x, &factor, digits+1); } float_free(&factor); if (infinity != 0) return _seterror(x, ZeroDivide); if (!result) float_setnan(x); return result; }
char _gamma0_5( floatnum x, int digits) { floatstruct tmp; int ofs; if (float_getexponent(x) >= 2) return _gamma(x, digits); float_create(&tmp); float_sub(&tmp, x, &c1Div2, EXACT); ofs = float_asinteger(&tmp); float_free(&tmp); if (ofs >= 0) { float_copy(x, &c1Div2, EXACT); if(!_pochhammer_su(x, ofs, digits)) return 0; return float_mul(x, x, &cSqrtPi, digits); } if(!_pochhammer_su(x, -ofs, digits)) return 0; return float_div(x, &cSqrtPi, x, digits); }
char float_arcosh( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; float_sub(x, x, &c1, digits+1); return float_arcoshxplus1(x, digits); }
/* evaluates cos x - 1 for |x| <= pi. This function may underflow, which is indicated by the return value 0 */ char _cosminus1( floatnum x, int digits) { float_abs(x); if (float_cmp(x, &cPiDiv4) <= 0) return _cosminus1ltPiDiv4(x, digits); _cos(x, digits); float_sub(x, x, &c1, digits); return 1; }
/* evaluates arccos x for -1 <= x <= 1. The result is in the range 0 <= result <= pi. The relative error for a 100 digit result is < 5e-100 */ void _arccos( floatnum x, int digits) { signed char sgn; sgn = float_getsign(x); float_abs(x); if (float_cmp(x, &c1Div2) > 0) { float_sub(x, x, &c1, digits+1); _arccosxplus1lt0_5(x, digits); } else { _arcsinlt0_5(x, digits); float_sub(x, &cPiDiv2, x, digits+1); } if (sgn < 0) float_sub(x, &cPi, x, digits+1); }
/* evaluates arccos(1+x) for -0.5 <= x <= 0 arccos(1+x) = arctan(sqrt(-x*(2+x))/(1+x)) the relative error of a 100 digit result is < 5e-100 */ void _arccosxplus1lt0_5( floatnum x, int digits) { floatstruct tmp; float_create(&tmp); float_add(&tmp, x, &c2, digits+1); float_mul(x, x, &tmp, digits+1); float_setsign(x, 1); float_sqrt(x, digits); float_sub(&tmp, &tmp, &c1, digits); float_div(x, x, &tmp, digits+1); _arctan(x, digits); float_free(&tmp); }
/* evaluates arcsin x for -0.5 <= x <= 0.5 arcsin x = arctan(x/sqrt(1-x*x)) the relative error of a 100 digit result is < 5e-100 */ void _arcsinlt0_5( floatnum x, int digits) { floatstruct tmp; if (2*float_getexponent(x) < -digits) return; float_create(&tmp); float_mul(&tmp, x, x, digits); float_sub(&tmp, &c1, &tmp, digits); float_sqrt(&tmp, digits); float_div(x, x, &tmp, digits+1); _arctanlt1(x, digits); float_free(&tmp); }
/* evaluates arcsin x for -1 <= x <= 1. The result is in the range -pi/2 <= result <= pi/2 The relative error for a 100 digit result is < 8e-100 */ void _arcsin( floatnum x, int digits) { signed char sgn; if (float_abscmp(x, &c1Div2) <= 0) _arcsinlt0_5(x, digits); else { sgn = float_getsign(x); float_abs(x); _arccos(x, digits); float_sub(x, &cPiDiv2, x, digits); float_setsign(x, sgn); } }
/* evaluates arctan x for all x. The result is in the range -pi/2 < result < pi/2 relative error for a 100 digit result is 9e-100 */ void _arctan( floatnum x, int digits) { signed char sgn; if (float_abscmp(x, &c1) > 0) { sgn = float_getsign(x); float_abs(x); float_reciprocal(x, digits); _arctanlt1(x, digits); float_sub(x, &cPiDiv2, x, digits+1); float_setsign(x, sgn); } else _arctanlt1(x, digits); }
char float_artanhxplus1( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_getsign(x) >= 0 || float_abscmp(x, &c2) >= 0) return _seterror(x, OutOfDomain); if (float_cmp(x, &c1Div2) < 0) { float_neg(x); _artanh1minusx(x, digits); } else { float_sub(x, &c1, x, digits+1); _artanh(x, digits); } return 1; }
char float_tanhminus1( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_cmp(x, &c1Div2) >= 0) return _tanhminus1gt0(x, digits)? 1 : _seterror(x, Underflow); if (!float_iszero(x)) { if (float_abscmp(x, &c1Div2) <= 0) _tanhlt0_5(x, digits); else { float_setsign(x, 1); _tanhgt0_5(x, digits); float_setsign(x, -1); } } return float_sub(x, x, &c1, digits); }
void _tanltPiDiv4( floatnum x, int digits) { floatstruct tmp; signed char sgn; if (2*float_getexponent(x)+2 < -digits) /* for small x: tan x approx.== x */ return; float_create(&tmp); sgn = float_getsign(x); _cosminus1ltPiDiv4(x, digits); float_add(&tmp, x, &c2, digits+1); float_mul(x, x, &tmp, digits+1); float_abs(x); float_sqrt(x, digits); float_sub(&tmp, &tmp, &c1, digits); float_div(x, x, &tmp, digits+1); float_setsign(x, sgn); float_free(&tmp); }
static char _pochhammer_g( floatnum x, cfloatnum n, int digits) { /* this generalizes the rising Pochhammer symbol using the formula pochhammer(x,n) = Gamma(x+1)/Gamma(x-n+1) */ floatstruct tmp, factor1, factor2; int inf1, inf2; char result; float_create(&tmp); float_create(&factor1); float_create(&factor2); inf2 = 0; float_add(&tmp, x, n, digits+1); result = _lngamma_prim(x, &factor1, &inf1, digits) && _lngamma_prim(&tmp, &factor2, &inf2, digits) && (inf2 -= inf1) <= 0; if (inf2 > 0) float_seterror(ZeroDivide); if (result && inf2 < 0) float_setzero(x); if (result && inf2 == 0) result = float_div(&factor1, &factor1, &factor2, digits+1) && float_sub(x, &tmp, x, digits+1) && _exp(x, digits) && float_mul(x, x, &factor1, digits+1); float_free(&tmp); float_free(&factor2); float_free(&factor1); if (!result) float_setnan(x); return result; }
/** * \brief Fractal Algorithm without FPU optimization. */ static int draw_mandel_without_fpu(void) { t_cpu_time timer; while (i_wofpu<HEIGHT/2+1) { cpu_set_timeout( cpu_us_2_cy(DELAY_US,pcl_freq_param.cpu_f), &timer ); while(j_wofpu<WIDTH) { z_wofpu = 0; zi_wofpu = 0; inset_wofpu = 1; while (k_wofpu<iter_wofpu) { /* z^2 = (a+bi)(a+bi) = a^2 + 2abi - b^2 */ newz_wofpu = float_add( float_sub( float_mul(z_wofpu,z_wofpu), float_mul(zi_wofpu,zi_wofpu)), x_wofpu ); newzi_wofpu = float_add( 2*float_mul( z_wofpu, zi_wofpu), y_wofpu ); z_wofpu = newz_wofpu; zi_wofpu = newzi_wofpu; if(float_add( float_mul(z_wofpu,z_wofpu), float_mul(zi_wofpu,zi_wofpu) ) > 4) { inset_wofpu = 0; colour_wofpu = k_wofpu; k_wofpu = iter_wofpu; } k_wofpu++; }; k_wofpu = 0; // Draw Mandelbrot set if (inset_wofpu) { et024006_DrawPixel(j_wofpu+WIDTH,i_wofpu+OFFSET_DISPLAY,BLACK); et024006_DrawPixel(j_wofpu+WIDTH,HEIGHT-i_wofpu+OFFSET_DISPLAY,BLACK); } else { et024006_DrawPixel(j_wofpu+WIDTH, i_wofpu+OFFSET_DISPLAY, BLUE_LEV((colour_wofpu*255) / iter_wofpu )+ GREEN_LEV((colour_wofpu*127) / iter_wofpu )+ RED_LEV((colour_wofpu*127) / iter_wofpu )); et024006_DrawPixel(j_wofpu+WIDTH, HEIGHT-i_wofpu+OFFSET_DISPLAY, BLUE_LEV((colour_wofpu*255) / iter_wofpu )+ GREEN_LEV((colour_wofpu*127) / iter_wofpu )+ RED_LEV((colour_wofpu*127) / iter_wofpu )); } x_wofpu += xstep_wofpu; j_wofpu++; }; j_wofpu = 0; y_wofpu += ystep_wofpu; x_wofpu = xstart_wofpu; i_wofpu++; if( cpu_is_timeout(&timer) ) { return 0; } }; return 1; }