00001
00002
00003
00004
00005
00006
00007
00008
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
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
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
00080
00081
00082
00083
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
00095
00096
00097
00098
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
00112
00113
00114
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
00127
00128
00129
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
00140 if (d0 < -1.0 || 1.0 < d0) domain_error("acos");
00141 d = acos(d0);
00142 return DBL2NUM(d);
00143 }
00144
00145
00146
00147
00148
00149
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
00160 if (d0 < -1.0 || 1.0 < d0) domain_error("asin");
00161 d = asin(d0);
00162 return DBL2NUM(d);
00163 }
00164
00165
00166
00167
00168
00169
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
00189
00190
00191
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
00212
00213
00214
00215
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
00235
00236
00237
00238
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
00250
00251
00252
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
00263 if (d0 < 1.0) domain_error("acosh");
00264 d = acosh(d0);
00265 return DBL2NUM(d);
00266 }
00267
00268
00269
00270
00271
00272
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
00284
00285
00286
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
00297 if (d0 < -1.0 || +1.0 < d0) domain_error("atanh");
00298
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
00307
00308
00309
00310
00311
00312
00313
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
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
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
00359 if (d0 < 0.0) domain_error("log");
00360
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
00384
00385
00386
00387
00388
00389
00390
00391
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
00403 if (d0 < 0.0) domain_error("log2");
00404
00405 if (d0 == 0.0) return DBL2NUM(-INFINITY);
00406 d = log2(d0);
00407 return DBL2NUM(d);
00408 }
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
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
00430 if (d0 < 0.0) domain_error("log10");
00431
00432 if (d0 == 0.0) return DBL2NUM(-INFINITY);
00433 d = log10(d0);
00434 return DBL2NUM(d);
00435 }
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
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
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
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
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
00516
00517
00518
00519
00520
00521
00522
00523
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
00540
00541
00542
00543
00544
00545
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
00557
00558
00559
00560
00561
00562
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
00574
00575
00576
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
00588
00589
00590
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
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640 static VALUE
00641 math_gamma(VALUE obj, VALUE x)
00642 {
00643 static const double fact_table[] = {
00644 1.0,
00645 1.0,
00646 2.0,
00647 6.0,
00648 24.0,
00649 120.0,
00650 720.0,
00651 5040.0,
00652 40320.0,
00653 362880.0,
00654 3628800.0,
00655 39916800.0,
00656 479001600.0,
00657 6227020800.0,
00658 87178291200.0,
00659 1307674368000.0,
00660 20922789888000.0,
00661 355687428096000.0,
00662 6402373705728000.0,
00663 121645100408832000.0,
00664 2432902008176640000.0,
00665 51090942171709440000.0,
00666 1124000727777607680000.0,
00667
00668
00669
00670 };
00671 double d0, d;
00672 double intpart, fracpart;
00673 Need_Float(x);
00674 d0 = RFLOAT_VALUE(x);
00675
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
00691
00692
00693
00694
00695
00696
00697
00698
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
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
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
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