📄 exp.c
字号:
/* specfunc/exp.c * * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* Author: G. Jungman */#include <config.h>#include <gsl/gsl_math.h>#include <gsl/gsl_errno.h>#include "gsl_sf_gamma.h"#include "gsl_sf_exp.h"#include "error.h"/* Evaluate the continued fraction for exprel. * [Abramowitz+Stegun, 4.2.41] */staticintexprel_n_CF(const int N, const double x, gsl_sf_result * result){ const double RECUR_BIG = GSL_SQRT_DBL_MAX; const int maxiter = 5000; int n = 1; double Anm2 = 1.0; double Bnm2 = 0.0; double Anm1 = 0.0; double Bnm1 = 1.0; double a1 = 1.0; double b1 = 1.0; double a2 = -x; double b2 = N+1; double an, bn; double fn; double An = b1*Anm1 + a1*Anm2; /* A1 */ double Bn = b1*Bnm1 + a1*Bnm2; /* B1 */ /* One explicit step, before we get to the main pattern. */ n++; Anm2 = Anm1; Bnm2 = Bnm1; Anm1 = An; Bnm1 = Bn; An = b2*Anm1 + a2*Anm2; /* A2 */ Bn = b2*Bnm1 + a2*Bnm2; /* B2 */ fn = An/Bn; while(n < maxiter) { double old_fn; double del; n++; Anm2 = Anm1; Bnm2 = Bnm1; Anm1 = An; Bnm1 = Bn; an = ( GSL_IS_ODD(n) ? ((n-1)/2)*x : -(N+(n/2)-1)*x ); bn = N + n - 1; An = bn*Anm1 + an*Anm2; Bn = bn*Bnm1 + an*Bnm2; if(fabs(An) > RECUR_BIG || fabs(Bn) > RECUR_BIG) { An /= RECUR_BIG; Bn /= RECUR_BIG; Anm1 /= RECUR_BIG; Bnm1 /= RECUR_BIG; Anm2 /= RECUR_BIG; Bnm2 /= RECUR_BIG; } old_fn = fn; fn = An/Bn; del = old_fn/fn; if(fabs(del - 1.0) < 2.0*GSL_DBL_EPSILON) break; } result->val = fn; result->err = 2.0*(n+1.0)*GSL_DBL_EPSILON*fabs(fn); if(n == maxiter) GSL_ERROR ("error", GSL_EMAXITER); else return GSL_SUCCESS;}/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/#ifndef HIDE_INLINE_STATICint gsl_sf_exp_e(const double x, gsl_sf_result * result){ if(x > GSL_LOG_DBL_MAX) { OVERFLOW_ERROR(result); } else if(x < GSL_LOG_DBL_MIN) { UNDERFLOW_ERROR(result); } else { result->val = exp(x); result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val); return GSL_SUCCESS; }}#endifint gsl_sf_exp_e10_e(const double x, gsl_sf_result_e10 * result){ if(x > INT_MAX-1) { OVERFLOW_ERROR_E10(result); } else if(x < INT_MIN+1) { UNDERFLOW_ERROR_E10(result); } else { const int N = (int) floor(x/M_LN10); result->val = exp(x-N*M_LN10); result->err = 2.0 * (fabs(x)+1.0) * GSL_DBL_EPSILON * fabs(result->val); result->e10 = N; return GSL_SUCCESS; }}int gsl_sf_exp_mult_e(const double x, const double y, gsl_sf_result * result){ const double ay = fabs(y); if(y == 0.0) { result->val = 0.0; result->err = 0.0; return GSL_SUCCESS; } else if( ( x < 0.5*GSL_LOG_DBL_MAX && x > 0.5*GSL_LOG_DBL_MIN) && (ay < 0.8*GSL_SQRT_DBL_MAX && ay > 1.2*GSL_SQRT_DBL_MIN) ) { const double ex = exp(x); result->val = y * ex; result->err = (2.0 + fabs(x)) * GSL_DBL_EPSILON * fabs(result->val); return GSL_SUCCESS; } else { const double ly = log(ay); const double lnr = x + ly; if(lnr > GSL_LOG_DBL_MAX - 0.01) { OVERFLOW_ERROR(result); } else if(lnr < GSL_LOG_DBL_MIN + 0.01) { UNDERFLOW_ERROR(result); } else { const double sy = GSL_SIGN(y); const double M = floor(x); const double N = floor(ly); const double a = x - M; const double b = ly - N; const double berr = 2.0 * GSL_DBL_EPSILON * (fabs(ly) + fabs(N)); result->val = sy * exp(M+N) * exp(a+b); result->err = berr * fabs(result->val); result->err += 2.0 * GSL_DBL_EPSILON * (M + N + 1.0) * fabs(result->val); return GSL_SUCCESS; } }}int gsl_sf_exp_mult_e10_e(const double x, const double y, gsl_sf_result_e10 * result){ const double ay = fabs(y); if(y == 0.0) { result->val = 0.0; result->err = 0.0; result->e10 = 0; return GSL_SUCCESS; } else if( ( x < 0.5*GSL_LOG_DBL_MAX && x > 0.5*GSL_LOG_DBL_MIN) && (ay < 0.8*GSL_SQRT_DBL_MAX && ay > 1.2*GSL_SQRT_DBL_MIN) ) { const double ex = exp(x); result->val = y * ex; result->err = (2.0 + fabs(x)) * GSL_DBL_EPSILON * fabs(result->val); result->e10 = 0; return GSL_SUCCESS; } else { const double ly = log(ay); const double l10_val = (x + ly)/M_LN10; if(l10_val > INT_MAX-1) { OVERFLOW_ERROR_E10(result); } else if(l10_val < INT_MIN+1) { UNDERFLOW_ERROR_E10(result); } else { const double sy = GSL_SIGN(y); const int N = (int) floor(l10_val); const double arg_val = (l10_val - N) * M_LN10; const double arg_err = 2.0 * GSL_DBL_EPSILON * fabs(ly); result->val = sy * exp(arg_val); result->err = arg_err * fabs(result->val); result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); result->e10 = N; return GSL_SUCCESS; } }}int gsl_sf_exp_mult_err_e(const double x, const double dx, const double y, const double dy, gsl_sf_result * result){ const double ay = fabs(y); if(y == 0.0) { result->val = 0.0; result->err = fabs(dy * exp(x)); return GSL_SUCCESS; } else if( ( x < 0.5*GSL_LOG_DBL_MAX && x > 0.5*GSL_LOG_DBL_MIN) && (ay < 0.8*GSL_SQRT_DBL_MAX && ay > 1.2*GSL_SQRT_DBL_MIN) ) { double ex = exp(x); result->val = y * ex; result->err = ex * (fabs(dy) + fabs(y*dx)); result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return GSL_SUCCESS; } else { const double ly = log(ay); const double lnr = x + ly; if(lnr > GSL_LOG_DBL_MAX - 0.01) { OVERFLOW_ERROR(result); } else if(lnr < GSL_LOG_DBL_MIN + 0.01) { UNDERFLOW_ERROR(result); } else { const double sy = GSL_SIGN(y); const double M = floor(x); const double N = floor(ly); const double a = x - M; const double b = ly - N; const double eMN = exp(M+N); const double eab = exp(a+b); result->val = sy * eMN * eab; result->err = eMN * eab * 2.0*GSL_DBL_EPSILON; result->err += eMN * eab * fabs(dy/y); result->err += eMN * eab * fabs(dx); return GSL_SUCCESS; } }}int gsl_sf_exp_mult_err_e10_e(const double x, const double dx, const double y, const double dy, gsl_sf_result_e10 * result){ const double ay = fabs(y); if(y == 0.0) { result->val = 0.0; result->err = fabs(dy * exp(x)); result->e10 = 0; return GSL_SUCCESS; } else if( ( x < 0.5*GSL_LOG_DBL_MAX && x > 0.5*GSL_LOG_DBL_MIN) && (ay < 0.8*GSL_SQRT_DBL_MAX && ay > 1.2*GSL_SQRT_DBL_MIN) ) { const double ex = exp(x); result->val = y * ex; result->err = ex * (fabs(dy) + fabs(y*dx)); result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); result->e10 = 0; return GSL_SUCCESS; } else { const double ly = log(ay); const double l10_val = (x + ly)/M_LN10; if(l10_val > INT_MAX-1) { OVERFLOW_ERROR_E10(result);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -