/* Compute gnm_log(gamma(a+1)) accurately also for small a (0 < a < 0.5). */ gnm_float lgamma1p (gnm_float a) { const gnm_float eulers_const = GNM_const(0.5772156649015328606065120900824024); /* coeffs[i] holds (zeta(i+2)-1)/(i+2) , i = 1:N, N = 40 : */ const int N = 40; static const gnm_float coeffs[40] = { GNM_const(0.3224670334241132182362075833230126e-0), GNM_const(0.6735230105319809513324605383715000e-1), GNM_const(0.2058080842778454787900092413529198e-1), GNM_const(0.7385551028673985266273097291406834e-2), GNM_const(0.2890510330741523285752988298486755e-2), GNM_const(0.1192753911703260977113935692828109e-2), GNM_const(0.5096695247430424223356548135815582e-3), GNM_const(0.2231547584535793797614188036013401e-3), GNM_const(0.9945751278180853371459589003190170e-4), GNM_const(0.4492623673813314170020750240635786e-4), GNM_const(0.2050721277567069155316650397830591e-4), GNM_const(0.9439488275268395903987425104415055e-5), GNM_const(0.4374866789907487804181793223952411e-5), GNM_const(0.2039215753801366236781900709670839e-5), GNM_const(0.9551412130407419832857179772951265e-6), GNM_const(0.4492469198764566043294290331193655e-6), GNM_const(0.2120718480555466586923135901077628e-6), GNM_const(0.1004322482396809960872083050053344e-6), GNM_const(0.4769810169363980565760193417246730e-7), GNM_const(0.2271109460894316491031998116062124e-7), GNM_const(0.1083865921489695409107491757968159e-7), GNM_const(0.5183475041970046655121248647057669e-8), GNM_const(0.2483674543802478317185008663991718e-8), GNM_const(0.1192140140586091207442548202774640e-8), GNM_const(0.5731367241678862013330194857961011e-9), GNM_const(0.2759522885124233145178149692816341e-9), GNM_const(0.1330476437424448948149715720858008e-9), GNM_const(0.6422964563838100022082448087644648e-10), GNM_const(0.3104424774732227276239215783404066e-10), GNM_const(0.1502138408075414217093301048780668e-10), GNM_const(0.7275974480239079662504549924814047e-11), GNM_const(0.3527742476575915083615072228655483e-11), GNM_const(0.1711991790559617908601084114443031e-11), GNM_const(0.8315385841420284819798357793954418e-12), GNM_const(0.4042200525289440065536008957032895e-12), GNM_const(0.1966475631096616490411045679010286e-12), GNM_const(0.9573630387838555763782200936508615e-13), GNM_const(0.4664076026428374224576492565974577e-13), GNM_const(0.2273736960065972320633279596737272e-13), GNM_const(0.1109139947083452201658320007192334e-13) }; const gnm_float c = GNM_const(0.2273736845824652515226821577978691e-12);/* zeta(N+2)-1 */ gnm_float lgam; int i; if (gnm_abs (a) >= 0.5) return gnm_lgamma (a + 1); /* Abramowitz & Stegun 6.1.33, * also http://functions.wolfram.com/06.11.06.0008.01 */ lgam = c * gnm_logcf (-a / 2, N + 2, 1); for (i = N - 1; i >= 0; i--) lgam = coeffs[i] - a * lgam; return (a * lgam - eulers_const) * a - log1pmx (a); } /* lgamma1p */
gnm_float stirlerr(gnm_float n) { #define S0 GNM_const(0.083333333333333333333) /* 1/12 */ #define S1 GNM_const(0.00277777777777777777778) /* 1/360 */ #define S2 GNM_const(0.00079365079365079365079365) /* 1/1260 */ #define S3 GNM_const(0.000595238095238095238095238) /* 1/1680 */ #define S4 GNM_const(0.0008417508417508417508417508)/* 1/1188 */ /* error for 0, 0.5, 1.0, 1.5, ..., 14.5, 15.0. */ static const gnm_float sferr_halves[31] = { 0.0, /* n=0 - wrong, place holder only */ GNM_const(0.1534264097200273452913848), /* 0.5 */ GNM_const(0.0810614667953272582196702), /* 1.0 */ GNM_const(0.0548141210519176538961390), /* 1.5 */ GNM_const(0.0413406959554092940938221), /* 2.0 */ GNM_const(0.03316287351993628748511048), /* 2.5 */ GNM_const(0.02767792568499833914878929), /* 3.0 */ GNM_const(0.02374616365629749597132920), /* 3.5 */ GNM_const(0.02079067210376509311152277), /* 4.0 */ GNM_const(0.01848845053267318523077934), /* 4.5 */ GNM_const(0.01664469118982119216319487), /* 5.0 */ GNM_const(0.01513497322191737887351255), /* 5.5 */ GNM_const(0.01387612882307074799874573), /* 6.0 */ GNM_const(0.01281046524292022692424986), /* 6.5 */ GNM_const(0.01189670994589177009505572), /* 7.0 */ GNM_const(0.01110455975820691732662991), /* 7.5 */ GNM_const(0.010411265261972096497478567), /* 8.0 */ GNM_const(0.009799416126158803298389475), /* 8.5 */ GNM_const(0.009255462182712732917728637), /* 9.0 */ GNM_const(0.008768700134139385462952823), /* 9.5 */ GNM_const(0.008330563433362871256469318), /* 10.0 */ GNM_const(0.007934114564314020547248100), /* 10.5 */ GNM_const(0.007573675487951840794972024), /* 11.0 */ GNM_const(0.007244554301320383179543912), /* 11.5 */ GNM_const(0.006942840107209529865664152), /* 12.0 */ GNM_const(0.006665247032707682442354394), /* 12.5 */ GNM_const(0.006408994188004207068439631), /* 13.0 */ GNM_const(0.006171712263039457647532867), /* 13.5 */ GNM_const(0.005951370112758847735624416), /* 14.0 */ GNM_const(0.005746216513010115682023589), /* 14.5 */ GNM_const(0.005554733551962801371038690) /* 15.0 */ }; gnm_float nn; if (n <= 15.0) { nn = n + n; if (nn == (int)nn) return(sferr_halves[(int)nn]); return(lgamma1p (n ) - (n + 0.5)*gnm_log(n) + n - M_LN_SQRT_2PI); } nn = n*n; if (n>500) return((S0-S1/nn)/n); if (n> 80) return((S0-(S1-S2/nn)/nn)/n); if (n> 35) return((S0-(S1-(S2-S3/nn)/nn)/nn)/n); /* 15 < n <= 35 : */ return((S0-(S1-(S2-(S3-S4/nn)/nn)/nn)/nn)/n); }
gnm_float axm2 = gnm_fmod (-x, 2.0); gnm_float y = gnm_sinpi (axm2) / M_PIgnum; *signp = axm2 > 1.0 ? +1 : -1; return y == 0 ? gnm_nan : - gnm_log (gnm_abs (y)) - lgamma1p (-x); } } #endif /* ------------------------------------------------------------------------- */ static const gnm_float lanczos_g = GNM_const (808618867.0) / 134217728; /* * This Mathematica sniplet computes the Lanczos gamma coefficients: * * Dr[k_]:=DiagonalMatrix[Join[{1},Array[-Binomial[2*#-1,#]*#&,k]]] * c[k_]:= Array[If[#1+#2==2,1/2,If[#1>=#2,(-1)^(#1+#2)*4^(#2-1)*(#1-1)*(#1+#2-3)!/(#1-#2)!/(2*#2-2)!,0]]&,{k+1,k+1}] * Dc[k_]:=DiagonalMatrix[Array[2*(2*#-3)!!&,k+1]] * B[k_]:=Array[If[#1==1,1,If[#1<=#2,(-1)^(#2-#1)*Binomial[#1+#2-3,#1+#1-3],0]]&,{k+1,k+1}] * M[k_]:=(Dr[k].B[k]).(c[k].Dc[k]) * f[g_,k_]:=Array[Sqrt[2]*(E/(2*(#-1+g)+1))^(#-1/2)&,k+1] * a[g_,k_]:=M[k].f[g,k]*Exp[g]/Sqrt[2*Pi] * * The result of a[g,k] will contain both positive and negative constants. * Most people using the Lanczos series do not understand that a naive * implemetation will suffer significant cancellation errors. The error
static gnm_float gnm_owent (gnm_float h, gnm_float a) { gnm_float weight[10] = { GNM_const(0.0666713443086881375935688098933), GNM_const(0.149451349150580593145776339658), GNM_const(0.219086362515982043995534934228), GNM_const(0.269266719309996355091226921569), GNM_const(0.295524224714752870173892994651), GNM_const(0.295524224714752870173892994651), GNM_const(0.269266719309996355091226921569), GNM_const(0.219086362515982043995534934228), GNM_const(0.149451349150580593145776339658), GNM_const(0.0666713443086881375935688098933) }; gnm_float xtab[10] = {GNM_const(0.026093471482828279922035987916), GNM_const(0.134936633311015489267903311577), GNM_const(0.320590431700975593765672634885), GNM_const(0.566604605870752809200734056834), GNM_const(0.85112566101836878911517399887), GNM_const(1.148874338981631210884826001130), GNM_const(1.433395394129247190799265943166), GNM_const(1.679409568299024406234327365115), GNM_const(1.865063366688984510732096688423), GNM_const(1.973906528517171720077964012084) }; gnm_float hs, h2, as, rt; int i; if (fabs(h) < LIM1) return atan(a) * TWOPI_INVERSE; if (fabs(h) > LIM2 || fabs(a) < LIM1) return 0.0; hs = -0.5 * h * h; h2 = a; as = a * a; if (log(1.0 + as) - hs * as >= LIM3) { gnm_float h1 = 0.5 * a; as *= 0.25; for (;;) { gnm_float rt = as + 1.0; h2 = h1 + (hs * as + LIM3 - log(rt)) / (2.0 * h1 * (1.0 / rt - hs)); as = h2 * h2; if (fabs(h2 - h1) < LIM4) break; h1 = h2; } } rt = 0.0; for (i = 0; i < 10; i++) { gnm_float x = 0.5 * h2 * xtab[i], tmp = 1.0 + x * x; rt += weight[i] * gnm_exp (hs * tmp) / tmp; } return 0.5 * rt * h2 * TWOPI_INVERSE; }
#include <number-match.h> #include <parse-util.h> #include <workbook.h> #include <workbook-control.h> #include <wbc-gtk.h> #include <workbook-view.h> #include <goal-seek.h> #include <mathfunc.h> #include <widgets/gnumeric-expr-entry.h> #include <selection.h> #include <gtk/gtk.h> #include <math.h> #include <string.h> static const gnm_float max_range_val = GNM_const(1e24); #define MAX_CELL_NAME_LEN 20 #define GOALSEEK_KEY "goal-seek-dialog" typedef struct { GladeXML *gui; GtkWidget *dialog; GnmExprEntry *set_cell_entry; GnmExprEntry *change_cell_entry; GtkWidget *to_value_entry; GtkWidget *at_least_entry; GtkWidget *at_most_entry; GtkWidget *close_button; GtkWidget *cancel_button; GtkWidget *apply_button;
static GnmValue * gnumeric_convert (GnmFuncEvalInfo *ei, GnmValue const * const *argv) { /* Weight and mass constants */ #define one_g_to_sg 0.00006852205001 #define one_g_to_lbm 0.002204622915 #define one_g_to_u 6.02217e+23 #define one_g_to_ozm 0.035273972 /* Distance constants */ #define one_m_to_mi (one_m_to_yd / 1760) #define one_m_to_Nmi (1 / GNM_const (1852.0)) #define one_m_to_in (10000 / GNM_const (254.0)) #define one_m_to_ft (one_m_to_in / 12) #define one_m_to_yd (one_m_to_ft / 3) #define one_m_to_ang GNM_const (1e10) #define one_m_to_pica 236.2204724409449 #define one_m_to_Pica one_m_to_pica * 12 /* Time constants */ #define one_yr_to_day 365.25 #define one_yr_to_hr (24 * one_yr_to_day) #define one_yr_to_mn (60 * one_yr_to_hr) #define one_yr_to_sec (60 * one_yr_to_mn) /* Pressure constants */ #define one_Pa_to_atm 0.9869233e-5 #define one_Pa_to_mmHg 0.00750061708 /* Force constants */ #define one_N_to_dyn 100000 #define one_N_to_lbf 0.224808924 /* Power constants */ #define one_HP_to_W 745.701 /* Energy constants */ #define one_J_to_e 9999995.193 #define one_J_to_c 0.239006249 #define one_J_to_cal 0.238846191 #define one_J_to_eV 6.2146e+18 #define one_J_to_HPh (GNM_const (1.0) / (3600 * one_HP_to_W)) #define one_J_to_Wh (GNM_const (1.0) / 3600) #define one_J_to_flb 23.73042222 #define one_J_to_BTU 0.000947815 /* Magnetism constants */ #define one_T_to_ga 10000 /* Temperature constants */ const gnm_float C_K_offset = GNM_const (273.15); /* Liquid measure constants */ #define one_tsp_to_tbs (GNM_const (1.0) / 3) #define one_tsp_to_oz (GNM_const (1.0) / 6) #define one_tsp_to_cup (GNM_const (1.0) / 48) #define one_tsp_to_pt (GNM_const (1.0) / 96) #define one_tsp_to_qt (GNM_const (1.0) / 192) #define one_tsp_to_gal (GNM_const (1.0) / 768) #define one_tsp_to_l 0.004929994 /* Prefixes */ #define yotta GNM_const (1e+24) #define zetta GNM_const (1e+21) #define exa GNM_const (1e+18) #define peta GNM_const (1e+15) #define tera GNM_const (1e+12) #define giga GNM_const (1e+09) #define mega GNM_const (1e+06) #define kilo GNM_const (1e+03) #define hecto GNM_const (1e+02) #define deka GNM_const (1e+01) #define deci GNM_const (1e-01) #define centi GNM_const (1e-02) #define milli GNM_const (1e-03) #define micro GNM_const (1e-06) #define nano GNM_const (1e-09) #define pico GNM_const (1e-12) #define femto GNM_const (1e-15) #define atto GNM_const (1e-18) #define zepto GNM_const (1e-21) #define yocto GNM_const (1e-24) static const eng_convert_unit_t weight_units[] = { { "g", 1.0 }, { "sg", one_g_to_sg }, { "lbm", one_g_to_lbm }, { "u", one_g_to_u }, { "ozm", one_g_to_ozm }, { NULL, 0.0 } }; static const eng_convert_unit_t distance_units[] = { { "m", 1.0 }, { "mi", one_m_to_mi }, { "Nmi", one_m_to_Nmi }, { "in", one_m_to_in }, { "ft", one_m_to_ft }, { "yd", one_m_to_yd }, { "ang", one_m_to_ang }, { "Pica", one_m_to_Pica }, { "picapt", one_m_to_Pica }, { "pica", one_m_to_pica }, { NULL, 0.0 } }; static const eng_convert_unit_t time_units[] = { { "yr", 1.0 }, { "day", one_yr_to_day }, { "hr", one_yr_to_hr }, { "mn", one_yr_to_mn }, { "sec", one_yr_to_sec }, { NULL, 0.0 } }; static const eng_convert_unit_t pressure_units[] = { { "Pa", 1.0 }, { "atm", one_Pa_to_atm }, { "mmHg", one_Pa_to_mmHg }, { NULL, 0.0 } }; static const eng_convert_unit_t force_units[] = { { "N", 1.0 }, { "dyn", one_N_to_dyn }, { "lbf", one_N_to_lbf }, { NULL, 0.0 } }; static const eng_convert_unit_t energy_units[] = { { "J", 1.0 }, { "e", one_J_to_e }, { "c", one_J_to_c }, { "cal", one_J_to_cal }, { "eV", one_J_to_eV }, { "HPh", one_J_to_HPh }, { "Wh", one_J_to_Wh }, { "flb", one_J_to_flb }, { "BTU", one_J_to_BTU }, { NULL, 0.0 } }; static const eng_convert_unit_t power_units[] = { { "HP", 1.0 }, { "W", one_HP_to_W }, { NULL, 0.0 } }; static const eng_convert_unit_t magnetism_units[] = { { "T", 1.0 }, { "ga", one_T_to_ga }, { NULL, 0.0 } }; static const eng_convert_unit_t liquid_units[] = { { "tsp", 1.0 }, { "tbs", one_tsp_to_tbs }, { "oz", one_tsp_to_oz }, { "cup", one_tsp_to_cup }, { "pt", one_tsp_to_pt }, { "qt", one_tsp_to_qt }, { "gal", one_tsp_to_gal }, { "l", one_tsp_to_l }, { NULL, 0.0 } }; static const eng_convert_unit_t prefixes[] = { { "Y", yotta }, { "Z", zetta }, { "E", exa }, { "P", peta }, { "T", tera }, { "G", giga }, { "M", mega }, { "k", kilo }, { "h", hecto }, { "e", deka }, { "d", deci }, { "c", centi }, { "m", milli }, { "u", micro }, { "n", nano }, { "p", pico }, { "f", femto }, { "a", atto }, { "z", zepto }, { "y", yocto }, { NULL,0.0 } }; gnm_float n; char const *from_unit, *to_unit; GnmValue *v; n = value_get_as_float (argv[0]); from_unit = value_peek_string (argv[1]); to_unit = value_peek_string (argv[2]); if (strcmp (from_unit, "C") == 0 && strcmp (to_unit, "F") == 0) return value_new_float (n * 9 / 5 + 32); else if (strcmp (from_unit, "F") == 0 && strcmp (to_unit, "C") == 0) return value_new_float ((n - 32) * 5 / 9); else if (strcmp (from_unit, "F") == 0 && strcmp (to_unit, "F") == 0) return value_new_float (n); else if (strcmp (from_unit, "F") == 0 && strcmp (to_unit, "K") == 0) return value_new_float ((n - 32) * 5 / 9 + C_K_offset); else if (strcmp (from_unit, "K") == 0 && strcmp (to_unit, "F") == 0) return value_new_float ((n - C_K_offset) * 9 / 5 + 32); else if (strcmp (from_unit, "C") == 0 && strcmp (to_unit, "K") == 0) return value_new_float (n + C_K_offset); else if (strcmp (from_unit, "K") == 0 && strcmp (to_unit, "C") == 0) return value_new_float (n - C_K_offset); if (convert (weight_units, prefixes, from_unit, to_unit, n, &v, ei->pos)) return v; if (convert (distance_units, prefixes, from_unit, to_unit, n, &v, ei->pos)) return v; if (convert (time_units, NULL, from_unit, to_unit, n, &v, ei->pos)) return v; if (convert (pressure_units, prefixes, from_unit, to_unit, n, &v, ei->pos)) return v; if (convert (force_units, prefixes, from_unit, to_unit, n, &v, ei->pos)) return v; if (convert (energy_units, prefixes, from_unit, to_unit, n, &v, ei->pos)) return v; if (convert (power_units, prefixes, from_unit, to_unit, n, &v, ei->pos)) return v; if (convert (magnetism_units, prefixes, from_unit, to_unit, n, &v, ei->pos)) return v; if (convert (liquid_units, prefixes, from_unit, to_unit, n, &v, ei->pos)) return v; if (convert (magnetism_units, prefixes, from_unit, to_unit, n, &v, ei->pos)) return v; return value_new_error_NA (ei->pos); }