00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "ruby/ruby.h"
00013 #include "internal.h"
00014 #include <float.h>
00015 #include <math.h>
00016 #include <errno.h>
00017
00018 #if defined(HAVE_SIGNBIT) && defined(__GNUC__) && defined(__sun) && \
00019 !defined(signbit)
00020 extern int signbit(double);
00021 #endif
00022
00023 #define RB_BIGNUM_TYPE_P(x) RB_TYPE_P((x), T_BIGNUM)
00024
00025 VALUE rb_mMath;
00026 VALUE rb_eMathDomainError;
00027
00028 #define Need_Float(x) do {if (!RB_TYPE_P(x, T_FLOAT)) {(x) = rb_to_float(x);}} while(0)
00029 #define Need_Float2(x,y) do {\
00030 Need_Float(x);\
00031 Need_Float(y);\
00032 } while (0)
00033
00034 #define domain_error(msg) \
00035 rb_raise(rb_eMathDomainError, "Numerical argument is out of domain - " #msg)
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 static VALUE
00062 math_atan2(VALUE obj, VALUE y, VALUE x)
00063 {
00064 #ifndef M_PI
00065 # define M_PI 3.14159265358979323846
00066 #endif
00067 double dx, dy;
00068 Need_Float2(y, x);
00069 dx = RFLOAT_VALUE(x);
00070 dy = RFLOAT_VALUE(y);
00071 if (dx == 0.0 && dy == 0.0) {
00072 if (!signbit(dx))
00073 return DBL2NUM(dy);
00074 if (!signbit(dy))
00075 return DBL2NUM(M_PI);
00076 return DBL2NUM(-M_PI);
00077 }
00078 if (isinf(dx) && isinf(dy)) domain_error("atan2");
00079 return DBL2NUM(atan2(dy, dx));
00080 }
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 static VALUE
00099 math_cos(VALUE obj, VALUE x)
00100 {
00101 Need_Float(x);
00102 return DBL2NUM(cos(RFLOAT_VALUE(x)));
00103 }
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120 static VALUE
00121 math_sin(VALUE obj, VALUE x)
00122 {
00123 Need_Float(x);
00124 return DBL2NUM(sin(RFLOAT_VALUE(x)));
00125 }
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 static VALUE
00143 math_tan(VALUE obj, VALUE x)
00144 {
00145 Need_Float(x);
00146 return DBL2NUM(tan(RFLOAT_VALUE(x)));
00147 }
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163 static VALUE
00164 math_acos(VALUE obj, VALUE x)
00165 {
00166 double d0, d;
00167
00168 Need_Float(x);
00169 d0 = RFLOAT_VALUE(x);
00170
00171 if (d0 < -1.0 || 1.0 < d0) domain_error("acos");
00172 d = acos(d0);
00173 return DBL2NUM(d);
00174 }
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189 static VALUE
00190 math_asin(VALUE obj, VALUE x)
00191 {
00192 double d0, d;
00193
00194 Need_Float(x);
00195 d0 = RFLOAT_VALUE(x);
00196
00197 if (d0 < -1.0 || 1.0 < d0) domain_error("asin");
00198 d = asin(d0);
00199 return DBL2NUM(d);
00200 }
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 static VALUE
00216 math_atan(VALUE obj, VALUE x)
00217 {
00218 Need_Float(x);
00219 return DBL2NUM(atan(RFLOAT_VALUE(x)));
00220 }
00221
00222 #ifndef HAVE_COSH
00223 double
00224 cosh(double x)
00225 {
00226 return (exp(x) + exp(-x)) / 2;
00227 }
00228 #endif
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244 static VALUE
00245 math_cosh(VALUE obj, VALUE x)
00246 {
00247 Need_Float(x);
00248 return DBL2NUM(cosh(RFLOAT_VALUE(x)));
00249 }
00250
00251 #ifndef HAVE_SINH
00252 double
00253 sinh(double x)
00254 {
00255 return (exp(x) - exp(-x)) / 2;
00256 }
00257 #endif
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273 static VALUE
00274 math_sinh(VALUE obj, VALUE x)
00275 {
00276 Need_Float(x);
00277 return DBL2NUM(sinh(RFLOAT_VALUE(x)));
00278 }
00279
00280 #ifndef HAVE_TANH
00281 double
00282 tanh(double x)
00283 {
00284 return sinh(x) / cosh(x);
00285 }
00286 #endif
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 static VALUE
00303 math_tanh(VALUE obj, VALUE x)
00304 {
00305 Need_Float(x);
00306 return DBL2NUM(tanh(RFLOAT_VALUE(x)));
00307 }
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323 static VALUE
00324 math_acosh(VALUE obj, VALUE x)
00325 {
00326 double d0, d;
00327
00328 Need_Float(x);
00329 d0 = RFLOAT_VALUE(x);
00330
00331 if (d0 < 1.0) domain_error("acosh");
00332 d = acosh(d0);
00333 return DBL2NUM(d);
00334 }
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350 static VALUE
00351 math_asinh(VALUE obj, VALUE x)
00352 {
00353 Need_Float(x);
00354 return DBL2NUM(asinh(RFLOAT_VALUE(x)));
00355 }
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 static VALUE
00372 math_atanh(VALUE obj, VALUE x)
00373 {
00374 double d0, d;
00375
00376 Need_Float(x);
00377 d0 = RFLOAT_VALUE(x);
00378
00379 if (d0 < -1.0 || +1.0 < d0) domain_error("atanh");
00380
00381 if (d0 == -1.0) return DBL2NUM(-INFINITY);
00382 if (d0 == +1.0) return DBL2NUM(+INFINITY);
00383 d = atanh(d0);
00384 return DBL2NUM(d);
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403 static VALUE
00404 math_exp(VALUE obj, VALUE x)
00405 {
00406 Need_Float(x);
00407 return DBL2NUM(exp(RFLOAT_VALUE(x)));
00408 }
00409
00410 #if defined __CYGWIN__
00411 # include <cygwin/version.h>
00412 # if CYGWIN_VERSION_DLL_MAJOR < 1005
00413 # define nan(x) nan()
00414 # endif
00415 # define log(x) ((x) < 0.0 ? nan("") : log(x))
00416 # define log10(x) ((x) < 0.0 ? nan("") : log10(x))
00417 #endif
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440 static VALUE
00441 math_log(int argc, VALUE *argv)
00442 {
00443 VALUE x, base;
00444 double d0, d;
00445 size_t numbits;
00446
00447 rb_scan_args(argc, argv, "11", &x, &base);
00448
00449 if (RB_BIGNUM_TYPE_P(x) && RBIGNUM_POSITIVE_P(x) &&
00450 DBL_MAX_EXP <= (numbits = rb_absint_numwords(x, 1, NULL))) {
00451 numbits -= DBL_MANT_DIG;
00452 x = rb_big_rshift(x, SIZET2NUM(numbits));
00453 }
00454 else {
00455 numbits = 0;
00456 }
00457
00458 Need_Float(x);
00459 d0 = RFLOAT_VALUE(x);
00460
00461 if (d0 < 0.0) domain_error("log");
00462
00463 if (d0 == 0.0) return DBL2NUM(-INFINITY);
00464 d = log(d0);
00465 if (numbits)
00466 d += numbits * log(2);
00467 if (argc == 2) {
00468 Need_Float(base);
00469 d /= log(RFLOAT_VALUE(base));
00470 }
00471 return DBL2NUM(d);
00472 }
00473
00474 #ifndef log2
00475 #ifndef HAVE_LOG2
00476 double
00477 log2(double x)
00478 {
00479 return log10(x)/log10(2.0);
00480 }
00481 #else
00482 extern double log2(double);
00483 #endif
00484 #endif
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503 static VALUE
00504 math_log2(VALUE obj, VALUE x)
00505 {
00506 double d0, d;
00507 size_t numbits;
00508
00509 if (RB_BIGNUM_TYPE_P(x) && RBIGNUM_POSITIVE_P(x) &&
00510 DBL_MAX_EXP <= (numbits = rb_absint_numwords(x, 1, NULL))) {
00511 numbits -= DBL_MANT_DIG;
00512 x = rb_big_rshift(x, SIZET2NUM(numbits));
00513 }
00514 else {
00515 numbits = 0;
00516 }
00517
00518 Need_Float(x);
00519 d0 = RFLOAT_VALUE(x);
00520
00521 if (d0 < 0.0) domain_error("log2");
00522
00523 if (d0 == 0.0) return DBL2NUM(-INFINITY);
00524 d = log2(d0);
00525 d += numbits;
00526 return DBL2NUM(d);
00527 }
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545 static VALUE
00546 math_log10(VALUE obj, VALUE x)
00547 {
00548 double d0, d;
00549 size_t numbits;
00550
00551 if (RB_BIGNUM_TYPE_P(x) && RBIGNUM_POSITIVE_P(x) &&
00552 DBL_MAX_EXP <= (numbits = rb_absint_numwords(x, 1, NULL))) {
00553 numbits -= DBL_MANT_DIG;
00554 x = rb_big_rshift(x, SIZET2NUM(numbits));
00555 }
00556 else {
00557 numbits = 0;
00558 }
00559
00560 Need_Float(x);
00561 d0 = RFLOAT_VALUE(x);
00562
00563 if (d0 < 0.0) domain_error("log10");
00564
00565 if (d0 == 0.0) return DBL2NUM(-INFINITY);
00566 d = log10(d0);
00567 if (numbits)
00568 d += numbits * log10(2);
00569 return DBL2NUM(d);
00570 }
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598 static VALUE
00599 math_sqrt(VALUE obj, VALUE x)
00600 {
00601 double d0, d;
00602
00603 Need_Float(x);
00604 d0 = RFLOAT_VALUE(x);
00605
00606 if (d0 < 0.0) domain_error("sqrt");
00607 if (d0 == 0.0) return DBL2NUM(0.0);
00608 d = sqrt(d0);
00609 return DBL2NUM(d);
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
00641
00642
00643
00644
00645
00646
00647 static VALUE
00648 math_cbrt(VALUE obj, VALUE x)
00649 {
00650 Need_Float(x);
00651 return DBL2NUM(cbrt(RFLOAT_VALUE(x)));
00652 }
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665 static VALUE
00666 math_frexp(VALUE obj, VALUE x)
00667 {
00668 double d;
00669 int exp;
00670
00671 Need_Float(x);
00672
00673 d = frexp(RFLOAT_VALUE(x), &exp);
00674 return rb_assoc_new(DBL2NUM(d), INT2NUM(exp));
00675 }
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687 static VALUE
00688 math_ldexp(VALUE obj, VALUE x, VALUE n)
00689 {
00690 Need_Float(x);
00691 return DBL2NUM(ldexp(RFLOAT_VALUE(x), NUM2INT(n)));
00692 }
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704 static VALUE
00705 math_hypot(VALUE obj, VALUE x, VALUE y)
00706 {
00707 Need_Float2(x, y);
00708 return DBL2NUM(hypot(RFLOAT_VALUE(x), RFLOAT_VALUE(y)));
00709 }
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725 static VALUE
00726 math_erf(VALUE obj, VALUE x)
00727 {
00728 Need_Float(x);
00729 return DBL2NUM(erf(RFLOAT_VALUE(x)));
00730 }
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746 static VALUE
00747 math_erfc(VALUE obj, VALUE x)
00748 {
00749 Need_Float(x);
00750 return DBL2NUM(erfc(RFLOAT_VALUE(x)));
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
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793 static VALUE
00794 math_gamma(VALUE obj, VALUE x)
00795 {
00796 static const double fact_table[] = {
00797 1.0,
00798 1.0,
00799 2.0,
00800 6.0,
00801 24.0,
00802 120.0,
00803 720.0,
00804 5040.0,
00805 40320.0,
00806 362880.0,
00807 3628800.0,
00808 39916800.0,
00809 479001600.0,
00810 6227020800.0,
00811 87178291200.0,
00812 1307674368000.0,
00813 20922789888000.0,
00814 355687428096000.0,
00815 6402373705728000.0,
00816 121645100408832000.0,
00817 2432902008176640000.0,
00818 51090942171709440000.0,
00819 1124000727777607680000.0,
00820
00821
00822
00823 };
00824 double d0, d;
00825 double intpart, fracpart;
00826 Need_Float(x);
00827 d0 = RFLOAT_VALUE(x);
00828
00829 if (isinf(d0) && signbit(d0)) domain_error("gamma");
00830 fracpart = modf(d0, &intpart);
00831 if (fracpart == 0.0) {
00832 if (intpart < 0) domain_error("gamma");
00833 if (0 < intpart &&
00834 intpart - 1 < (double)numberof(fact_table)) {
00835 return DBL2NUM(fact_table[(int)intpart - 1]);
00836 }
00837 }
00838 d = tgamma(d0);
00839 return DBL2NUM(d);
00840 }
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856 static VALUE
00857 math_lgamma(VALUE obj, VALUE x)
00858 {
00859 double d0, d;
00860 int sign=1;
00861 VALUE v;
00862 Need_Float(x);
00863 d0 = RFLOAT_VALUE(x);
00864
00865 if (isinf(d0)) {
00866 if (signbit(d0)) domain_error("lgamma");
00867 return rb_assoc_new(DBL2NUM(INFINITY), INT2FIX(1));
00868 }
00869 d = lgamma_r(d0, &sign);
00870 v = DBL2NUM(d);
00871 return rb_assoc_new(v, INT2FIX(sign));
00872 }
00873
00874
00875 #define exp1(n) \
00876 VALUE \
00877 rb_math_##n(VALUE x)\
00878 {\
00879 return math_##n(rb_mMath, x);\
00880 }
00881
00882 #define exp2(n) \
00883 VALUE \
00884 rb_math_##n(VALUE x, VALUE y)\
00885 {\
00886 return math_##n(rb_mMath, x, y);\
00887 }
00888
00889 exp2(atan2)
00890 exp1(cos)
00891 exp1(cosh)
00892 exp1(exp)
00893 exp2(hypot)
00894
00895 VALUE
00896 rb_math_log(int argc, VALUE *argv)
00897 {
00898 return math_log(argc, argv);
00899 }
00900
00901 exp1(sin)
00902 exp1(sinh)
00903 exp1(sqrt)
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934 void
00935 Init_Math(void)
00936 {
00937 rb_mMath = rb_define_module("Math");
00938 rb_eMathDomainError = rb_define_class_under(rb_mMath, "DomainError", rb_eStandardError);
00939
00940 #ifdef M_PI
00941
00942 rb_define_const(rb_mMath, "PI", DBL2NUM(M_PI));
00943 #else
00944 rb_define_const(rb_mMath, "PI", DBL2NUM(atan(1.0)*4.0));
00945 #endif
00946
00947 #ifdef M_E
00948
00949 rb_define_const(rb_mMath, "E", DBL2NUM(M_E));
00950 #else
00951 rb_define_const(rb_mMath, "E", DBL2NUM(exp(1.0)));
00952 #endif
00953
00954 rb_define_module_function(rb_mMath, "atan2", math_atan2, 2);
00955 rb_define_module_function(rb_mMath, "cos", math_cos, 1);
00956 rb_define_module_function(rb_mMath, "sin", math_sin, 1);
00957 rb_define_module_function(rb_mMath, "tan", math_tan, 1);
00958
00959 rb_define_module_function(rb_mMath, "acos", math_acos, 1);
00960 rb_define_module_function(rb_mMath, "asin", math_asin, 1);
00961 rb_define_module_function(rb_mMath, "atan", math_atan, 1);
00962
00963 rb_define_module_function(rb_mMath, "cosh", math_cosh, 1);
00964 rb_define_module_function(rb_mMath, "sinh", math_sinh, 1);
00965 rb_define_module_function(rb_mMath, "tanh", math_tanh, 1);
00966
00967 rb_define_module_function(rb_mMath, "acosh", math_acosh, 1);
00968 rb_define_module_function(rb_mMath, "asinh", math_asinh, 1);
00969 rb_define_module_function(rb_mMath, "atanh", math_atanh, 1);
00970
00971 rb_define_module_function(rb_mMath, "exp", math_exp, 1);
00972 rb_define_module_function(rb_mMath, "log", math_log, -1);
00973 rb_define_module_function(rb_mMath, "log2", math_log2, 1);
00974 rb_define_module_function(rb_mMath, "log10", math_log10, 1);
00975 rb_define_module_function(rb_mMath, "sqrt", math_sqrt, 1);
00976 rb_define_module_function(rb_mMath, "cbrt", math_cbrt, 1);
00977
00978 rb_define_module_function(rb_mMath, "frexp", math_frexp, 1);
00979 rb_define_module_function(rb_mMath, "ldexp", math_ldexp, 2);
00980
00981 rb_define_module_function(rb_mMath, "hypot", math_hypot, 2);
00982
00983 rb_define_module_function(rb_mMath, "erf", math_erf, 1);
00984 rb_define_module_function(rb_mMath, "erfc", math_erfc, 1);
00985
00986 rb_define_module_function(rb_mMath, "gamma", math_gamma, 1);
00987 rb_define_module_function(rb_mMath, "lgamma", math_lgamma, 1);
00988 }
00989