mbed I/F binding for mruby

Dependents:   mruby_mbed_web mirb_mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers numeric.c Source File

numeric.c

00001 /*
00002 ** numeric.c - Numeric, Integer, Float, Fixnum class
00003 **
00004 ** See Copyright Notice in mruby.h
00005 */
00006 
00007 #include <float.h>
00008 #include <limits.h>
00009 #include <math.h>
00010 #include <stdlib.h>
00011 
00012 #include "mruby.h"
00013 #include "mruby/array.h"
00014 #include "mruby/numeric.h"
00015 #include "mruby/string.h"
00016 
00017 #ifdef MRB_USE_FLOAT
00018 #define floor(f) floorf(f)
00019 #define ceil(f) ceilf(f)
00020 #define fmod(x,y) fmodf(x,y)
00021 #define FLO_MAX_DIGITS 7
00022 #define FLO_MAX_SIGN_LENGTH 3
00023 #define FLO_EPSILON FLT_EPSILON
00024 #else
00025 #define FLO_MAX_DIGITS 14
00026 #define FLO_MAX_SIGN_LENGTH 10
00027 #define FLO_EPSILON DBL_EPSILON
00028 #endif
00029 
00030 MRB_API mrb_float
00031 mrb_to_flo(mrb_state *mrb, mrb_value val)
00032 {
00033   switch (mrb_type(val)) {
00034   case MRB_TT_FIXNUM:
00035     return (mrb_float)mrb_fixnum(val);
00036   case MRB_TT_FLOAT:
00037     break;
00038   default:
00039     mrb_raise(mrb, E_TYPE_ERROR, "non float value");
00040   }
00041   return mrb_float(val);
00042 }
00043 
00044 /*
00045  * call-seq:
00046  *
00047  *  num ** other  ->  num
00048  *
00049  * Raises <code>num</code> the <code>other</code> power.
00050  *
00051  *    2.0**3      #=> 8.0
00052  */
00053 static mrb_value
00054 num_pow(mrb_state *mrb, mrb_value x)
00055 {
00056   mrb_value y;
00057   mrb_float d, yv;
00058 
00059   mrb_get_args(mrb, "o", &y);
00060   yv = mrb_to_flo(mrb, y);
00061   d = pow(mrb_to_flo(mrb, x), yv);
00062   if (mrb_fixnum_p(x) && mrb_fixnum_p(y) && FIXABLE(d) && yv > 0)
00063     return mrb_fixnum_value((mrb_int)d);
00064   return mrb_float_value(mrb, d);
00065 }
00066 
00067 /* 15.2.8.3.4  */
00068 /* 15.2.9.3.4  */
00069 /*
00070  * call-seq:
00071  *   num / other  ->  num
00072  *
00073  * Performs division: the class of the resulting object depends on
00074  * the class of <code>num</code> and on the magnitude of the
00075  * result.
00076  */
00077 
00078 mrb_value
00079 mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y)
00080 {
00081   return mrb_float_value(mrb, mrb_to_flo(mrb, x) / mrb_to_flo(mrb, y));
00082 }
00083 
00084 /* 15.2.9.3.19(x) */
00085 /*
00086  *  call-seq:
00087  *     num.quo(numeric)  ->  real
00088  *
00089  *  Returns most exact division.
00090  */
00091 
00092 static mrb_value
00093 num_div(mrb_state *mrb, mrb_value x)
00094 {
00095   mrb_float y;
00096 
00097   mrb_get_args(mrb, "f", &y);
00098   return mrb_float_value(mrb, mrb_to_flo(mrb, x) / y);
00099 }
00100 
00101 /********************************************************************
00102  *
00103  * Document-class: Float
00104  *
00105  *  <code>Float</code> objects represent inexact real numbers using
00106  *  the native architecture's double-precision floating point
00107  *  representation.
00108  */
00109 
00110 static mrb_value
00111 mrb_flo_to_str(mrb_state *mrb, mrb_float flo)
00112 {
00113   double n = (double)flo;
00114   int max_digits = FLO_MAX_DIGITS;
00115 
00116   if (isnan(n)) {
00117     return mrb_str_new_lit(mrb, "NaN");
00118   }
00119   else if (isinf(n)) {
00120     if (n < 0) {
00121       return mrb_str_new_lit(mrb, "-inf");
00122     }
00123     else {
00124       return mrb_str_new_lit(mrb, "inf");
00125     }
00126   }
00127   else {
00128     int digit;
00129     int m = 0;
00130     int exp;
00131     mrb_bool e = FALSE;
00132     char s[48];
00133     char *c = &s[0];
00134     int length = 0;
00135 
00136     if (signbit(n)) {
00137       n = -n;
00138       *(c++) = '-';
00139     }
00140 
00141     if (n != 0.0) {
00142       if (n > 1.0) {
00143         exp = (int)floor(log10(n));
00144       }
00145       else {
00146         exp = (int)-ceil(-log10(n));
00147       }
00148     }
00149     else {
00150       exp = 0;
00151     }
00152 
00153     /* preserve significands */
00154     if (exp < 0) {
00155       int i, beg = -1, end = 0;
00156       double f = n;
00157       double fd = 0;
00158       for (i = 0; i < FLO_MAX_DIGITS; ++i) {
00159         f = (f - fd) * 10.0;
00160         fd = floor(f + FLO_EPSILON);
00161         if (fd != 0) {
00162           if (beg < 0) beg = i;
00163           end = i + 1;
00164         }
00165       }
00166       if (beg >= 0) length = end - beg;
00167       if (length > FLO_MAX_SIGN_LENGTH) length = FLO_MAX_SIGN_LENGTH;
00168     }
00169 
00170     if (abs(exp) + length >= FLO_MAX_DIGITS) {
00171       /* exponent representation */
00172       e = TRUE;
00173       n = n / pow(10.0, exp);
00174       if (isinf(n)) {
00175         if (s < c) {            /* s[0] == '-' */
00176           return mrb_str_new_lit(mrb, "-0.0");
00177         }
00178         else {
00179           return mrb_str_new_lit(mrb, "0.0");
00180         }
00181       }
00182     }
00183     else {
00184       /* un-exponent (normal) representation */
00185       if (exp > 0) {
00186         m = exp;
00187       }
00188     }
00189 
00190     /* puts digits */
00191     while (max_digits >= 0) {
00192       double weight = (m < 0) ? 0.0 : pow(10.0, m);
00193       double fdigit = (m < 0) ? n * 10.0 : n / weight;
00194 
00195       if (fdigit < 0) fdigit = n = 0;
00196       if (m < -1 && fdigit < FLO_EPSILON) {
00197         if (e || exp > 0 || m <= -abs(exp)) {
00198           break;
00199         }
00200       }
00201       digit = (int)floor(fdigit + FLO_EPSILON);
00202       if (m == 0 && digit > 9) {
00203         n /= 10.0;
00204         exp++;
00205         continue;
00206       }
00207       *(c++) = '0' + digit;
00208       n = (m < 0) ? n * 10.0 - digit : n - (digit * weight);
00209       max_digits--;
00210       if (m-- == 0) {
00211         *(c++) = '.';
00212       }
00213     }
00214     if (c[-1] == '0') {
00215       while (&s[0] < c && c[-1] == '0') {
00216         c--;
00217       }
00218       c++;
00219     }
00220 
00221     if (e) {
00222       *(c++) = 'e';
00223       if (exp > 0) {
00224         *(c++) = '+';
00225       }
00226       else {
00227         *(c++) = '-';
00228         exp = -exp;
00229       }
00230 
00231       if (exp >= 100) {
00232         *(c++) = '0' + exp / 100;
00233         exp -= exp / 100 * 100;
00234       }
00235 
00236       *(c++) = '0' + exp / 10;
00237       *(c++) = '0' + exp % 10;
00238     }
00239 
00240     *c = '\0';
00241 
00242     return mrb_str_new(mrb, &s[0], c - &s[0]);
00243   }
00244 }
00245 
00246 /* 15.2.9.3.16(x) */
00247 /*
00248  *  call-seq:
00249  *     flt.to_s  ->  string
00250  *
00251  *  Returns a string containing a representation of self. As well as a
00252  *  fixed or exponential form of the number, the call may return
00253  *  ``<code>NaN</code>'', ``<code>Infinity</code>'', and
00254  *  ``<code>-Infinity</code>''.
00255  */
00256 
00257 static mrb_value
00258 flo_to_s(mrb_state *mrb, mrb_value flt)
00259 {
00260   return mrb_flo_to_str(mrb, mrb_float(flt));
00261 }
00262 
00263 /* 15.2.9.3.2  */
00264 /*
00265  * call-seq:
00266  *   float - other  ->  float
00267  *
00268  * Returns a new float which is the difference of <code>float</code>
00269  * and <code>other</code>.
00270  */
00271 
00272 static mrb_value
00273 flo_minus(mrb_state *mrb, mrb_value x)
00274 {
00275   mrb_value y;
00276 
00277   mrb_get_args(mrb, "o", &y);
00278   return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y));
00279 }
00280 
00281 /* 15.2.9.3.3  */
00282 /*
00283  * call-seq:
00284  *   float * other  ->  float
00285  *
00286  * Returns a new float which is the product of <code>float</code>
00287  * and <code>other</code>.
00288  */
00289 
00290 static mrb_value
00291 flo_mul(mrb_state *mrb, mrb_value x)
00292 {
00293   mrb_value y;
00294 
00295   mrb_get_args(mrb, "o", &y);
00296   return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y));
00297 }
00298 
00299 static void
00300 flodivmod(mrb_state *mrb, mrb_float x, mrb_float y, mrb_float *divp, mrb_float *modp)
00301 {
00302   mrb_float div;
00303   mrb_float mod;
00304 
00305   if (y == 0.0) {
00306     div = INFINITY;
00307     mod = NAN;
00308   }
00309   else {
00310     mod = fmod(x, y);
00311     if (isinf(x) && isfinite(y))
00312       div = x;
00313     else
00314       div = (x - mod) / y;
00315     if (y*mod < 0) {
00316       mod += y;
00317       div -= 1.0;
00318     }
00319   }
00320 
00321   if (modp) *modp = mod;
00322   if (divp) *divp = div;
00323 }
00324 
00325 /* 15.2.9.3.5  */
00326 /*
00327  *  call-seq:
00328  *     flt % other        ->  float
00329  *     flt.modulo(other)  ->  float
00330  *
00331  *  Return the modulo after division of <code>flt</code> by <code>other</code>.
00332  *
00333  *     6543.21.modulo(137)      #=> 104.21
00334  *     6543.21.modulo(137.24)   #=> 92.9299999999996
00335  */
00336 
00337 static mrb_value
00338 flo_mod(mrb_state *mrb, mrb_value x)
00339 {
00340   mrb_value y;
00341   mrb_float mod;
00342 
00343   mrb_get_args(mrb, "o", &y);
00344 
00345   flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), 0, &mod);
00346   return mrb_float_value(mrb, mod);
00347 }
00348 
00349 /* 15.2.8.3.16 */
00350 /*
00351  *  call-seq:
00352  *     num.eql?(numeric)  ->  true or false
00353  *
00354  *  Returns <code>true</code> if <i>num</i> and <i>numeric</i> are the
00355  *  same type and have equal values.
00356  *
00357  *     1 == 1.0          #=> true
00358  *     1.eql?(1.0)       #=> false
00359  *     (1.0).eql?(1.0)   #=> true
00360  */
00361 static mrb_value
00362 fix_eql(mrb_state *mrb, mrb_value x)
00363 {
00364   mrb_value y;
00365 
00366   mrb_get_args(mrb, "o", &y);
00367   if (!mrb_fixnum_p(y)) return mrb_false_value();
00368   return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y));
00369 }
00370 
00371 static mrb_value
00372 flo_eql(mrb_state *mrb, mrb_value x)
00373 {
00374   mrb_value y;
00375 
00376   mrb_get_args(mrb, "o", &y);
00377   if (!mrb_float_p(y)) return mrb_false_value();
00378   return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y));
00379 }
00380 
00381 /* 15.2.9.3.7  */
00382 /*
00383  *  call-seq:
00384  *     flt == obj  ->  true or false
00385  *
00386  *  Returns <code>true</code> only if <i>obj</i> has the same value
00387  *  as <i>flt</i>. Contrast this with <code>Float#eql?</code>, which
00388  *  requires <i>obj</i> to be a <code>Float</code>.
00389  *
00390  *     1.0 == 1   #=> true
00391  *
00392  */
00393 
00394 static mrb_value
00395 flo_eq(mrb_state *mrb, mrb_value x)
00396 {
00397   mrb_value y;
00398   mrb_get_args(mrb, "o", &y);
00399 
00400   switch (mrb_type(y)) {
00401   case MRB_TT_FIXNUM:
00402     return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y));
00403   case MRB_TT_FLOAT:
00404     return mrb_bool_value(mrb_float(x) == mrb_float(y));
00405   default:
00406     return mrb_false_value();
00407   }
00408 }
00409 
00410 /* 15.2.8.3.18 */
00411 /*
00412  * call-seq:
00413  *   flt.hash  ->  integer
00414  *
00415  * Returns a hash code for this float.
00416  */
00417 static mrb_value
00418 flo_hash(mrb_state *mrb, mrb_value num)
00419 {
00420   mrb_float d;
00421   char *c;
00422   size_t i;
00423   int hash;
00424 
00425   d = (mrb_float)mrb_fixnum(num);
00426   /* normalize -0.0 to 0.0 */
00427   if (d == 0) d = 0.0;
00428   c = (char*)&d;
00429   for (hash=0, i=0; i<sizeof(mrb_float);i++) {
00430     hash = (hash * 971) ^ (unsigned char)c[i];
00431   }
00432   if (hash < 0) hash = -hash;
00433   return mrb_fixnum_value(hash);
00434 }
00435 
00436 /* 15.2.9.3.13 */
00437 /*
00438  * call-seq:
00439  *   flt.to_f  ->  self
00440  *
00441  * As <code>flt</code> is already a float, returns +self+.
00442  */
00443 
00444 static mrb_value
00445 flo_to_f(mrb_state *mrb, mrb_value num)
00446 {
00447   return num;
00448 }
00449 
00450 /* 15.2.9.3.11 */
00451 /*
00452  *  call-seq:
00453  *     flt.infinite?  ->  nil, -1, +1
00454  *
00455  *  Returns <code>nil</code>, -1, or +1 depending on whether <i>flt</i>
00456  *  is finite, -infinity, or +infinity.
00457  *
00458  *     (0.0).infinite?        #=> nil
00459  *     (-1.0/0.0).infinite?   #=> -1
00460  *     (+1.0/0.0).infinite?   #=> 1
00461  */
00462 
00463 static mrb_value
00464 flo_infinite_p(mrb_state *mrb, mrb_value num)
00465 {
00466   mrb_float value = mrb_float(num);
00467 
00468   if (isinf(value)) {
00469     return mrb_fixnum_value(value < 0 ? -1 : 1);
00470   }
00471   return mrb_nil_value();
00472 }
00473 
00474 /* 15.2.9.3.9  */
00475 /*
00476  *  call-seq:
00477  *     flt.finite?  ->  true or false
00478  *
00479  *  Returns <code>true</code> if <i>flt</i> is a valid IEEE floating
00480  *  point number (it is not infinite, and <code>nan?</code> is
00481  *  <code>false</code>).
00482  *
00483  */
00484 
00485 static mrb_value
00486 flo_finite_p(mrb_state *mrb, mrb_value num)
00487 {
00488   return mrb_bool_value(isfinite(mrb_float(num)));
00489 }
00490 
00491 /* 15.2.9.3.10 */
00492 /*
00493  *  call-seq:
00494  *     flt.floor  ->  integer
00495  *
00496  *  Returns the largest integer less than or equal to <i>flt</i>.
00497  *
00498  *     1.2.floor      #=> 1
00499  *     2.0.floor      #=> 2
00500  *     (-1.2).floor   #=> -2
00501  *     (-2.0).floor   #=> -2
00502  */
00503 
00504 static mrb_value
00505 flo_floor(mrb_state *mrb, mrb_value num)
00506 {
00507   mrb_float f = floor(mrb_float(num));
00508 
00509   if (!FIXABLE(f)) {
00510     return mrb_float_value(mrb, f);
00511   }
00512   return mrb_fixnum_value((mrb_int)f);
00513 }
00514 
00515 /* 15.2.9.3.8  */
00516 /*
00517  *  call-seq:
00518  *     flt.ceil  ->  integer
00519  *
00520  *  Returns the smallest <code>Integer</code> greater than or equal to
00521  *  <i>flt</i>.
00522  *
00523  *     1.2.ceil      #=> 2
00524  *     2.0.ceil      #=> 2
00525  *     (-1.2).ceil   #=> -1
00526  *     (-2.0).ceil   #=> -2
00527  */
00528 
00529 static mrb_value
00530 flo_ceil(mrb_state *mrb, mrb_value num)
00531 {
00532   mrb_float f = ceil(mrb_float(num));
00533 
00534   if (!FIXABLE(f)) {
00535     return mrb_float_value(mrb, f);
00536   }
00537   return mrb_fixnum_value((mrb_int)f);
00538 }
00539 
00540 /* 15.2.9.3.12 */
00541 /*
00542  *  call-seq:
00543  *     flt.round([ndigits])  ->  integer or float
00544  *
00545  *  Rounds <i>flt</i> to a given precision in decimal digits (default 0 digits).
00546  *  Precision may be negative.  Returns a floating point number when ndigits
00547  *  is more than zero.
00548  *
00549  *     1.4.round      #=> 1
00550  *     1.5.round      #=> 2
00551  *     1.6.round      #=> 2
00552  *     (-1.5).round   #=> -2
00553  *
00554  *     1.234567.round(2)  #=> 1.23
00555  *     1.234567.round(3)  #=> 1.235
00556  *     1.234567.round(4)  #=> 1.2346
00557  *     1.234567.round(5)  #=> 1.23457
00558  *
00559  *     34567.89.round(-5) #=> 0
00560  *     34567.89.round(-4) #=> 30000
00561  *     34567.89.round(-3) #=> 35000
00562  *     34567.89.round(-2) #=> 34600
00563  *     34567.89.round(-1) #=> 34570
00564  *     34567.89.round(0)  #=> 34568
00565  *     34567.89.round(1)  #=> 34567.9
00566  *     34567.89.round(2)  #=> 34567.89
00567  *     34567.89.round(3)  #=> 34567.89
00568  *
00569  */
00570 
00571 static mrb_value
00572 flo_round(mrb_state *mrb, mrb_value num)
00573 {
00574   double number, f;
00575   mrb_int ndigits = 0;
00576   int i;
00577 
00578   mrb_get_args(mrb, "|i", &ndigits);
00579   number = mrb_float(num);
00580 
00581   if (isinf(number)) {
00582     if (0 < ndigits) return num;
00583     else mrb_raise(mrb, E_FLOATDOMAIN_ERROR, number < 0 ? "-Infinity" : "Infinity");
00584   }
00585   if (isnan(number)) {
00586     if (0 < ndigits) return num;
00587     else mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
00588   }
00589 
00590   f = 1.0;
00591   i = abs(ndigits);
00592   while  (--i >= 0)
00593     f = f*10.0;
00594 
00595   if (isinf(f)) {
00596     if (ndigits < 0) number = 0;
00597   }
00598   else {
00599     double d;
00600 
00601     if (ndigits < 0) number /= f;
00602     else number *= f;
00603 
00604     /* home-made inline implementation of round(3) */
00605     if (number > 0.0) {
00606       d = floor(number);
00607       number = d + (number - d >= 0.5);
00608     }
00609     else if (number < 0.0) {
00610       d = ceil(number);
00611       number = d - (d - number >= 0.5);
00612     }
00613 
00614     if (ndigits < 0) number *= f;
00615     else number /= f;
00616   }
00617 
00618   if (ndigits > 0) {
00619     if (!isfinite(number)) return num;
00620     return mrb_float_value(mrb, number);
00621   }
00622   return mrb_fixnum_value((mrb_int)number);
00623 }
00624 
00625 /* 15.2.9.3.14 */
00626 /* 15.2.9.3.15 */
00627 /*
00628  *  call-seq:
00629  *     flt.to_i      ->  integer
00630  *     flt.to_int    ->  integer
00631  *     flt.truncate  ->  integer
00632  *
00633  *  Returns <i>flt</i> truncated to an <code>Integer</code>.
00634  */
00635 
00636 static mrb_value
00637 flo_truncate(mrb_state *mrb, mrb_value num)
00638 {
00639   mrb_float f = mrb_float(num);
00640 
00641   if (f > 0.0) f = floor(f);
00642   if (f < 0.0) f = ceil(f);
00643 
00644   if (!FIXABLE(f)) {
00645     return mrb_float_value(mrb, f);
00646   }
00647   return mrb_fixnum_value((mrb_int)f);
00648 }
00649 
00650 static mrb_value
00651 flo_nan_p(mrb_state *mrb, mrb_value num)
00652 {
00653   return mrb_bool_value(isnan(mrb_float(num)));
00654 }
00655 
00656 /*
00657  * Document-class: Integer
00658  *
00659  *  <code>Integer</code> is the basis for the two concrete classes that
00660  *  hold whole numbers, <code>Bignum</code> and <code>Fixnum</code>.
00661  *
00662  */
00663 
00664 
00665 /*
00666  *  call-seq:
00667  *     int.to_i      ->  integer
00668  *     int.to_int    ->  integer
00669  *
00670  *  As <i>int</i> is already an <code>Integer</code>, all these
00671  *  methods simply return the receiver.
00672  */
00673 
00674 static mrb_value
00675 int_to_i(mrb_state *mrb, mrb_value num)
00676 {
00677   return num;
00678 }
00679 
00680 /*tests if N*N would overflow*/
00681 #define SQRT_INT_MAX ((mrb_int)1<<((MRB_INT_BIT-1-MRB_FIXNUM_SHIFT)/2))
00682 #define FIT_SQRT_INT(n) (((n)<SQRT_INT_MAX)&&((n)>=-SQRT_INT_MAX))
00683 
00684 mrb_value
00685 mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
00686 {
00687   mrb_int a;
00688 
00689   a = mrb_fixnum(x);
00690   if (mrb_fixnum_p(y)) {
00691     mrb_float c;
00692     mrb_int b;
00693 
00694     if (a == 0) return x;
00695     b = mrb_fixnum(y);
00696     if (FIT_SQRT_INT(a) && FIT_SQRT_INT(b))
00697       return mrb_fixnum_value(a*b);
00698     c = a * b;
00699     if ((a != 0 && c/a != b) || !FIXABLE(c)) {
00700       return mrb_float_value(mrb, (mrb_float)a*(mrb_float)b);
00701     }
00702     return mrb_fixnum_value((mrb_int)c);
00703   }
00704   return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
00705 }
00706 
00707 /* 15.2.8.3.3  */
00708 /*
00709  * call-seq:
00710  *   fix * numeric  ->  numeric_result
00711  *
00712  * Performs multiplication: the class of the resulting object depends on
00713  * the class of <code>numeric</code> and on the magnitude of the
00714  * result.
00715  */
00716 
00717 static mrb_value
00718 fix_mul(mrb_state *mrb, mrb_value x)
00719 {
00720   mrb_value y;
00721 
00722   mrb_get_args(mrb, "o", &y);
00723   return mrb_fixnum_mul(mrb, x, y);
00724 }
00725 
00726 static void
00727 fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp)
00728 {
00729   mrb_int div, mod;
00730 
00731   /* TODO: add mrb_assert(y != 0) to make sure */
00732 
00733   if (y < 0) {
00734     if (x < 0)
00735       div = -x / -y;
00736     else
00737       div = - (x / -y);
00738   }
00739   else {
00740     if (x < 0)
00741       div = - (-x / y);
00742     else
00743       div = x / y;
00744   }
00745   mod = x - div*y;
00746   if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) {
00747     mod += y;
00748     div -= 1;
00749   }
00750   if (divp) *divp = div;
00751   if (modp) *modp = mod;
00752 }
00753 
00754 /* 15.2.8.3.5  */
00755 /*
00756  *  call-seq:
00757  *    fix % other        ->  real
00758  *    fix.modulo(other)  ->  real
00759  *
00760  *  Returns <code>fix</code> modulo <code>other</code>.
00761  *  See <code>numeric.divmod</code> for more information.
00762  */
00763 
00764 static mrb_value
00765 fix_mod(mrb_state *mrb, mrb_value x)
00766 {
00767   mrb_value y;
00768   mrb_int a;
00769 
00770   mrb_get_args(mrb, "o", &y);
00771   a = mrb_fixnum(x);
00772   if (mrb_fixnum_p(y)) {
00773     mrb_int b, mod;
00774 
00775     if ((b=mrb_fixnum(y)) == 0) {
00776       return mrb_float_value(mrb, NAN);
00777     }
00778     fixdivmod(mrb, a, b, 0, &mod);
00779     return mrb_fixnum_value(mod);
00780   }
00781   else {
00782     mrb_float mod;
00783 
00784     flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), 0, &mod);
00785     return mrb_float_value(mrb, mod);
00786   }
00787 }
00788 
00789 /*
00790  *  call-seq:
00791  *     fix.divmod(numeric)  ->  array
00792  *
00793  *  See <code>Numeric#divmod</code>.
00794  */
00795 static mrb_value
00796 fix_divmod(mrb_state *mrb, mrb_value x)
00797 {
00798   mrb_value y;
00799 
00800   mrb_get_args(mrb, "o", &y);
00801 
00802   if (mrb_fixnum_p(y)) {
00803     mrb_int div, mod;
00804 
00805     if (mrb_fixnum(y) == 0) {
00806       return mrb_assoc_new(mrb, mrb_float_value(mrb, INFINITY),
00807         mrb_float_value(mrb, NAN));
00808     }
00809     fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, &mod);
00810     return mrb_assoc_new(mrb, mrb_fixnum_value(div), mrb_fixnum_value(mod));
00811   }
00812   else {
00813     mrb_float div, mod;
00814     mrb_value a, b;
00815 
00816     flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_to_flo(mrb, y), &div, &mod);
00817     a = mrb_float_value(mrb, (mrb_int)div);
00818     b = mrb_float_value(mrb, mod);
00819     return mrb_assoc_new(mrb, a, b);
00820   }
00821 }
00822 
00823 static mrb_value
00824 flo_divmod(mrb_state *mrb, mrb_value x)
00825 {
00826   mrb_value y;
00827   mrb_float div, mod;
00828   mrb_value a, b;
00829 
00830   mrb_get_args(mrb, "o", &y);
00831 
00832   flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod);
00833   a = mrb_float_value(mrb, (mrb_int)div);
00834   b = mrb_float_value(mrb, mod);
00835   return mrb_assoc_new(mrb, a, b);
00836 }
00837 
00838 /* 15.2.8.3.7  */
00839 /*
00840  * call-seq:
00841  *   fix == other  ->  true or false
00842  *
00843  * Return <code>true</code> if <code>fix</code> equals <code>other</code>
00844  * numerically.
00845  *
00846  *   1 == 2      #=> false
00847  *   1 == 1.0    #=> true
00848  */
00849 
00850 static mrb_value
00851 fix_equal(mrb_state *mrb, mrb_value x)
00852 {
00853   mrb_value y;
00854 
00855   mrb_get_args(mrb, "o", &y);
00856   switch (mrb_type(y)) {
00857   case MRB_TT_FIXNUM:
00858     return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y));
00859   case MRB_TT_FLOAT:
00860     return mrb_bool_value((mrb_float)mrb_fixnum(x) == mrb_float(y));
00861   default:
00862     return mrb_false_value();
00863   }
00864 }
00865 
00866 /* 15.2.8.3.8  */
00867 /*
00868  * call-seq:
00869  *   ~fix  ->  integer
00870  *
00871  * One's complement: returns a number where each bit is flipped.
00872  *   ex.0---00001 (1)-> 1---11110 (-2)
00873  *   ex.0---00010 (2)-> 1---11101 (-3)
00874  *   ex.0---00100 (4)-> 1---11011 (-5)
00875  */
00876 
00877 static mrb_value
00878 fix_rev(mrb_state *mrb, mrb_value num)
00879 {
00880   mrb_int val = mrb_fixnum(num);
00881 
00882   return mrb_fixnum_value(~val);
00883 }
00884 
00885 static mrb_value
00886 bit_coerce(mrb_state *mrb, mrb_value x)
00887 {
00888   while (!mrb_fixnum_p(x)) {
00889     if (mrb_float_p(x)) {
00890       mrb_raise(mrb, E_TYPE_ERROR, "can't convert Float into Integer");
00891     }
00892     x = mrb_to_int(mrb, x);
00893   }
00894   return x;
00895 }
00896 
00897 /* 15.2.8.3.9  */
00898 /*
00899  * call-seq:
00900  *   fix & integer  ->  integer_result
00901  *
00902  * Bitwise AND.
00903  */
00904 
00905 static mrb_value
00906 fix_and(mrb_state *mrb, mrb_value x)
00907 {
00908   mrb_value y;
00909 
00910   mrb_get_args(mrb, "o", &y);
00911 
00912   y = bit_coerce(mrb, y);
00913   return mrb_fixnum_value(mrb_fixnum(x) & mrb_fixnum(y));
00914 }
00915 
00916 /* 15.2.8.3.10 */
00917 /*
00918  * call-seq:
00919  *   fix | integer  ->  integer_result
00920  *
00921  * Bitwise OR.
00922  */
00923 
00924 static mrb_value
00925 fix_or(mrb_state *mrb, mrb_value x)
00926 {
00927   mrb_value y;
00928 
00929   mrb_get_args(mrb, "o", &y);
00930 
00931   y = bit_coerce(mrb, y);
00932   return mrb_fixnum_value(mrb_fixnum(x) | mrb_fixnum(y));
00933 }
00934 
00935 /* 15.2.8.3.11 */
00936 /*
00937  * call-seq:
00938  *   fix ^ integer  ->  integer_result
00939  *
00940  * Bitwise EXCLUSIVE OR.
00941  */
00942 
00943 static mrb_value
00944 fix_xor(mrb_state *mrb, mrb_value x)
00945 {
00946   mrb_value y;
00947 
00948   mrb_get_args(mrb, "o", &y);
00949 
00950   y = bit_coerce(mrb, y);
00951   return mrb_fixnum_value(mrb_fixnum(x) ^ mrb_fixnum(y));
00952 }
00953 
00954 #define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1)
00955 
00956 static mrb_value
00957 lshift(mrb_state *mrb, mrb_int val, mrb_int width)
00958 {
00959   mrb_assert(width >= 0);
00960   if (width > NUMERIC_SHIFT_WIDTH_MAX) {
00961     mrb_raisef(mrb, E_RANGE_ERROR, "width(%S) > (%S:MRB_INT_BIT-1)",
00962                mrb_fixnum_value(width),
00963                mrb_fixnum_value(NUMERIC_SHIFT_WIDTH_MAX));
00964   }
00965   return mrb_fixnum_value(val << width);
00966 }
00967 
00968 static mrb_value
00969 rshift(mrb_int val, mrb_int width)
00970 {
00971   mrb_assert(width >= 0);
00972   if (width >= NUMERIC_SHIFT_WIDTH_MAX) {
00973     if (val < 0) {
00974       return mrb_fixnum_value(-1);
00975     }
00976     return mrb_fixnum_value(0);
00977   }
00978   return mrb_fixnum_value(val >> width);
00979 }
00980 
00981 static inline void
00982 fix_shift_get_width(mrb_state *mrb, mrb_int *width)
00983 {
00984   mrb_value y;
00985 
00986   mrb_get_args(mrb, "o", &y);
00987   *width = mrb_fixnum(bit_coerce(mrb, y));
00988 }
00989 
00990 /* 15.2.8.3.12 */
00991 /*
00992  * call-seq:
00993  *   fix << count  ->  integer
00994  *
00995  * Shifts _fix_ left _count_ positions (right if _count_ is negative).
00996  */
00997 
00998 static mrb_value
00999 fix_lshift(mrb_state *mrb, mrb_value x)
01000 {
01001   mrb_int width, val;
01002 
01003   fix_shift_get_width(mrb, &width);
01004 
01005   if (width == 0) {
01006     return x;
01007   }
01008   val = mrb_fixnum(x);
01009   if (width < 0) {
01010     return rshift(val, -width);
01011   }
01012   return lshift(mrb, val, width);
01013 }
01014 
01015 /* 15.2.8.3.13 */
01016 /*
01017  * call-seq:
01018  *   fix >> count  ->  integer
01019  *
01020  * Shifts _fix_ right _count_ positions (left if _count_ is negative).
01021  */
01022 
01023 static mrb_value
01024 fix_rshift(mrb_state *mrb, mrb_value x)
01025 {
01026   mrb_int width, val;
01027 
01028   fix_shift_get_width(mrb, &width);
01029 
01030   if (width == 0) {
01031     return x;
01032   }
01033   val = mrb_fixnum(x);
01034   if (width < 0) {
01035     return lshift(mrb, val, -width);
01036   }
01037   return rshift(val, width);
01038 }
01039 
01040 /* 15.2.8.3.23 */
01041 /*
01042  *  call-seq:
01043  *     fix.to_f  ->  float
01044  *
01045  *  Converts <i>fix</i> to a <code>Float</code>.
01046  *
01047  */
01048 
01049 static mrb_value
01050 fix_to_f(mrb_state *mrb, mrb_value num)
01051 {
01052   return mrb_float_value(mrb, (mrb_float)mrb_fixnum(num));
01053 }
01054 
01055 /*
01056  *  Document-class: FloatDomainError
01057  *
01058  *  Raised when attempting to convert special float values
01059  *  (in particular infinite or NaN)
01060  *  to numerical classes which don't support them.
01061  *
01062  *     Float::INFINITY.to_r
01063  *
01064  *  <em>raises the exception:</em>
01065  *
01066  *     FloatDomainError: Infinity
01067  */
01068 /* ------------------------------------------------------------------------*/
01069 MRB_API mrb_value
01070 mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
01071 {
01072   mrb_int z;
01073 
01074   if (!mrb_float_p(x)) {
01075     mrb_raise(mrb, E_TYPE_ERROR, "non float value");
01076     z = 0; /* not reached. just suppress warnings. */
01077   }
01078   else {
01079     mrb_float d = mrb_float(x);
01080 
01081     if (isinf(d)) {
01082       mrb_raise(mrb, E_FLOATDOMAIN_ERROR, d < 0 ? "-Infinity" : "Infinity");
01083     }
01084     if (isnan(d)) {
01085       mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
01086     }
01087     z = (mrb_int)d;
01088   }
01089   return mrb_fixnum_value(z);
01090 }
01091 
01092 mrb_value
01093 mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y)
01094 {
01095   mrb_int a;
01096 
01097   a = mrb_fixnum(x);
01098   if (mrb_fixnum_p(y)) {
01099     mrb_int b, c;
01100 
01101     if (a == 0) return y;
01102     b = mrb_fixnum(y);
01103     if (mrb_int_add_overflow(a, b, &c)) {
01104       return mrb_float_value(mrb, (mrb_float)a + (mrb_float)b);
01105     }
01106     return mrb_fixnum_value(c);
01107   }
01108   return mrb_float_value(mrb, (mrb_float)a + mrb_to_flo(mrb, y));
01109 }
01110 
01111 /* 15.2.8.3.1  */
01112 /*
01113  * call-seq:
01114  *   fix + numeric  ->  numeric_result
01115  *
01116  * Performs addition: the class of the resulting object depends on
01117  * the class of <code>numeric</code> and on the magnitude of the
01118  * result.
01119  */
01120 static mrb_value
01121 fix_plus(mrb_state *mrb, mrb_value self)
01122 {
01123   mrb_value other;
01124 
01125   mrb_get_args(mrb, "o", &other);
01126   return mrb_fixnum_plus(mrb, self, other);
01127 }
01128 
01129 mrb_value
01130 mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y)
01131 {
01132   mrb_int a;
01133 
01134   a = mrb_fixnum(x);
01135   if (mrb_fixnum_p(y)) {
01136     mrb_int b, c;
01137 
01138     b = mrb_fixnum(y);
01139     if (mrb_int_sub_overflow(a, b, &c)) {
01140       return mrb_float_value(mrb, (mrb_float)a - (mrb_float)b);
01141     }
01142     return mrb_fixnum_value(c);
01143   }
01144   return mrb_float_value(mrb, (mrb_float)a - mrb_to_flo(mrb, y));
01145 }
01146 
01147 /* 15.2.8.3.2  */
01148 /* 15.2.8.3.16 */
01149 /*
01150  * call-seq:
01151  *   fix - numeric  ->  numeric_result
01152  *
01153  * Performs subtraction: the class of the resulting object depends on
01154  * the class of <code>numeric</code> and on the magnitude of the
01155  * result.
01156  */
01157 static mrb_value
01158 fix_minus(mrb_state *mrb, mrb_value self)
01159 {
01160   mrb_value other;
01161 
01162   mrb_get_args(mrb, "o", &other);
01163   return mrb_fixnum_minus(mrb, self, other);
01164 }
01165 
01166 
01167 MRB_API mrb_value
01168 mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, int base)
01169 {
01170   char buf[MRB_INT_BIT+1];
01171   char *b = buf + sizeof buf;
01172   mrb_int val = mrb_fixnum(x);
01173 
01174   if (base < 2 || 36 < base) {
01175     mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %S", mrb_fixnum_value(base));
01176   }
01177 
01178   if (val == 0) {
01179     *--b = '0';
01180   }
01181   else if (val < 0) {
01182     do {
01183       *--b = mrb_digitmap[-(val % base)];
01184     } while (val /= base);
01185     *--b = '-';
01186   }
01187   else {
01188     do {
01189       *--b = mrb_digitmap[(int)(val % base)];
01190     } while (val /= base);
01191   }
01192 
01193   return mrb_str_new(mrb, b, buf + sizeof(buf) - b);
01194 }
01195 
01196 /* 15.2.8.3.25 */
01197 /*
01198  *  call-seq:
01199  *     fix.to_s(base=10)  ->  string
01200  *
01201  *  Returns a string containing the representation of <i>fix</i> radix
01202  *  <i>base</i> (between 2 and 36).
01203  *
01204  *     12345.to_s       #=> "12345"
01205  *     12345.to_s(2)    #=> "11000000111001"
01206  *     12345.to_s(8)    #=> "30071"
01207  *     12345.to_s(10)   #=> "12345"
01208  *     12345.to_s(16)   #=> "3039"
01209  *     12345.to_s(36)   #=> "9ix"
01210  *
01211  */
01212 static mrb_value
01213 fix_to_s(mrb_state *mrb, mrb_value self)
01214 {
01215   mrb_int base = 10;
01216 
01217   mrb_get_args(mrb, "|i", &base);
01218   return mrb_fixnum_to_str(mrb, self, base);
01219 }
01220 
01221 /* 15.2.9.3.6  */
01222 /*
01223  * call-seq:
01224  *     self.f <=> other.f    => -1, 0, +1
01225  *             <  => -1
01226  *             =  =>  0
01227  *             >  => +1
01228  *  Comparison---Returns -1, 0, or +1 depending on whether <i>fix</i> is
01229  *  less than, equal to, or greater than <i>numeric</i>. This is the
01230  *  basis for the tests in <code>Comparable</code>.
01231  */
01232 static mrb_value
01233 num_cmp(mrb_state *mrb, mrb_value self)
01234 {
01235   mrb_value other;
01236   mrb_float x, y;
01237 
01238   mrb_get_args(mrb, "o", &other);
01239 
01240   x = mrb_to_flo(mrb, self);
01241   switch (mrb_type(other)) {
01242   case MRB_TT_FIXNUM:
01243     y = (mrb_float)mrb_fixnum(other);
01244     break;
01245   case MRB_TT_FLOAT:
01246     y = mrb_float(other);
01247     break;
01248   default:
01249     return mrb_nil_value();
01250   }
01251   if (x > y)
01252     return mrb_fixnum_value(1);
01253   else {
01254     if (x < y)
01255       return mrb_fixnum_value(-1);
01256     return mrb_fixnum_value(0);
01257   }
01258 }
01259 
01260 /* 15.2.9.3.1  */
01261 /*
01262  * call-seq:
01263  *   float + other  ->  float
01264  *
01265  * Returns a new float which is the sum of <code>float</code>
01266  * and <code>other</code>.
01267  */
01268 static mrb_value
01269 flo_plus(mrb_state *mrb, mrb_value x)
01270 {
01271   mrb_value y;
01272 
01273   mrb_get_args(mrb, "o", &y);
01274   return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y));
01275 }
01276 
01277 /* ------------------------------------------------------------------------*/
01278 void
01279 mrb_init_numeric(mrb_state *mrb)
01280 {
01281   struct RClass *numeric, *integer, *fixnum, *fl;
01282 
01283   /* Numeric Class */
01284   numeric = mrb_define_class(mrb, "Numeric",  mrb->object_class);                /* 15.2.7 */
01285 
01286   mrb_define_method(mrb, numeric, "**",       num_pow,        MRB_ARGS_REQ(1));
01287   mrb_define_method(mrb, numeric, "/",        num_div,        MRB_ARGS_REQ(1));  /* 15.2.8.3.4  */
01288   mrb_define_method(mrb, numeric, "quo",      num_div,        MRB_ARGS_REQ(1));  /* 15.2.7.4.5 (x) */
01289   mrb_define_method(mrb, numeric, "<=>",      num_cmp,        MRB_ARGS_REQ(1));  /* 15.2.9.3.6  */
01290 
01291   /* Integer Class */
01292   integer = mrb_define_class(mrb, "Integer",  numeric);                          /* 15.2.8 */
01293   mrb_undef_class_method(mrb, integer, "new");
01294   mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE());            /* 15.2.8.3.24 */
01295   mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE());
01296 
01297   /* Fixnum Class */
01298   fixnum = mrb->fixnum_class = mrb_define_class(mrb, "Fixnum", integer);
01299   mrb_define_method(mrb, fixnum,  "+",        fix_plus,          MRB_ARGS_REQ(1)); /* 15.2.8.3.1  */
01300   mrb_define_method(mrb, fixnum,  "-",        fix_minus,         MRB_ARGS_REQ(1)); /* 15.2.8.3.2  */
01301   mrb_define_method(mrb, fixnum,  "*",        fix_mul,           MRB_ARGS_REQ(1)); /* 15.2.8.3.3  */
01302   mrb_define_method(mrb, fixnum,  "%",        fix_mod,           MRB_ARGS_REQ(1)); /* 15.2.8.3.5  */
01303   mrb_define_method(mrb, fixnum,  "==",       fix_equal,         MRB_ARGS_REQ(1)); /* 15.2.8.3.7  */
01304   mrb_define_method(mrb, fixnum,  "~",        fix_rev,           MRB_ARGS_NONE()); /* 15.2.8.3.8  */
01305   mrb_define_method(mrb, fixnum,  "&",        fix_and,           MRB_ARGS_REQ(1)); /* 15.2.8.3.9  */
01306   mrb_define_method(mrb, fixnum,  "|",        fix_or,            MRB_ARGS_REQ(1)); /* 15.2.8.3.10 */
01307   mrb_define_method(mrb, fixnum,  "^",        fix_xor,           MRB_ARGS_REQ(1)); /* 15.2.8.3.11 */
01308   mrb_define_method(mrb, fixnum,  "<<",       fix_lshift,        MRB_ARGS_REQ(1)); /* 15.2.8.3.12 */
01309   mrb_define_method(mrb, fixnum,  ">>",       fix_rshift,        MRB_ARGS_REQ(1)); /* 15.2.8.3.13 */
01310   mrb_define_method(mrb, fixnum,  "eql?",     fix_eql,           MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
01311   mrb_define_method(mrb, fixnum,  "hash",     flo_hash,          MRB_ARGS_NONE()); /* 15.2.8.3.18 */
01312   mrb_define_method(mrb, fixnum,  "to_f",     fix_to_f,          MRB_ARGS_NONE()); /* 15.2.8.3.23 */
01313   mrb_define_method(mrb, fixnum,  "to_s",     fix_to_s,          MRB_ARGS_NONE()); /* 15.2.8.3.25 */
01314   mrb_define_method(mrb, fixnum,  "inspect",  fix_to_s,          MRB_ARGS_NONE());
01315   mrb_define_method(mrb, fixnum,  "divmod",   fix_divmod,        MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */
01316 
01317   /* Float Class */
01318   fl = mrb->float_class = mrb_define_class(mrb, "Float", numeric);                 /* 15.2.9 */
01319   mrb_undef_class_method(mrb,  fl, "new");
01320   mrb_define_method(mrb, fl,      "+",         flo_plus,         MRB_ARGS_REQ(1)); /* 15.2.9.3.1  */
01321   mrb_define_method(mrb, fl,      "-",         flo_minus,        MRB_ARGS_REQ(1)); /* 15.2.9.3.2  */
01322   mrb_define_method(mrb, fl,      "*",         flo_mul,          MRB_ARGS_REQ(1)); /* 15.2.9.3.3  */
01323   mrb_define_method(mrb, fl,      "%",         flo_mod,          MRB_ARGS_REQ(1)); /* 15.2.9.3.5  */
01324   mrb_define_method(mrb, fl,      "==",        flo_eq,           MRB_ARGS_REQ(1)); /* 15.2.9.3.7  */
01325   mrb_define_method(mrb, fl,      "ceil",      flo_ceil,         MRB_ARGS_NONE()); /* 15.2.9.3.8  */
01326   mrb_define_method(mrb, fl,      "finite?",   flo_finite_p,     MRB_ARGS_NONE()); /* 15.2.9.3.9  */
01327   mrb_define_method(mrb, fl,      "floor",     flo_floor,        MRB_ARGS_NONE()); /* 15.2.9.3.10 */
01328   mrb_define_method(mrb, fl,      "infinite?", flo_infinite_p,   MRB_ARGS_NONE()); /* 15.2.9.3.11 */
01329   mrb_define_method(mrb, fl,      "round",     flo_round,        MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */
01330   mrb_define_method(mrb, fl,      "to_f",      flo_to_f,         MRB_ARGS_NONE()); /* 15.2.9.3.13 */
01331   mrb_define_method(mrb, fl,      "to_i",      flo_truncate,     MRB_ARGS_NONE()); /* 15.2.9.3.14 */
01332   mrb_define_method(mrb, fl,      "to_int",    flo_truncate,     MRB_ARGS_NONE());
01333   mrb_define_method(mrb, fl,      "truncate",  flo_truncate,     MRB_ARGS_NONE()); /* 15.2.9.3.15 */
01334   mrb_define_method(mrb, fl,      "divmod",    flo_divmod,       MRB_ARGS_REQ(1));
01335   mrb_define_method(mrb, fl,      "eql?",      flo_eql,          MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
01336 
01337   mrb_define_method(mrb, fl,      "to_s",      flo_to_s,         MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */
01338   mrb_define_method(mrb, fl,      "inspect",   flo_to_s,         MRB_ARGS_NONE());
01339   mrb_define_method(mrb, fl,      "nan?",      flo_nan_p,        MRB_ARGS_NONE());
01340 
01341 #ifdef INFINITY
01342   mrb_define_const(mrb, fl, "INFINITY", mrb_float_value(mrb, INFINITY));
01343 #endif
01344 #ifdef NAN
01345   mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN));
01346 #endif
01347 }
01348