Ruby 1.9.3p327(2012-11-10revision37606)
math.c
Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   math.c -
00004 
00005   $Author: ngoto $
00006   created at: Tue Jan 25 14:12:56 JST 1994
00007 
00008   Copyright (C) 1993-2007 Yukihiro Matsumoto
00009 
00010 **********************************************************************/
00011 
00012 #include "ruby/ruby.h"
00013 #include "internal.h"
00014 #include <math.h>
00015 #include <errno.h>
00016 
00017 #if defined(HAVE_SIGNBIT) && defined(__GNUC__) && defined(__sun__) && \
00018     !defined(signbit)
00019     extern int signbit(double);
00020 #endif
00021 
00022 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
00023 
00024 VALUE rb_mMath;
00025 VALUE rb_eMathDomainError;
00026 
00027 #define Need_Float(x) do {if (TYPE(x) != T_FLOAT) {(x) = rb_to_float(x);}} while(0)
00028 #define Need_Float2(x,y) do {\
00029     Need_Float(x);\
00030     Need_Float(y);\
00031 } while (0)
00032 
00033 #define domain_error(msg) \
00034     rb_raise(rb_eMathDomainError, "Numerical argument is out of domain - " #msg);
00035 
00036 /*
00037  *  call-seq:
00038  *     Math.atan2(y, x)  -> float
00039  *
00040  *  Computes the arc tangent given <i>y</i> and <i>x</i>. Returns
00041  *  -PI..PI.
00042  *
00043  *    Math.atan2(-0.0, -1.0) #=> -3.141592653589793
00044  *    Math.atan2(-1.0, -1.0) #=> -2.356194490192345
00045  *    Math.atan2(-1.0, 0.0)  #=> -1.5707963267948966
00046  *    Math.atan2(-1.0, 1.0)  #=> -0.7853981633974483
00047  *    Math.atan2(-0.0, 1.0)  #=> -0.0
00048  *    Math.atan2(0.0, 1.0)   #=> 0.0
00049  *    Math.atan2(1.0, 1.0)   #=> 0.7853981633974483
00050  *    Math.atan2(1.0, 0.0)   #=> 1.5707963267948966
00051  *    Math.atan2(1.0, -1.0)  #=> 2.356194490192345
00052  *    Math.atan2(0.0, -1.0)  #=> 3.141592653589793
00053  *
00054  */
00055 
00056 static VALUE
00057 math_atan2(VALUE obj, VALUE y, VALUE x)
00058 {
00059 #ifndef M_PI
00060 # define M_PI 3.14159265358979323846
00061 #endif
00062     double dx, dy;
00063     Need_Float2(y, x);
00064     dx = RFLOAT_VALUE(x);
00065     dy = RFLOAT_VALUE(y);
00066     if (dx == 0.0 && dy == 0.0) {
00067         if (!signbit(dx))
00068             return DBL2NUM(dy);
00069         if (!signbit(dy))
00070             return DBL2NUM(M_PI);
00071         return DBL2NUM(-M_PI);
00072     }
00073     if (isinf(dx) && isinf(dy)) domain_error("atan2");
00074     return DBL2NUM(atan2(dy, dx));
00075 }
00076 
00077 
00078 /*
00079  *  call-seq:
00080  *     Math.cos(x)    -> float
00081  *
00082  *  Computes the cosine of <i>x</i> (expressed in radians). Returns
00083  *  -1..1.
00084  */
00085 
00086 static VALUE
00087 math_cos(VALUE obj, VALUE x)
00088 {
00089     Need_Float(x);
00090     return DBL2NUM(cos(RFLOAT_VALUE(x)));
00091 }
00092 
00093 /*
00094  *  call-seq:
00095  *     Math.sin(x)    -> float
00096  *
00097  *  Computes the sine of <i>x</i> (expressed in radians). Returns
00098  *  -1..1.
00099  */
00100 
00101 static VALUE
00102 math_sin(VALUE obj, VALUE x)
00103 {
00104     Need_Float(x);
00105 
00106     return DBL2NUM(sin(RFLOAT_VALUE(x)));
00107 }
00108 
00109 
00110 /*
00111  *  call-seq:
00112  *     Math.tan(x)    -> float
00113  *
00114  *  Returns the tangent of <i>x</i> (expressed in radians).
00115  */
00116 
00117 static VALUE
00118 math_tan(VALUE obj, VALUE x)
00119 {
00120     Need_Float(x);
00121 
00122     return DBL2NUM(tan(RFLOAT_VALUE(x)));
00123 }
00124 
00125 /*
00126  *  call-seq:
00127  *     Math.acos(x)    -> float
00128  *
00129  *  Computes the arc cosine of <i>x</i>. Returns 0..PI.
00130  */
00131 
00132 static VALUE
00133 math_acos(VALUE obj, VALUE x)
00134 {
00135     double d0, d;
00136 
00137     Need_Float(x);
00138     d0 = RFLOAT_VALUE(x);
00139     /* check for domain error */
00140     if (d0 < -1.0 || 1.0 < d0) domain_error("acos");
00141     d = acos(d0);
00142     return DBL2NUM(d);
00143 }
00144 
00145 /*
00146  *  call-seq:
00147  *     Math.asin(x)    -> float
00148  *
00149  *  Computes the arc sine of <i>x</i>. Returns -{PI/2} .. {PI/2}.
00150  */
00151 
00152 static VALUE
00153 math_asin(VALUE obj, VALUE x)
00154 {
00155     double d0, d;
00156 
00157     Need_Float(x);
00158     d0 = RFLOAT_VALUE(x);
00159     /* check for domain error */
00160     if (d0 < -1.0 || 1.0 < d0) domain_error("asin");
00161     d = asin(d0);
00162     return DBL2NUM(d);
00163 }
00164 
00165 /*
00166  *  call-seq:
00167  *     Math.atan(x)    -> float
00168  *
00169  *  Computes the arc tangent of <i>x</i>. Returns -{PI/2} .. {PI/2}.
00170  */
00171 
00172 static VALUE
00173 math_atan(VALUE obj, VALUE x)
00174 {
00175     Need_Float(x);
00176     return DBL2NUM(atan(RFLOAT_VALUE(x)));
00177 }
00178 
00179 #ifndef HAVE_COSH
00180 double
00181 cosh(double x)
00182 {
00183     return (exp(x) + exp(-x)) / 2;
00184 }
00185 #endif
00186 
00187 /*
00188  *  call-seq:
00189  *     Math.cosh(x)    -> float
00190  *
00191  *  Computes the hyperbolic cosine of <i>x</i> (expressed in radians).
00192  */
00193 
00194 static VALUE
00195 math_cosh(VALUE obj, VALUE x)
00196 {
00197     Need_Float(x);
00198 
00199     return DBL2NUM(cosh(RFLOAT_VALUE(x)));
00200 }
00201 
00202 #ifndef HAVE_SINH
00203 double
00204 sinh(double x)
00205 {
00206     return (exp(x) - exp(-x)) / 2;
00207 }
00208 #endif
00209 
00210 /*
00211  *  call-seq:
00212  *     Math.sinh(x)    -> float
00213  *
00214  *  Computes the hyperbolic sine of <i>x</i> (expressed in
00215  *  radians).
00216  */
00217 
00218 static VALUE
00219 math_sinh(VALUE obj, VALUE x)
00220 {
00221     Need_Float(x);
00222     return DBL2NUM(sinh(RFLOAT_VALUE(x)));
00223 }
00224 
00225 #ifndef HAVE_TANH
00226 double
00227 tanh(double x)
00228 {
00229     return sinh(x) / cosh(x);
00230 }
00231 #endif
00232 
00233 /*
00234  *  call-seq:
00235  *     Math.tanh()    -> float
00236  *
00237  *  Computes the hyperbolic tangent of <i>x</i> (expressed in
00238  *  radians).
00239  */
00240 
00241 static VALUE
00242 math_tanh(VALUE obj, VALUE x)
00243 {
00244     Need_Float(x);
00245     return DBL2NUM(tanh(RFLOAT_VALUE(x)));
00246 }
00247 
00248 /*
00249  *  call-seq:
00250  *     Math.acosh(x)    -> float
00251  *
00252  *  Computes the inverse hyperbolic cosine of <i>x</i>.
00253  */
00254 
00255 static VALUE
00256 math_acosh(VALUE obj, VALUE x)
00257 {
00258     double d0, d;
00259 
00260     Need_Float(x);
00261     d0 = RFLOAT_VALUE(x);
00262     /* check for domain error */
00263     if (d0 < 1.0) domain_error("acosh");
00264     d = acosh(d0);
00265     return DBL2NUM(d);
00266 }
00267 
00268 /*
00269  *  call-seq:
00270  *     Math.asinh(x)    -> float
00271  *
00272  *  Computes the inverse hyperbolic sine of <i>x</i>.
00273  */
00274 
00275 static VALUE
00276 math_asinh(VALUE obj, VALUE x)
00277 {
00278     Need_Float(x);
00279     return DBL2NUM(asinh(RFLOAT_VALUE(x)));
00280 }
00281 
00282 /*
00283  *  call-seq:
00284  *     Math.atanh(x)    -> float
00285  *
00286  *  Computes the inverse hyperbolic tangent of <i>x</i>.
00287  */
00288 
00289 static VALUE
00290 math_atanh(VALUE obj, VALUE x)
00291 {
00292     double d0, d;
00293 
00294     Need_Float(x);
00295     d0 = RFLOAT_VALUE(x);
00296     /* check for domain error */
00297     if (d0 <  -1.0 || +1.0 <  d0) domain_error("atanh");
00298     /* check for pole error */
00299     if (d0 == -1.0) return DBL2NUM(-INFINITY);
00300     if (d0 == +1.0) return DBL2NUM(+INFINITY);
00301     d = atanh(d0);
00302     return DBL2NUM(d);
00303 }
00304 
00305 /*
00306  *  call-seq:
00307  *     Math.exp(x)    -> float
00308  *
00309  *  Returns e**x.
00310  *
00311  *    Math.exp(0)       #=> 1.0
00312  *    Math.exp(1)       #=> 2.718281828459045
00313  *    Math.exp(1.5)     #=> 4.4816890703380645
00314  *
00315  */
00316 
00317 static VALUE
00318 math_exp(VALUE obj, VALUE x)
00319 {
00320     Need_Float(x);
00321     return DBL2NUM(exp(RFLOAT_VALUE(x)));
00322 }
00323 
00324 #if defined __CYGWIN__
00325 # include <cygwin/version.h>
00326 # if CYGWIN_VERSION_DLL_MAJOR < 1005
00327 #  define nan(x) nan()
00328 # endif
00329 # define log(x) ((x) < 0.0 ? nan("") : log(x))
00330 # define log10(x) ((x) < 0.0 ? nan("") : log10(x))
00331 #endif
00332 
00333 /*
00334  *  call-seq:
00335  *     Math.log(numeric)    -> float
00336  *     Math.log(num,base)   -> float
00337  *
00338  *  Returns the natural logarithm of <i>numeric</i>.
00339  *  If additional second argument is given, it will be the base
00340  *  of logarithm.
00341  *
00342  *    Math.log(1)          #=> 0.0
00343  *    Math.log(Math::E)    #=> 1.0
00344  *    Math.log(Math::E**3) #=> 3.0
00345  *    Math.log(12,3)       #=> 2.2618595071429146
00346  *
00347  */
00348 
00349 static VALUE
00350 math_log(int argc, VALUE *argv)
00351 {
00352     VALUE x, base;
00353     double d0, d;
00354 
00355     rb_scan_args(argc, argv, "11", &x, &base);
00356     Need_Float(x);
00357     d0 = RFLOAT_VALUE(x);
00358     /* check for domain error */
00359     if (d0 < 0.0) domain_error("log");
00360     /* check for pole error */
00361     if (d0 == 0.0) return DBL2NUM(-INFINITY);
00362     d = log(d0);
00363     if (argc == 2) {
00364         Need_Float(base);
00365         d /= log(RFLOAT_VALUE(base));
00366     }
00367     return DBL2NUM(d);
00368 }
00369 
00370 #ifndef log2
00371 #ifndef HAVE_LOG2
00372 double
00373 log2(double x)
00374 {
00375     return log10(x)/log10(2.0);
00376 }
00377 #else
00378 extern double log2(double);
00379 #endif
00380 #endif
00381 
00382 /*
00383  *  call-seq:
00384  *     Math.log2(numeric)    -> float
00385  *
00386  *  Returns the base 2 logarithm of <i>numeric</i>.
00387  *
00388  *    Math.log2(1)      #=> 0.0
00389  *    Math.log2(2)      #=> 1.0
00390  *    Math.log2(32768)  #=> 15.0
00391  *    Math.log2(65536)  #=> 16.0
00392  *
00393  */
00394 
00395 static VALUE
00396 math_log2(VALUE obj, VALUE x)
00397 {
00398     double d0, d;
00399 
00400     Need_Float(x);
00401     d0 = RFLOAT_VALUE(x);
00402     /* check for domain error */
00403     if (d0 < 0.0) domain_error("log2");
00404     /* check for pole error */
00405     if (d0 == 0.0) return DBL2NUM(-INFINITY);
00406     d = log2(d0);
00407     return DBL2NUM(d);
00408 }
00409 
00410 /*
00411  *  call-seq:
00412  *     Math.log10(numeric)    -> float
00413  *
00414  *  Returns the base 10 logarithm of <i>numeric</i>.
00415  *
00416  *    Math.log10(1)       #=> 0.0
00417  *    Math.log10(10)      #=> 1.0
00418  *    Math.log10(10**100) #=> 100.0
00419  *
00420  */
00421 
00422 static VALUE
00423 math_log10(VALUE obj, VALUE x)
00424 {
00425     double d0, d;
00426 
00427     Need_Float(x);
00428     d0 = RFLOAT_VALUE(x);
00429     /* check for domain error */
00430     if (d0 < 0.0) domain_error("log10");
00431     /* check for pole error */
00432     if (d0 == 0.0) return DBL2NUM(-INFINITY);
00433     d = log10(d0);
00434     return DBL2NUM(d);
00435 }
00436 
00437 /*
00438  *  call-seq:
00439  *     Math.sqrt(numeric)    -> float
00440  *
00441  *  Returns the non-negative square root of <i>numeric</i>.
00442  *
00443  *    0.upto(10) {|x|
00444  *      p [x, Math.sqrt(x), Math.sqrt(x)**2]
00445  *    }
00446  *    #=>
00447  *    [0, 0.0, 0.0]
00448  *    [1, 1.0, 1.0]
00449  *    [2, 1.4142135623731, 2.0]
00450  *    [3, 1.73205080756888, 3.0]
00451  *    [4, 2.0, 4.0]
00452  *    [5, 2.23606797749979, 5.0]
00453  *    [6, 2.44948974278318, 6.0]
00454  *    [7, 2.64575131106459, 7.0]
00455  *    [8, 2.82842712474619, 8.0]
00456  *    [9, 3.0, 9.0]
00457  *    [10, 3.16227766016838, 10.0]
00458  *
00459  */
00460 
00461 static VALUE
00462 math_sqrt(VALUE obj, VALUE x)
00463 {
00464     double d0, d;
00465 
00466     Need_Float(x);
00467     d0 = RFLOAT_VALUE(x);
00468     /* check for domain error */
00469     if (d0 < 0.0) domain_error("sqrt");
00470     if (d0 == 0.0) return DBL2NUM(0.0);
00471     d = sqrt(d0);
00472     return DBL2NUM(d);
00473 }
00474 
00475 /*
00476  *  call-seq:
00477  *     Math.cbrt(numeric)    -> float
00478  *
00479  *  Returns the cube root of <i>numeric</i>.
00480  *
00481  *    -9.upto(9) {|x|
00482  *      p [x, Math.cbrt(x), Math.cbrt(x)**3]
00483  *    }
00484  *    #=>
00485  *    [-9, -2.0800838230519, -9.0]
00486  *    [-8, -2.0, -8.0]
00487  *    [-7, -1.91293118277239, -7.0]
00488  *    [-6, -1.81712059283214, -6.0]
00489  *    [-5, -1.7099759466767, -5.0]
00490  *    [-4, -1.5874010519682, -4.0]
00491  *    [-3, -1.44224957030741, -3.0]
00492  *    [-2, -1.25992104989487, -2.0]
00493  *    [-1, -1.0, -1.0]
00494  *    [0, 0.0, 0.0]
00495  *    [1, 1.0, 1.0]
00496  *    [2, 1.25992104989487, 2.0]
00497  *    [3, 1.44224957030741, 3.0]
00498  *    [4, 1.5874010519682, 4.0]
00499  *    [5, 1.7099759466767, 5.0]
00500  *    [6, 1.81712059283214, 6.0]
00501  *    [7, 1.91293118277239, 7.0]
00502  *    [8, 2.0, 8.0]
00503  *    [9, 2.0800838230519, 9.0]
00504  *
00505  */
00506 
00507 static VALUE
00508 math_cbrt(VALUE obj, VALUE x)
00509 {
00510     Need_Float(x);
00511     return DBL2NUM(cbrt(RFLOAT_VALUE(x)));
00512 }
00513 
00514 /*
00515  *  call-seq:
00516  *     Math.frexp(numeric)    -> [ fraction, exponent ]
00517  *
00518  *  Returns a two-element array containing the normalized fraction (a
00519  *  <code>Float</code>) and exponent (a <code>Fixnum</code>) of
00520  *  <i>numeric</i>.
00521  *
00522  *     fraction, exponent = Math.frexp(1234)   #=> [0.6025390625, 11]
00523  *     fraction * 2**exponent                  #=> 1234.0
00524  */
00525 
00526 static VALUE
00527 math_frexp(VALUE obj, VALUE x)
00528 {
00529     double d;
00530     int exp;
00531 
00532     Need_Float(x);
00533 
00534     d = frexp(RFLOAT_VALUE(x), &exp);
00535     return rb_assoc_new(DBL2NUM(d), INT2NUM(exp));
00536 }
00537 
00538 /*
00539  *  call-seq:
00540  *     Math.ldexp(flt, int) -> float
00541  *
00542  *  Returns the value of <i>flt</i>*(2**<i>int</i>).
00543  *
00544  *     fraction, exponent = Math.frexp(1234)
00545  *     Math.ldexp(fraction, exponent)   #=> 1234.0
00546  */
00547 
00548 static VALUE
00549 math_ldexp(VALUE obj, VALUE x, VALUE n)
00550 {
00551     Need_Float(x);
00552     return DBL2NUM(ldexp(RFLOAT_VALUE(x), NUM2INT(n)));
00553 }
00554 
00555 /*
00556  *  call-seq:
00557  *     Math.hypot(x, y)    -> float
00558  *
00559  *  Returns sqrt(x**2 + y**2), the hypotenuse of a right-angled triangle
00560  *  with sides <i>x</i> and <i>y</i>.
00561  *
00562  *     Math.hypot(3, 4)   #=> 5.0
00563  */
00564 
00565 static VALUE
00566 math_hypot(VALUE obj, VALUE x, VALUE y)
00567 {
00568     Need_Float2(x, y);
00569     return DBL2NUM(hypot(RFLOAT_VALUE(x), RFLOAT_VALUE(y)));
00570 }
00571 
00572 /*
00573  * call-seq:
00574  *    Math.erf(x)  -> float
00575  *
00576  *  Calculates the error function of x.
00577  */
00578 
00579 static VALUE
00580 math_erf(VALUE obj, VALUE x)
00581 {
00582     Need_Float(x);
00583     return DBL2NUM(erf(RFLOAT_VALUE(x)));
00584 }
00585 
00586 /*
00587  * call-seq:
00588  *    Math.erfc(x)  -> float
00589  *
00590  *  Calculates the complementary error function of x.
00591  */
00592 
00593 static VALUE
00594 math_erfc(VALUE obj, VALUE x)
00595 {
00596     Need_Float(x);
00597     return DBL2NUM(erfc(RFLOAT_VALUE(x)));
00598 }
00599 
00600 /*
00601  * call-seq:
00602  *    Math.gamma(x)  -> float
00603  *
00604  *  Calculates the gamma function of x.
00605  *
00606  *  Note that gamma(n) is same as fact(n-1) for integer n > 0.
00607  *  However gamma(n) returns float and can be an approximation.
00608  *
00609  *   def fact(n) (1..n).inject(1) {|r,i| r*i } end
00610  *   1.upto(26) {|i| p [i, Math.gamma(i), fact(i-1)] }
00611  *   #=> [1, 1.0, 1]
00612  *   #   [2, 1.0, 1]
00613  *   #   [3, 2.0, 2]
00614  *   #   [4, 6.0, 6]
00615  *   #   [5, 24.0, 24]
00616  *   #   [6, 120.0, 120]
00617  *   #   [7, 720.0, 720]
00618  *   #   [8, 5040.0, 5040]
00619  *   #   [9, 40320.0, 40320]
00620  *   #   [10, 362880.0, 362880]
00621  *   #   [11, 3628800.0, 3628800]
00622  *   #   [12, 39916800.0, 39916800]
00623  *   #   [13, 479001600.0, 479001600]
00624  *   #   [14, 6227020800.0, 6227020800]
00625  *   #   [15, 87178291200.0, 87178291200]
00626  *   #   [16, 1307674368000.0, 1307674368000]
00627  *   #   [17, 20922789888000.0, 20922789888000]
00628  *   #   [18, 355687428096000.0, 355687428096000]
00629  *   #   [19, 6.402373705728e+15, 6402373705728000]
00630  *   #   [20, 1.21645100408832e+17, 121645100408832000]
00631  *   #   [21, 2.43290200817664e+18, 2432902008176640000]
00632  *   #   [22, 5.109094217170944e+19, 51090942171709440000]
00633  *   #   [23, 1.1240007277776077e+21, 1124000727777607680000]
00634  *   #   [24, 2.5852016738885062e+22, 25852016738884976640000]
00635  *   #   [25, 6.204484017332391e+23, 620448401733239439360000]
00636  *   #   [26, 1.5511210043330954e+25, 15511210043330985984000000]
00637  *
00638  */
00639 
00640 static VALUE
00641 math_gamma(VALUE obj, VALUE x)
00642 {
00643     static const double fact_table[] = {
00644         /* fact(0) */ 1.0,
00645         /* fact(1) */ 1.0,
00646         /* fact(2) */ 2.0,
00647         /* fact(3) */ 6.0,
00648         /* fact(4) */ 24.0,
00649         /* fact(5) */ 120.0,
00650         /* fact(6) */ 720.0,
00651         /* fact(7) */ 5040.0,
00652         /* fact(8) */ 40320.0,
00653         /* fact(9) */ 362880.0,
00654         /* fact(10) */ 3628800.0,
00655         /* fact(11) */ 39916800.0,
00656         /* fact(12) */ 479001600.0,
00657         /* fact(13) */ 6227020800.0,
00658         /* fact(14) */ 87178291200.0,
00659         /* fact(15) */ 1307674368000.0,
00660         /* fact(16) */ 20922789888000.0,
00661         /* fact(17) */ 355687428096000.0,
00662         /* fact(18) */ 6402373705728000.0,
00663         /* fact(19) */ 121645100408832000.0,
00664         /* fact(20) */ 2432902008176640000.0,
00665         /* fact(21) */ 51090942171709440000.0,
00666         /* fact(22) */ 1124000727777607680000.0,
00667         /* fact(23)=25852016738884976640000 needs 56bit mantissa which is
00668          * impossible to represent exactly in IEEE 754 double which have
00669          * 53bit mantissa. */
00670     };
00671     double d0, d;
00672     double intpart, fracpart;
00673     Need_Float(x);
00674     d0 = RFLOAT_VALUE(x);
00675     /* check for domain error */
00676     if (isinf(d0) && signbit(d0)) domain_error("gamma");
00677     fracpart = modf(d0, &intpart);
00678     if (fracpart == 0.0) {
00679         if (intpart < 0) domain_error("gamma");
00680         if (0 < intpart &&
00681             intpart - 1 < (double)numberof(fact_table)) {
00682             return DBL2NUM(fact_table[(int)intpart - 1]);
00683         }
00684     }
00685     d = tgamma(d0);
00686     return DBL2NUM(d);
00687 }
00688 
00689 /*
00690  * call-seq:
00691  *    Math.lgamma(x)  -> [float, -1 or 1]
00692  *
00693  *  Calculates the logarithmic gamma of x and
00694  *  the sign of gamma of x.
00695  *
00696  *  Math.lgamma(x) is same as
00697  *   [Math.log(Math.gamma(x).abs), Math.gamma(x) < 0 ? -1 : 1]
00698  *  but avoid overflow by Math.gamma(x) for large x.
00699  */
00700 
00701 static VALUE
00702 math_lgamma(VALUE obj, VALUE x)
00703 {
00704     double d0, d;
00705     int sign=1;
00706     VALUE v;
00707     Need_Float(x);
00708     d0 = RFLOAT_VALUE(x);
00709     /* check for domain error */
00710     if (isinf(d0)) {
00711         if (signbit(d0)) domain_error("lgamma");
00712         return rb_assoc_new(DBL2NUM(INFINITY), INT2FIX(1));
00713     }
00714     d = lgamma_r(d0, &sign);
00715     v = DBL2NUM(d);
00716     return rb_assoc_new(v, INT2FIX(sign));
00717 }
00718 
00719 
00720 #define exp1(n) \
00721 VALUE \
00722 rb_math_##n(VALUE x)\
00723 {\
00724     return math_##n(rb_mMath, x);\
00725 }
00726 
00727 #define exp2(n) \
00728 VALUE \
00729 rb_math_##n(VALUE x, VALUE y)\
00730 {\
00731     return math_##n(rb_mMath, x, y);\
00732 }
00733 
00734 exp2(atan2)
00735 exp1(cos)
00736 exp1(cosh)
00737 exp1(exp)
00738 exp2(hypot)
00739 
00740 VALUE
00741 rb_math_log(int argc, VALUE *argv)
00742 {
00743     return math_log(argc, argv);
00744 }
00745 
00746 exp1(sin)
00747 exp1(sinh)
00748 exp1(sqrt)
00749 
00750 
00751 /*
00752  *  Document-class: Math::DomainError
00753  *
00754  *  Raised when a mathematical function is evaluated outside of its
00755  *  domain of definition.
00756  *
00757  *  For example, since +cos+ returns values in the range -1..1,
00758  *  its inverse function +acos+ is only defined on that interval:
00759  *
00760  *     Math.acos(42)
00761  *
00762  *  <em>produces:</em>
00763  *
00764  *     Math::DomainError: Numerical argument is out of domain - "acos"
00765  */
00766 
00767 /*
00768  *  Document-class: Math
00769  *
00770  *  The <code>Math</code> module contains module functions for basic
00771  *  trigonometric and transcendental functions. See class
00772  *  <code>Float</code> for a list of constants that
00773  *  define Ruby's floating point accuracy.
00774  */
00775 
00776 
00777 void
00778 Init_Math(void)
00779 {
00780     rb_mMath = rb_define_module("Math");
00781     rb_eMathDomainError = rb_define_class_under(rb_mMath, "DomainError", rb_eStandardError);
00782 
00783 #ifdef M_PI
00784     rb_define_const(rb_mMath, "PI", DBL2NUM(M_PI));
00785 #else
00786     rb_define_const(rb_mMath, "PI", DBL2NUM(atan(1.0)*4.0));
00787 #endif
00788 
00789 #ifdef M_E
00790     rb_define_const(rb_mMath, "E", DBL2NUM(M_E));
00791 #else
00792     rb_define_const(rb_mMath, "E", DBL2NUM(exp(1.0)));
00793 #endif
00794 
00795     rb_define_module_function(rb_mMath, "atan2", math_atan2, 2);
00796     rb_define_module_function(rb_mMath, "cos", math_cos, 1);
00797     rb_define_module_function(rb_mMath, "sin", math_sin, 1);
00798     rb_define_module_function(rb_mMath, "tan", math_tan, 1);
00799 
00800     rb_define_module_function(rb_mMath, "acos", math_acos, 1);
00801     rb_define_module_function(rb_mMath, "asin", math_asin, 1);
00802     rb_define_module_function(rb_mMath, "atan", math_atan, 1);
00803 
00804     rb_define_module_function(rb_mMath, "cosh", math_cosh, 1);
00805     rb_define_module_function(rb_mMath, "sinh", math_sinh, 1);
00806     rb_define_module_function(rb_mMath, "tanh", math_tanh, 1);
00807 
00808     rb_define_module_function(rb_mMath, "acosh", math_acosh, 1);
00809     rb_define_module_function(rb_mMath, "asinh", math_asinh, 1);
00810     rb_define_module_function(rb_mMath, "atanh", math_atanh, 1);
00811 
00812     rb_define_module_function(rb_mMath, "exp", math_exp, 1);
00813     rb_define_module_function(rb_mMath, "log", math_log, -1);
00814     rb_define_module_function(rb_mMath, "log2", math_log2, 1);
00815     rb_define_module_function(rb_mMath, "log10", math_log10, 1);
00816     rb_define_module_function(rb_mMath, "sqrt", math_sqrt, 1);
00817     rb_define_module_function(rb_mMath, "cbrt", math_cbrt, 1);
00818 
00819     rb_define_module_function(rb_mMath, "frexp", math_frexp, 1);
00820     rb_define_module_function(rb_mMath, "ldexp", math_ldexp, 2);
00821 
00822     rb_define_module_function(rb_mMath, "hypot", math_hypot, 2);
00823 
00824     rb_define_module_function(rb_mMath, "erf",  math_erf,  1);
00825     rb_define_module_function(rb_mMath, "erfc", math_erfc, 1);
00826 
00827     rb_define_module_function(rb_mMath, "gamma", math_gamma, 1);
00828     rb_define_module_function(rb_mMath, "lgamma", math_lgamma, 1);
00829 }
00830