mbed I/F binding for mruby
Dependents: mruby_mbed_web mirb_mbed
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
Generated on Tue Jul 12 2022 18:00:34 by 1.7.2