[270] | 1 | /*
|
---|
| 2 | ** numeric.c - Numeric, Integer, Float, Fixnum class
|
---|
| 3 | **
|
---|
| 4 | ** See Copyright Notice in mruby.h
|
---|
| 5 | */
|
---|
| 6 |
|
---|
[439] | 7 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[270] | 8 | #include <float.h>
|
---|
[439] | 9 | #include <math.h>
|
---|
| 10 | #endif
|
---|
[270] | 11 | #include <limits.h>
|
---|
| 12 | #include <stdlib.h>
|
---|
[439] | 13 | #include <string.h>
|
---|
[270] | 14 |
|
---|
[331] | 15 | #include <mruby.h>
|
---|
| 16 | #include <mruby/array.h>
|
---|
| 17 | #include <mruby/numeric.h>
|
---|
| 18 | #include <mruby/string.h>
|
---|
| 19 | #include <mruby/class.h>
|
---|
[270] | 20 |
|
---|
[439] | 21 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[270] | 22 | #ifdef MRB_USE_FLOAT
|
---|
[331] | 23 | #define trunc(f) truncf(f)
|
---|
[270] | 24 | #define floor(f) floorf(f)
|
---|
| 25 | #define ceil(f) ceilf(f)
|
---|
| 26 | #define fmod(x,y) fmodf(x,y)
|
---|
[439] | 27 | #define FLO_TO_STR_PREC 8
|
---|
[270] | 28 | #else
|
---|
[439] | 29 | #define FLO_TO_STR_PREC 16
|
---|
[270] | 30 | #endif
|
---|
[439] | 31 | #endif
|
---|
[270] | 32 |
|
---|
[439] | 33 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[270] | 34 | MRB_API mrb_float
|
---|
| 35 | mrb_to_flo(mrb_state *mrb, mrb_value val)
|
---|
| 36 | {
|
---|
| 37 | switch (mrb_type(val)) {
|
---|
| 38 | case MRB_TT_FIXNUM:
|
---|
| 39 | return (mrb_float)mrb_fixnum(val);
|
---|
| 40 | case MRB_TT_FLOAT:
|
---|
| 41 | break;
|
---|
| 42 | default:
|
---|
| 43 | mrb_raise(mrb, E_TYPE_ERROR, "non float value");
|
---|
| 44 | }
|
---|
| 45 | return mrb_float(val);
|
---|
| 46 | }
|
---|
| 47 |
|
---|
[439] | 48 | MRB_API mrb_value
|
---|
| 49 | mrb_int_value(mrb_state *mrb, mrb_float f)
|
---|
| 50 | {
|
---|
| 51 | if (FIXABLE_FLOAT(f)) {
|
---|
| 52 | return mrb_fixnum_value((mrb_int)f);
|
---|
| 53 | }
|
---|
| 54 | return mrb_float_value(mrb, f);
|
---|
| 55 | }
|
---|
| 56 | #endif
|
---|
| 57 |
|
---|
[270] | 58 | /*
|
---|
| 59 | * call-seq:
|
---|
| 60 | *
|
---|
| 61 | * num ** other -> num
|
---|
| 62 | *
|
---|
| 63 | * Raises <code>num</code> the <code>other</code> power.
|
---|
| 64 | *
|
---|
| 65 | * 2.0**3 #=> 8.0
|
---|
| 66 | */
|
---|
| 67 | static mrb_value
|
---|
[439] | 68 | integral_pow(mrb_state *mrb, mrb_value x)
|
---|
[270] | 69 | {
|
---|
| 70 | mrb_value y;
|
---|
[439] | 71 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[331] | 72 | mrb_float d;
|
---|
[439] | 73 | #endif
|
---|
[270] | 74 |
|
---|
| 75 | mrb_get_args(mrb, "o", &y);
|
---|
[331] | 76 | if (mrb_fixnum_p(x) && mrb_fixnum_p(y)) {
|
---|
| 77 | /* try ipow() */
|
---|
| 78 | mrb_int base = mrb_fixnum(x);
|
---|
| 79 | mrb_int exp = mrb_fixnum(y);
|
---|
| 80 | mrb_int result = 1;
|
---|
| 81 |
|
---|
[439] | 82 | if (exp < 0)
|
---|
| 83 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 84 | return mrb_fixnum_value(0);
|
---|
| 85 | #else
|
---|
| 86 | goto float_pow;
|
---|
| 87 | #endif
|
---|
[331] | 88 | for (;;) {
|
---|
| 89 | if (exp & 1) {
|
---|
| 90 | if (mrb_int_mul_overflow(result, base, &result)) {
|
---|
[439] | 91 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[331] | 92 | goto float_pow;
|
---|
[439] | 93 | #endif
|
---|
[331] | 94 | }
|
---|
| 95 | }
|
---|
| 96 | exp >>= 1;
|
---|
| 97 | if (exp == 0) break;
|
---|
| 98 | if (mrb_int_mul_overflow(base, base, &base)) {
|
---|
[439] | 99 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[331] | 100 | goto float_pow;
|
---|
[439] | 101 | #endif
|
---|
[331] | 102 | }
|
---|
| 103 | }
|
---|
| 104 | return mrb_fixnum_value(result);
|
---|
| 105 | }
|
---|
[439] | 106 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 107 | mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
|
---|
| 108 | #else
|
---|
[331] | 109 | float_pow:
|
---|
| 110 | d = pow(mrb_to_flo(mrb, x), mrb_to_flo(mrb, y));
|
---|
[270] | 111 | return mrb_float_value(mrb, d);
|
---|
[439] | 112 | #endif
|
---|
[270] | 113 | }
|
---|
| 114 |
|
---|
[439] | 115 | static mrb_value
|
---|
| 116 | integral_idiv(mrb_state *mrb, mrb_value x)
|
---|
| 117 | {
|
---|
| 118 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 119 | mrb_value y;
|
---|
| 120 |
|
---|
| 121 | mrb_get_args(mrb, "o", &y);
|
---|
| 122 | if (!mrb_fixnum_p(y)) {
|
---|
| 123 | mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
|
---|
| 124 | }
|
---|
| 125 | return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y));
|
---|
| 126 | #else
|
---|
| 127 | mrb_float y;
|
---|
| 128 |
|
---|
| 129 | mrb_get_args(mrb, "f", &y);
|
---|
| 130 | return mrb_int_value(mrb, mrb_to_flo(mrb, x) / y);
|
---|
| 131 | #endif
|
---|
| 132 | }
|
---|
| 133 |
|
---|
[270] | 134 | /* 15.2.8.3.4 */
|
---|
| 135 | /* 15.2.9.3.4 */
|
---|
| 136 | /*
|
---|
| 137 | * call-seq:
|
---|
| 138 | * num / other -> num
|
---|
| 139 | *
|
---|
| 140 | * Performs division: the class of the resulting object depends on
|
---|
| 141 | * the class of <code>num</code> and on the magnitude of the
|
---|
| 142 | * result.
|
---|
| 143 | */
|
---|
| 144 |
|
---|
| 145 | /* 15.2.9.3.19(x) */
|
---|
| 146 | /*
|
---|
| 147 | * call-seq:
|
---|
| 148 | * num.quo(numeric) -> real
|
---|
| 149 | *
|
---|
| 150 | * Returns most exact division.
|
---|
| 151 | */
|
---|
| 152 |
|
---|
| 153 | static mrb_value
|
---|
[439] | 154 | integral_div(mrb_state *mrb, mrb_value x)
|
---|
[270] | 155 | {
|
---|
[439] | 156 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 157 | mrb_value y;
|
---|
| 158 |
|
---|
| 159 | mrb_get_args(mrb, "o", &y);
|
---|
| 160 | if (!mrb_fixnum_p(y)) {
|
---|
| 161 | mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
|
---|
| 162 | }
|
---|
| 163 | return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y));
|
---|
| 164 | #else
|
---|
[270] | 165 | mrb_float y;
|
---|
| 166 |
|
---|
| 167 | mrb_get_args(mrb, "f", &y);
|
---|
| 168 | return mrb_float_value(mrb, mrb_to_flo(mrb, x) / y);
|
---|
[439] | 169 | #endif
|
---|
[270] | 170 | }
|
---|
| 171 |
|
---|
[439] | 172 | static mrb_value
|
---|
| 173 | integral_coerce_step_counter(mrb_state *mrb, mrb_value self)
|
---|
| 174 | {
|
---|
| 175 | mrb_value num, step;
|
---|
| 176 |
|
---|
| 177 | mrb_get_args(mrb, "oo", &num, &step);
|
---|
| 178 |
|
---|
| 179 | #ifndef MRB_WITHOUT_FLOAT
|
---|
| 180 | if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) {
|
---|
| 181 | return mrb_Float(mrb, self);
|
---|
| 182 | }
|
---|
| 183 | #endif
|
---|
| 184 |
|
---|
| 185 | return self;
|
---|
| 186 | }
|
---|
| 187 |
|
---|
| 188 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[270] | 189 | /********************************************************************
|
---|
| 190 | *
|
---|
| 191 | * Document-class: Float
|
---|
| 192 | *
|
---|
| 193 | * <code>Float</code> objects represent inexact real numbers using
|
---|
| 194 | * the native architecture's double-precision floating point
|
---|
| 195 | * representation.
|
---|
| 196 | */
|
---|
| 197 |
|
---|
| 198 | /* 15.2.9.3.16(x) */
|
---|
| 199 | /*
|
---|
| 200 | * call-seq:
|
---|
| 201 | * flt.to_s -> string
|
---|
| 202 | *
|
---|
| 203 | * Returns a string containing a representation of self. As well as a
|
---|
| 204 | * fixed or exponential form of the number, the call may return
|
---|
| 205 | * "<code>NaN</code>", "<code>Infinity</code>", and
|
---|
| 206 | * "<code>-Infinity</code>".
|
---|
| 207 | */
|
---|
| 208 |
|
---|
| 209 | static mrb_value
|
---|
| 210 | flo_to_s(mrb_state *mrb, mrb_value flt)
|
---|
| 211 | {
|
---|
[439] | 212 | mrb_float f = mrb_float(flt);
|
---|
| 213 |
|
---|
| 214 | if (isinf(f)) {
|
---|
| 215 | return f < 0 ? mrb_str_new_lit(mrb, "-Infinity")
|
---|
| 216 | : mrb_str_new_lit(mrb, "Infinity");
|
---|
| 217 | }
|
---|
| 218 | else if (isnan(f)) {
|
---|
[270] | 219 | return mrb_str_new_lit(mrb, "NaN");
|
---|
| 220 | }
|
---|
[439] | 221 | else {
|
---|
| 222 | char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g";
|
---|
| 223 | mrb_value str = mrb_float_to_str(mrb, flt, fmt);
|
---|
| 224 | mrb_int len;
|
---|
| 225 | char *begp, *p, *endp;
|
---|
| 226 |
|
---|
| 227 | insert_dot_zero:
|
---|
| 228 | begp = RSTRING_PTR(str);
|
---|
| 229 | len = RSTRING_LEN(str);
|
---|
| 230 | for (p = begp, endp = p + len; p < endp; ++p) {
|
---|
| 231 | if (*p == '.') {
|
---|
| 232 | return str;
|
---|
| 233 | }
|
---|
| 234 | else if (*p == 'e') {
|
---|
| 235 | ptrdiff_t e_pos = p - begp;
|
---|
| 236 | mrb_str_cat(mrb, str, ".0", 2);
|
---|
| 237 | p = RSTRING_PTR(str) + e_pos;
|
---|
| 238 | memmove(p + 2, p, len - e_pos);
|
---|
| 239 | memcpy(p, ".0", 2);
|
---|
| 240 | return str;
|
---|
| 241 | }
|
---|
| 242 | }
|
---|
| 243 |
|
---|
| 244 | if (FLO_TO_STR_PREC + (begp[0] == '-') <= len) {
|
---|
| 245 | --fmt[sizeof(fmt) - 3]; /* %.16g(%.8g) -> %.15g(%.7g) */
|
---|
| 246 | str = mrb_float_to_str(mrb, flt, fmt);
|
---|
| 247 | goto insert_dot_zero;
|
---|
| 248 | }
|
---|
| 249 |
|
---|
| 250 | return str;
|
---|
| 251 | }
|
---|
[270] | 252 | }
|
---|
| 253 |
|
---|
| 254 | /* 15.2.9.3.2 */
|
---|
| 255 | /*
|
---|
| 256 | * call-seq:
|
---|
| 257 | * float - other -> float
|
---|
| 258 | *
|
---|
| 259 | * Returns a new float which is the difference of <code>float</code>
|
---|
| 260 | * and <code>other</code>.
|
---|
| 261 | */
|
---|
| 262 |
|
---|
| 263 | static mrb_value
|
---|
| 264 | flo_minus(mrb_state *mrb, mrb_value x)
|
---|
| 265 | {
|
---|
| 266 | mrb_value y;
|
---|
| 267 |
|
---|
| 268 | mrb_get_args(mrb, "o", &y);
|
---|
| 269 | return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y));
|
---|
| 270 | }
|
---|
| 271 |
|
---|
| 272 | /* 15.2.9.3.3 */
|
---|
| 273 | /*
|
---|
| 274 | * call-seq:
|
---|
| 275 | * float * other -> float
|
---|
| 276 | *
|
---|
| 277 | * Returns a new float which is the product of <code>float</code>
|
---|
| 278 | * and <code>other</code>.
|
---|
| 279 | */
|
---|
| 280 |
|
---|
| 281 | static mrb_value
|
---|
| 282 | flo_mul(mrb_state *mrb, mrb_value x)
|
---|
| 283 | {
|
---|
| 284 | mrb_value y;
|
---|
| 285 |
|
---|
| 286 | mrb_get_args(mrb, "o", &y);
|
---|
| 287 | return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y));
|
---|
| 288 | }
|
---|
| 289 |
|
---|
| 290 | static void
|
---|
[439] | 291 | flodivmod(mrb_state *mrb, double x, double y, mrb_float *divp, mrb_float *modp)
|
---|
[270] | 292 | {
|
---|
[439] | 293 | double div, mod;
|
---|
[270] | 294 |
|
---|
[439] | 295 | if (isnan(y)) {
|
---|
| 296 | /* y is NaN so all results are NaN */
|
---|
| 297 | div = mod = y;
|
---|
| 298 | goto exit;
|
---|
| 299 | }
|
---|
[270] | 300 | if (y == 0.0) {
|
---|
[439] | 301 | if (x == 0) div = NAN;
|
---|
| 302 | else if (x > 0.0) div = INFINITY;
|
---|
| 303 | else div = -INFINITY; /* x < 0.0 */
|
---|
[270] | 304 | mod = NAN;
|
---|
[439] | 305 | goto exit;
|
---|
[270] | 306 | }
|
---|
[439] | 307 | if ((x == 0.0) || (isinf(y) && !isinf(x))) {
|
---|
| 308 | mod = x;
|
---|
| 309 | }
|
---|
[270] | 310 | else {
|
---|
| 311 | mod = fmod(x, y);
|
---|
| 312 | }
|
---|
[439] | 313 | if (isinf(x) && !isinf(y)) {
|
---|
| 314 | div = x;
|
---|
| 315 | }
|
---|
| 316 | else {
|
---|
| 317 | div = (x - mod) / y;
|
---|
| 318 | if (modp && divp) div = round(div);
|
---|
| 319 | }
|
---|
| 320 | if (div == 0) div = 0.0;
|
---|
| 321 | if (mod == 0) mod = 0.0;
|
---|
| 322 | if (y*mod < 0) {
|
---|
| 323 | mod += y;
|
---|
| 324 | div -= 1.0;
|
---|
| 325 | }
|
---|
| 326 | exit:
|
---|
[270] | 327 | if (modp) *modp = mod;
|
---|
| 328 | if (divp) *divp = div;
|
---|
| 329 | }
|
---|
| 330 |
|
---|
| 331 | /* 15.2.9.3.5 */
|
---|
| 332 | /*
|
---|
| 333 | * call-seq:
|
---|
| 334 | * flt % other -> float
|
---|
| 335 | * flt.modulo(other) -> float
|
---|
| 336 | *
|
---|
| 337 | * Return the modulo after division of <code>flt</code> by <code>other</code>.
|
---|
| 338 | *
|
---|
| 339 | * 6543.21.modulo(137) #=> 104.21
|
---|
| 340 | * 6543.21.modulo(137.24) #=> 92.9299999999996
|
---|
| 341 | */
|
---|
| 342 |
|
---|
| 343 | static mrb_value
|
---|
| 344 | flo_mod(mrb_state *mrb, mrb_value x)
|
---|
| 345 | {
|
---|
| 346 | mrb_value y;
|
---|
| 347 | mrb_float mod;
|
---|
| 348 |
|
---|
| 349 | mrb_get_args(mrb, "o", &y);
|
---|
| 350 |
|
---|
| 351 | flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), 0, &mod);
|
---|
| 352 | return mrb_float_value(mrb, mod);
|
---|
| 353 | }
|
---|
[439] | 354 | #endif
|
---|
[270] | 355 |
|
---|
| 356 | /* 15.2.8.3.16 */
|
---|
| 357 | /*
|
---|
| 358 | * call-seq:
|
---|
| 359 | * num.eql?(numeric) -> true or false
|
---|
| 360 | *
|
---|
| 361 | * Returns <code>true</code> if <i>num</i> and <i>numeric</i> are the
|
---|
| 362 | * same type and have equal values.
|
---|
| 363 | *
|
---|
| 364 | * 1 == 1.0 #=> true
|
---|
| 365 | * 1.eql?(1.0) #=> false
|
---|
| 366 | * (1.0).eql?(1.0) #=> true
|
---|
| 367 | */
|
---|
| 368 | static mrb_value
|
---|
| 369 | fix_eql(mrb_state *mrb, mrb_value x)
|
---|
| 370 | {
|
---|
| 371 | mrb_value y;
|
---|
| 372 |
|
---|
| 373 | mrb_get_args(mrb, "o", &y);
|
---|
| 374 | if (!mrb_fixnum_p(y)) return mrb_false_value();
|
---|
| 375 | return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y));
|
---|
| 376 | }
|
---|
| 377 |
|
---|
[439] | 378 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[270] | 379 | static mrb_value
|
---|
| 380 | flo_eql(mrb_state *mrb, mrb_value x)
|
---|
| 381 | {
|
---|
| 382 | mrb_value y;
|
---|
| 383 |
|
---|
| 384 | mrb_get_args(mrb, "o", &y);
|
---|
| 385 | if (!mrb_float_p(y)) return mrb_false_value();
|
---|
[439] | 386 | return mrb_bool_value(mrb_float(x) == mrb_float(y));
|
---|
[270] | 387 | }
|
---|
| 388 |
|
---|
| 389 | /* 15.2.9.3.7 */
|
---|
| 390 | /*
|
---|
| 391 | * call-seq:
|
---|
| 392 | * flt == obj -> true or false
|
---|
| 393 | *
|
---|
| 394 | * Returns <code>true</code> only if <i>obj</i> has the same value
|
---|
| 395 | * as <i>flt</i>. Contrast this with <code>Float#eql?</code>, which
|
---|
| 396 | * requires <i>obj</i> to be a <code>Float</code>.
|
---|
| 397 | *
|
---|
| 398 | * 1.0 == 1 #=> true
|
---|
| 399 | *
|
---|
| 400 | */
|
---|
| 401 |
|
---|
| 402 | static mrb_value
|
---|
| 403 | flo_eq(mrb_state *mrb, mrb_value x)
|
---|
| 404 | {
|
---|
| 405 | mrb_value y;
|
---|
| 406 | mrb_get_args(mrb, "o", &y);
|
---|
| 407 |
|
---|
| 408 | switch (mrb_type(y)) {
|
---|
| 409 | case MRB_TT_FIXNUM:
|
---|
| 410 | return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y));
|
---|
| 411 | case MRB_TT_FLOAT:
|
---|
| 412 | return mrb_bool_value(mrb_float(x) == mrb_float(y));
|
---|
| 413 | default:
|
---|
| 414 | return mrb_false_value();
|
---|
| 415 | }
|
---|
| 416 | }
|
---|
| 417 |
|
---|
[331] | 418 | static int64_t
|
---|
| 419 | value_int64(mrb_state *mrb, mrb_value x)
|
---|
| 420 | {
|
---|
| 421 | switch (mrb_type(x)) {
|
---|
| 422 | case MRB_TT_FIXNUM:
|
---|
| 423 | return (int64_t)mrb_fixnum(x);
|
---|
| 424 | break;
|
---|
| 425 | case MRB_TT_FLOAT:
|
---|
| 426 | return (int64_t)mrb_float(x);
|
---|
| 427 | default:
|
---|
| 428 | mrb_raise(mrb, E_TYPE_ERROR, "cannot convert to Integer");
|
---|
| 429 | break;
|
---|
| 430 | }
|
---|
| 431 | /* not reached */
|
---|
| 432 | return 0;
|
---|
| 433 | }
|
---|
| 434 |
|
---|
| 435 | static mrb_value
|
---|
| 436 | int64_value(mrb_state *mrb, int64_t v)
|
---|
| 437 | {
|
---|
[439] | 438 | if (TYPED_FIXABLE(v,int64_t)) {
|
---|
[331] | 439 | return mrb_fixnum_value((mrb_int)v);
|
---|
| 440 | }
|
---|
| 441 | return mrb_float_value(mrb, (mrb_float)v);
|
---|
| 442 | }
|
---|
| 443 |
|
---|
| 444 | static mrb_value
|
---|
| 445 | flo_rev(mrb_state *mrb, mrb_value x)
|
---|
| 446 | {
|
---|
| 447 | int64_t v1;
|
---|
| 448 | v1 = (int64_t)mrb_float(x);
|
---|
| 449 | return int64_value(mrb, ~v1);
|
---|
| 450 | }
|
---|
| 451 |
|
---|
| 452 | static mrb_value
|
---|
| 453 | flo_and(mrb_state *mrb, mrb_value x)
|
---|
| 454 | {
|
---|
| 455 | mrb_value y;
|
---|
| 456 | int64_t v1, v2;
|
---|
| 457 | mrb_get_args(mrb, "o", &y);
|
---|
| 458 |
|
---|
| 459 | v1 = (int64_t)mrb_float(x);
|
---|
| 460 | v2 = value_int64(mrb, y);
|
---|
| 461 | return int64_value(mrb, v1 & v2);
|
---|
| 462 | }
|
---|
| 463 |
|
---|
| 464 | static mrb_value
|
---|
| 465 | flo_or(mrb_state *mrb, mrb_value x)
|
---|
| 466 | {
|
---|
| 467 | mrb_value y;
|
---|
| 468 | int64_t v1, v2;
|
---|
| 469 | mrb_get_args(mrb, "o", &y);
|
---|
| 470 |
|
---|
| 471 | v1 = (int64_t)mrb_float(x);
|
---|
| 472 | v2 = value_int64(mrb, y);
|
---|
| 473 | return int64_value(mrb, v1 | v2);
|
---|
| 474 | }
|
---|
| 475 |
|
---|
| 476 | static mrb_value
|
---|
| 477 | flo_xor(mrb_state *mrb, mrb_value x)
|
---|
| 478 | {
|
---|
| 479 | mrb_value y;
|
---|
| 480 | int64_t v1, v2;
|
---|
| 481 | mrb_get_args(mrb, "o", &y);
|
---|
| 482 |
|
---|
| 483 | v1 = (int64_t)mrb_float(x);
|
---|
| 484 | v2 = value_int64(mrb, y);
|
---|
| 485 | return int64_value(mrb, v1 ^ v2);
|
---|
| 486 | }
|
---|
| 487 |
|
---|
| 488 | static mrb_value
|
---|
| 489 | flo_shift(mrb_state *mrb, mrb_value x, mrb_int width)
|
---|
| 490 | {
|
---|
| 491 | mrb_float val;
|
---|
| 492 |
|
---|
| 493 | if (width == 0) {
|
---|
| 494 | return x;
|
---|
| 495 | }
|
---|
| 496 | val = mrb_float(x);
|
---|
| 497 | if (width < 0) {
|
---|
| 498 | while (width++) {
|
---|
| 499 | val /= 2;
|
---|
[439] | 500 | if (val < 1.0) {
|
---|
| 501 | val = 0;
|
---|
| 502 | break;
|
---|
| 503 | }
|
---|
[331] | 504 | }
|
---|
| 505 | #if defined(_ISOC99_SOURCE)
|
---|
| 506 | val = trunc(val);
|
---|
| 507 | #else
|
---|
[439] | 508 | if (val > 0){
|
---|
| 509 | val = floor(val);
|
---|
| 510 | } else {
|
---|
| 511 | val = ceil(val);
|
---|
| 512 | }
|
---|
[331] | 513 | #endif
|
---|
| 514 | if (val == 0 && mrb_float(x) < 0) {
|
---|
| 515 | return mrb_fixnum_value(-1);
|
---|
| 516 | }
|
---|
| 517 | }
|
---|
| 518 | else {
|
---|
| 519 | while (width--) {
|
---|
| 520 | val *= 2;
|
---|
| 521 | }
|
---|
| 522 | }
|
---|
[439] | 523 | return mrb_int_value(mrb, val);
|
---|
[331] | 524 | }
|
---|
| 525 |
|
---|
| 526 | static mrb_value
|
---|
[439] | 527 | flo_rshift(mrb_state *mrb, mrb_value x)
|
---|
[331] | 528 | {
|
---|
| 529 | mrb_int width;
|
---|
| 530 |
|
---|
| 531 | mrb_get_args(mrb, "i", &width);
|
---|
| 532 | return flo_shift(mrb, x, -width);
|
---|
| 533 | }
|
---|
| 534 |
|
---|
| 535 | static mrb_value
|
---|
[439] | 536 | flo_lshift(mrb_state *mrb, mrb_value x)
|
---|
[331] | 537 | {
|
---|
| 538 | mrb_int width;
|
---|
| 539 |
|
---|
| 540 | mrb_get_args(mrb, "i", &width);
|
---|
| 541 | return flo_shift(mrb, x, width);
|
---|
| 542 | }
|
---|
| 543 |
|
---|
[270] | 544 | /* 15.2.9.3.13 */
|
---|
| 545 | /*
|
---|
| 546 | * call-seq:
|
---|
| 547 | * flt.to_f -> self
|
---|
| 548 | *
|
---|
| 549 | * As <code>flt</code> is already a float, returns +self+.
|
---|
| 550 | */
|
---|
| 551 |
|
---|
| 552 | static mrb_value
|
---|
| 553 | flo_to_f(mrb_state *mrb, mrb_value num)
|
---|
| 554 | {
|
---|
| 555 | return num;
|
---|
| 556 | }
|
---|
| 557 |
|
---|
| 558 | /* 15.2.9.3.11 */
|
---|
| 559 | /*
|
---|
| 560 | * call-seq:
|
---|
| 561 | * flt.infinite? -> nil, -1, +1
|
---|
| 562 | *
|
---|
| 563 | * Returns <code>nil</code>, -1, or +1 depending on whether <i>flt</i>
|
---|
| 564 | * is finite, -infinity, or +infinity.
|
---|
| 565 | *
|
---|
| 566 | * (0.0).infinite? #=> nil
|
---|
| 567 | * (-1.0/0.0).infinite? #=> -1
|
---|
| 568 | * (+1.0/0.0).infinite? #=> 1
|
---|
| 569 | */
|
---|
| 570 |
|
---|
| 571 | static mrb_value
|
---|
| 572 | flo_infinite_p(mrb_state *mrb, mrb_value num)
|
---|
| 573 | {
|
---|
| 574 | mrb_float value = mrb_float(num);
|
---|
| 575 |
|
---|
| 576 | if (isinf(value)) {
|
---|
| 577 | return mrb_fixnum_value(value < 0 ? -1 : 1);
|
---|
| 578 | }
|
---|
| 579 | return mrb_nil_value();
|
---|
| 580 | }
|
---|
| 581 |
|
---|
| 582 | /* 15.2.9.3.9 */
|
---|
| 583 | /*
|
---|
| 584 | * call-seq:
|
---|
| 585 | * flt.finite? -> true or false
|
---|
| 586 | *
|
---|
| 587 | * Returns <code>true</code> if <i>flt</i> is a valid IEEE floating
|
---|
| 588 | * point number (it is not infinite, and <code>nan?</code> is
|
---|
| 589 | * <code>false</code>).
|
---|
| 590 | *
|
---|
| 591 | */
|
---|
| 592 |
|
---|
| 593 | static mrb_value
|
---|
| 594 | flo_finite_p(mrb_state *mrb, mrb_value num)
|
---|
| 595 | {
|
---|
| 596 | return mrb_bool_value(isfinite(mrb_float(num)));
|
---|
| 597 | }
|
---|
| 598 |
|
---|
[331] | 599 | void
|
---|
| 600 | mrb_check_num_exact(mrb_state *mrb, mrb_float num)
|
---|
| 601 | {
|
---|
| 602 | if (isinf(num)) {
|
---|
| 603 | mrb_raise(mrb, E_FLOATDOMAIN_ERROR, num < 0 ? "-Infinity" : "Infinity");
|
---|
| 604 | }
|
---|
| 605 | if (isnan(num)) {
|
---|
| 606 | mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
|
---|
| 607 | }
|
---|
| 608 | }
|
---|
| 609 |
|
---|
[270] | 610 | /* 15.2.9.3.10 */
|
---|
| 611 | /*
|
---|
| 612 | * call-seq:
|
---|
| 613 | * flt.floor -> integer
|
---|
| 614 | *
|
---|
| 615 | * Returns the largest integer less than or equal to <i>flt</i>.
|
---|
| 616 | *
|
---|
| 617 | * 1.2.floor #=> 1
|
---|
| 618 | * 2.0.floor #=> 2
|
---|
| 619 | * (-1.2).floor #=> -2
|
---|
| 620 | * (-2.0).floor #=> -2
|
---|
| 621 | */
|
---|
| 622 |
|
---|
| 623 | static mrb_value
|
---|
| 624 | flo_floor(mrb_state *mrb, mrb_value num)
|
---|
| 625 | {
|
---|
| 626 | mrb_float f = floor(mrb_float(num));
|
---|
| 627 |
|
---|
[331] | 628 | mrb_check_num_exact(mrb, f);
|
---|
[439] | 629 | return mrb_int_value(mrb, f);
|
---|
[270] | 630 | }
|
---|
| 631 |
|
---|
| 632 | /* 15.2.9.3.8 */
|
---|
| 633 | /*
|
---|
| 634 | * call-seq:
|
---|
| 635 | * flt.ceil -> integer
|
---|
| 636 | *
|
---|
| 637 | * Returns the smallest <code>Integer</code> greater than or equal to
|
---|
| 638 | * <i>flt</i>.
|
---|
| 639 | *
|
---|
| 640 | * 1.2.ceil #=> 2
|
---|
| 641 | * 2.0.ceil #=> 2
|
---|
| 642 | * (-1.2).ceil #=> -1
|
---|
| 643 | * (-2.0).ceil #=> -2
|
---|
| 644 | */
|
---|
| 645 |
|
---|
| 646 | static mrb_value
|
---|
| 647 | flo_ceil(mrb_state *mrb, mrb_value num)
|
---|
| 648 | {
|
---|
| 649 | mrb_float f = ceil(mrb_float(num));
|
---|
| 650 |
|
---|
[331] | 651 | mrb_check_num_exact(mrb, f);
|
---|
[439] | 652 | return mrb_int_value(mrb, f);
|
---|
[270] | 653 | }
|
---|
| 654 |
|
---|
| 655 | /* 15.2.9.3.12 */
|
---|
| 656 | /*
|
---|
| 657 | * call-seq:
|
---|
| 658 | * flt.round([ndigits]) -> integer or float
|
---|
| 659 | *
|
---|
| 660 | * Rounds <i>flt</i> to a given precision in decimal digits (default 0 digits).
|
---|
| 661 | * Precision may be negative. Returns a floating point number when ndigits
|
---|
| 662 | * is more than zero.
|
---|
| 663 | *
|
---|
| 664 | * 1.4.round #=> 1
|
---|
| 665 | * 1.5.round #=> 2
|
---|
| 666 | * 1.6.round #=> 2
|
---|
| 667 | * (-1.5).round #=> -2
|
---|
| 668 | *
|
---|
| 669 | * 1.234567.round(2) #=> 1.23
|
---|
| 670 | * 1.234567.round(3) #=> 1.235
|
---|
| 671 | * 1.234567.round(4) #=> 1.2346
|
---|
| 672 | * 1.234567.round(5) #=> 1.23457
|
---|
| 673 | *
|
---|
| 674 | * 34567.89.round(-5) #=> 0
|
---|
| 675 | * 34567.89.round(-4) #=> 30000
|
---|
| 676 | * 34567.89.round(-3) #=> 35000
|
---|
| 677 | * 34567.89.round(-2) #=> 34600
|
---|
| 678 | * 34567.89.round(-1) #=> 34570
|
---|
| 679 | * 34567.89.round(0) #=> 34568
|
---|
| 680 | * 34567.89.round(1) #=> 34567.9
|
---|
| 681 | * 34567.89.round(2) #=> 34567.89
|
---|
| 682 | * 34567.89.round(3) #=> 34567.89
|
---|
| 683 | *
|
---|
| 684 | */
|
---|
| 685 |
|
---|
| 686 | static mrb_value
|
---|
| 687 | flo_round(mrb_state *mrb, mrb_value num)
|
---|
| 688 | {
|
---|
| 689 | double number, f;
|
---|
| 690 | mrb_int ndigits = 0;
|
---|
| 691 | mrb_int i;
|
---|
| 692 |
|
---|
| 693 | mrb_get_args(mrb, "|i", &ndigits);
|
---|
| 694 | number = mrb_float(num);
|
---|
| 695 |
|
---|
[331] | 696 | if (0 < ndigits && (isinf(number) || isnan(number))) {
|
---|
| 697 | return num;
|
---|
[270] | 698 | }
|
---|
[331] | 699 | mrb_check_num_exact(mrb, number);
|
---|
[270] | 700 |
|
---|
| 701 | f = 1.0;
|
---|
| 702 | i = ndigits >= 0 ? ndigits : -ndigits;
|
---|
[439] | 703 | if (ndigits > DBL_DIG+2) return num;
|
---|
[270] | 704 | while (--i >= 0)
|
---|
| 705 | f = f*10.0;
|
---|
| 706 |
|
---|
| 707 | if (isinf(f)) {
|
---|
| 708 | if (ndigits < 0) number = 0;
|
---|
| 709 | }
|
---|
| 710 | else {
|
---|
| 711 | double d;
|
---|
| 712 |
|
---|
| 713 | if (ndigits < 0) number /= f;
|
---|
| 714 | else number *= f;
|
---|
| 715 |
|
---|
| 716 | /* home-made inline implementation of round(3) */
|
---|
| 717 | if (number > 0.0) {
|
---|
| 718 | d = floor(number);
|
---|
| 719 | number = d + (number - d >= 0.5);
|
---|
| 720 | }
|
---|
| 721 | else if (number < 0.0) {
|
---|
| 722 | d = ceil(number);
|
---|
| 723 | number = d - (d - number >= 0.5);
|
---|
| 724 | }
|
---|
| 725 |
|
---|
| 726 | if (ndigits < 0) number *= f;
|
---|
| 727 | else number /= f;
|
---|
| 728 | }
|
---|
| 729 |
|
---|
| 730 | if (ndigits > 0) {
|
---|
| 731 | if (!isfinite(number)) return num;
|
---|
| 732 | return mrb_float_value(mrb, number);
|
---|
| 733 | }
|
---|
[439] | 734 | return mrb_int_value(mrb, number);
|
---|
[270] | 735 | }
|
---|
| 736 |
|
---|
| 737 | /* 15.2.9.3.14 */
|
---|
| 738 | /* 15.2.9.3.15 */
|
---|
| 739 | /*
|
---|
| 740 | * call-seq:
|
---|
| 741 | * flt.to_i -> integer
|
---|
| 742 | * flt.truncate -> integer
|
---|
| 743 | *
|
---|
| 744 | * Returns <i>flt</i> truncated to an <code>Integer</code>.
|
---|
| 745 | */
|
---|
| 746 |
|
---|
| 747 | static mrb_value
|
---|
| 748 | flo_truncate(mrb_state *mrb, mrb_value num)
|
---|
| 749 | {
|
---|
| 750 | mrb_float f = mrb_float(num);
|
---|
| 751 |
|
---|
| 752 | if (f > 0.0) f = floor(f);
|
---|
| 753 | if (f < 0.0) f = ceil(f);
|
---|
| 754 |
|
---|
[331] | 755 | mrb_check_num_exact(mrb, f);
|
---|
[439] | 756 | return mrb_int_value(mrb, f);
|
---|
[270] | 757 | }
|
---|
| 758 |
|
---|
| 759 | static mrb_value
|
---|
| 760 | flo_nan_p(mrb_state *mrb, mrb_value num)
|
---|
| 761 | {
|
---|
| 762 | return mrb_bool_value(isnan(mrb_float(num)));
|
---|
| 763 | }
|
---|
[439] | 764 | #endif
|
---|
[270] | 765 |
|
---|
| 766 | /*
|
---|
| 767 | * Document-class: Integer
|
---|
| 768 | *
|
---|
| 769 | * <code>Integer</code> is the basis for the two concrete classes that
|
---|
| 770 | * hold whole numbers, <code>Bignum</code> and <code>Fixnum</code>.
|
---|
| 771 | *
|
---|
| 772 | */
|
---|
| 773 |
|
---|
| 774 |
|
---|
| 775 | /*
|
---|
| 776 | * call-seq:
|
---|
| 777 | * int.to_i -> integer
|
---|
| 778 | *
|
---|
| 779 | * As <i>int</i> is already an <code>Integer</code>, all these
|
---|
| 780 | * methods simply return the receiver.
|
---|
| 781 | */
|
---|
| 782 |
|
---|
| 783 | static mrb_value
|
---|
| 784 | int_to_i(mrb_state *mrb, mrb_value num)
|
---|
| 785 | {
|
---|
| 786 | return num;
|
---|
| 787 | }
|
---|
| 788 |
|
---|
[439] | 789 | static mrb_value
|
---|
| 790 | fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
|
---|
[270] | 791 | {
|
---|
| 792 | mrb_int a;
|
---|
| 793 |
|
---|
| 794 | a = mrb_fixnum(x);
|
---|
| 795 | if (mrb_fixnum_p(y)) {
|
---|
[331] | 796 | mrb_int b, c;
|
---|
[270] | 797 |
|
---|
| 798 | if (a == 0) return x;
|
---|
| 799 | b = mrb_fixnum(y);
|
---|
[331] | 800 | if (mrb_int_mul_overflow(a, b, &c)) {
|
---|
[439] | 801 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[331] | 802 | return mrb_float_value(mrb, (mrb_float)a * (mrb_float)b);
|
---|
[439] | 803 | #endif
|
---|
[270] | 804 | }
|
---|
[331] | 805 | return mrb_fixnum_value(c);
|
---|
[270] | 806 | }
|
---|
[439] | 807 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 808 | mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
|
---|
| 809 | #else
|
---|
[270] | 810 | return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
|
---|
[439] | 811 | #endif
|
---|
[270] | 812 | }
|
---|
| 813 |
|
---|
[439] | 814 | MRB_API mrb_value
|
---|
| 815 | mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y)
|
---|
| 816 | {
|
---|
| 817 | if (mrb_fixnum_p(x)) {
|
---|
| 818 | return fixnum_mul(mrb, x, y);
|
---|
| 819 | }
|
---|
| 820 | #ifndef MRB_WITHOUT_FLOAT
|
---|
| 821 | if (mrb_float_p(x)) {
|
---|
| 822 | return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y));
|
---|
| 823 | }
|
---|
| 824 | #endif
|
---|
| 825 | mrb_raise(mrb, E_TYPE_ERROR, "no number multiply");
|
---|
| 826 | return mrb_nil_value(); /* not reached */
|
---|
| 827 | }
|
---|
| 828 |
|
---|
[270] | 829 | /* 15.2.8.3.3 */
|
---|
| 830 | /*
|
---|
| 831 | * call-seq:
|
---|
| 832 | * fix * numeric -> numeric_result
|
---|
| 833 | *
|
---|
| 834 | * Performs multiplication: the class of the resulting object depends on
|
---|
| 835 | * the class of <code>numeric</code> and on the magnitude of the
|
---|
| 836 | * result.
|
---|
| 837 | */
|
---|
| 838 |
|
---|
| 839 | static mrb_value
|
---|
| 840 | fix_mul(mrb_state *mrb, mrb_value x)
|
---|
| 841 | {
|
---|
| 842 | mrb_value y;
|
---|
| 843 |
|
---|
| 844 | mrb_get_args(mrb, "o", &y);
|
---|
[439] | 845 | return fixnum_mul(mrb, x, y);
|
---|
[270] | 846 | }
|
---|
| 847 |
|
---|
| 848 | static void
|
---|
| 849 | fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp)
|
---|
| 850 | {
|
---|
| 851 | mrb_int div, mod;
|
---|
| 852 |
|
---|
| 853 | /* TODO: add mrb_assert(y != 0) to make sure */
|
---|
| 854 |
|
---|
| 855 | if (y < 0) {
|
---|
| 856 | if (x < 0)
|
---|
| 857 | div = -x / -y;
|
---|
| 858 | else
|
---|
| 859 | div = - (x / -y);
|
---|
| 860 | }
|
---|
| 861 | else {
|
---|
| 862 | if (x < 0)
|
---|
| 863 | div = - (-x / y);
|
---|
| 864 | else
|
---|
| 865 | div = x / y;
|
---|
| 866 | }
|
---|
| 867 | mod = x - div*y;
|
---|
| 868 | if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) {
|
---|
| 869 | mod += y;
|
---|
| 870 | div -= 1;
|
---|
| 871 | }
|
---|
| 872 | if (divp) *divp = div;
|
---|
| 873 | if (modp) *modp = mod;
|
---|
| 874 | }
|
---|
| 875 |
|
---|
| 876 | /* 15.2.8.3.5 */
|
---|
| 877 | /*
|
---|
| 878 | * call-seq:
|
---|
| 879 | * fix % other -> real
|
---|
| 880 | * fix.modulo(other) -> real
|
---|
| 881 | *
|
---|
| 882 | * Returns <code>fix</code> modulo <code>other</code>.
|
---|
| 883 | * See <code>numeric.divmod</code> for more information.
|
---|
| 884 | */
|
---|
| 885 |
|
---|
| 886 | static mrb_value
|
---|
| 887 | fix_mod(mrb_state *mrb, mrb_value x)
|
---|
| 888 | {
|
---|
| 889 | mrb_value y;
|
---|
[439] | 890 | mrb_int a, b;
|
---|
[270] | 891 |
|
---|
| 892 | mrb_get_args(mrb, "o", &y);
|
---|
| 893 | a = mrb_fixnum(x);
|
---|
[439] | 894 | if (mrb_fixnum_p(y) && a != MRB_INT_MIN && (b=mrb_fixnum(y)) != MRB_INT_MIN) {
|
---|
| 895 | mrb_int mod;
|
---|
[270] | 896 |
|
---|
[439] | 897 | if (b == 0) {
|
---|
| 898 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 899 | /* ZeroDivisionError */
|
---|
| 900 | return mrb_fixnum_value(0);
|
---|
| 901 | #else
|
---|
| 902 | if (a > 0) return mrb_float_value(mrb, INFINITY);
|
---|
| 903 | if (a < 0) return mrb_float_value(mrb, INFINITY);
|
---|
[270] | 904 | return mrb_float_value(mrb, NAN);
|
---|
[439] | 905 | #endif
|
---|
[270] | 906 | }
|
---|
[439] | 907 | fixdivmod(mrb, a, b, NULL, &mod);
|
---|
[270] | 908 | return mrb_fixnum_value(mod);
|
---|
| 909 | }
|
---|
[439] | 910 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 911 | mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
|
---|
| 912 | #else
|
---|
[270] | 913 | else {
|
---|
| 914 | mrb_float mod;
|
---|
| 915 |
|
---|
[439] | 916 | flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), NULL, &mod);
|
---|
[270] | 917 | return mrb_float_value(mrb, mod);
|
---|
| 918 | }
|
---|
[439] | 919 | #endif
|
---|
[270] | 920 | }
|
---|
| 921 |
|
---|
| 922 | /*
|
---|
| 923 | * call-seq:
|
---|
| 924 | * fix.divmod(numeric) -> array
|
---|
| 925 | *
|
---|
| 926 | * See <code>Numeric#divmod</code>.
|
---|
| 927 | */
|
---|
| 928 | static mrb_value
|
---|
| 929 | fix_divmod(mrb_state *mrb, mrb_value x)
|
---|
| 930 | {
|
---|
| 931 | mrb_value y;
|
---|
| 932 |
|
---|
| 933 | mrb_get_args(mrb, "o", &y);
|
---|
| 934 |
|
---|
| 935 | if (mrb_fixnum_p(y)) {
|
---|
| 936 | mrb_int div, mod;
|
---|
| 937 |
|
---|
| 938 | if (mrb_fixnum(y) == 0) {
|
---|
[439] | 939 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 940 | return mrb_assoc_new(mrb, mrb_fixnum_value(0), mrb_fixnum_value(0));
|
---|
| 941 | #else
|
---|
| 942 | return mrb_assoc_new(mrb, ((mrb_fixnum(x) == 0) ?
|
---|
| 943 | mrb_float_value(mrb, NAN):
|
---|
| 944 | mrb_float_value(mrb, INFINITY)),
|
---|
| 945 | mrb_float_value(mrb, NAN));
|
---|
| 946 | #endif
|
---|
[270] | 947 | }
|
---|
| 948 | fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, &mod);
|
---|
| 949 | return mrb_assoc_new(mrb, mrb_fixnum_value(div), mrb_fixnum_value(mod));
|
---|
| 950 | }
|
---|
[439] | 951 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 952 | mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
|
---|
| 953 | #else
|
---|
[270] | 954 | else {
|
---|
| 955 | mrb_float div, mod;
|
---|
| 956 | mrb_value a, b;
|
---|
| 957 |
|
---|
| 958 | flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_to_flo(mrb, y), &div, &mod);
|
---|
[439] | 959 | a = mrb_int_value(mrb, div);
|
---|
[270] | 960 | b = mrb_float_value(mrb, mod);
|
---|
| 961 | return mrb_assoc_new(mrb, a, b);
|
---|
| 962 | }
|
---|
[439] | 963 | #endif
|
---|
[270] | 964 | }
|
---|
| 965 |
|
---|
[439] | 966 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[270] | 967 | static mrb_value
|
---|
| 968 | flo_divmod(mrb_state *mrb, mrb_value x)
|
---|
| 969 | {
|
---|
| 970 | mrb_value y;
|
---|
| 971 | mrb_float div, mod;
|
---|
| 972 | mrb_value a, b;
|
---|
| 973 |
|
---|
| 974 | mrb_get_args(mrb, "o", &y);
|
---|
| 975 |
|
---|
| 976 | flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod);
|
---|
[439] | 977 | a = mrb_int_value(mrb, div);
|
---|
[270] | 978 | b = mrb_float_value(mrb, mod);
|
---|
| 979 | return mrb_assoc_new(mrb, a, b);
|
---|
| 980 | }
|
---|
[439] | 981 | #endif
|
---|
[270] | 982 |
|
---|
| 983 | /* 15.2.8.3.7 */
|
---|
| 984 | /*
|
---|
| 985 | * call-seq:
|
---|
| 986 | * fix == other -> true or false
|
---|
| 987 | *
|
---|
| 988 | * Return <code>true</code> if <code>fix</code> equals <code>other</code>
|
---|
| 989 | * numerically.
|
---|
| 990 | *
|
---|
| 991 | * 1 == 2 #=> false
|
---|
| 992 | * 1 == 1.0 #=> true
|
---|
| 993 | */
|
---|
| 994 |
|
---|
| 995 | static mrb_value
|
---|
| 996 | fix_equal(mrb_state *mrb, mrb_value x)
|
---|
| 997 | {
|
---|
| 998 | mrb_value y;
|
---|
| 999 |
|
---|
| 1000 | mrb_get_args(mrb, "o", &y);
|
---|
| 1001 | switch (mrb_type(y)) {
|
---|
| 1002 | case MRB_TT_FIXNUM:
|
---|
| 1003 | return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y));
|
---|
[439] | 1004 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[270] | 1005 | case MRB_TT_FLOAT:
|
---|
| 1006 | return mrb_bool_value((mrb_float)mrb_fixnum(x) == mrb_float(y));
|
---|
[439] | 1007 | #endif
|
---|
[270] | 1008 | default:
|
---|
| 1009 | return mrb_false_value();
|
---|
| 1010 | }
|
---|
| 1011 | }
|
---|
| 1012 |
|
---|
| 1013 | /* 15.2.8.3.8 */
|
---|
| 1014 | /*
|
---|
| 1015 | * call-seq:
|
---|
| 1016 | * ~fix -> integer
|
---|
| 1017 | *
|
---|
| 1018 | * One's complement: returns a number where each bit is flipped.
|
---|
| 1019 | * ex.0---00001 (1)-> 1---11110 (-2)
|
---|
| 1020 | * ex.0---00010 (2)-> 1---11101 (-3)
|
---|
| 1021 | * ex.0---00100 (4)-> 1---11011 (-5)
|
---|
| 1022 | */
|
---|
| 1023 |
|
---|
| 1024 | static mrb_value
|
---|
| 1025 | fix_rev(mrb_state *mrb, mrb_value num)
|
---|
| 1026 | {
|
---|
| 1027 | mrb_int val = mrb_fixnum(num);
|
---|
| 1028 |
|
---|
| 1029 | return mrb_fixnum_value(~val);
|
---|
| 1030 | }
|
---|
| 1031 |
|
---|
[439] | 1032 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 1033 | #define bit_op(x,y,op1,op2) do {\
|
---|
| 1034 | return mrb_fixnum_value(mrb_fixnum(x) op2 mrb_fixnum(y));\
|
---|
| 1035 | } while(0)
|
---|
| 1036 | #else
|
---|
[331] | 1037 | static mrb_value flo_and(mrb_state *mrb, mrb_value x);
|
---|
| 1038 | static mrb_value flo_or(mrb_state *mrb, mrb_value x);
|
---|
| 1039 | static mrb_value flo_xor(mrb_state *mrb, mrb_value x);
|
---|
| 1040 | #define bit_op(x,y,op1,op2) do {\
|
---|
| 1041 | if (mrb_fixnum_p(y)) return mrb_fixnum_value(mrb_fixnum(x) op2 mrb_fixnum(y));\
|
---|
[439] | 1042 | return flo_ ## op1(mrb, mrb_float_value(mrb, (mrb_float)mrb_fixnum(x)));\
|
---|
[331] | 1043 | } while(0)
|
---|
[439] | 1044 | #endif
|
---|
[270] | 1045 |
|
---|
| 1046 | /* 15.2.8.3.9 */
|
---|
| 1047 | /*
|
---|
| 1048 | * call-seq:
|
---|
| 1049 | * fix & integer -> integer_result
|
---|
| 1050 | *
|
---|
| 1051 | * Bitwise AND.
|
---|
| 1052 | */
|
---|
| 1053 |
|
---|
| 1054 | static mrb_value
|
---|
| 1055 | fix_and(mrb_state *mrb, mrb_value x)
|
---|
| 1056 | {
|
---|
| 1057 | mrb_value y;
|
---|
| 1058 |
|
---|
| 1059 | mrb_get_args(mrb, "o", &y);
|
---|
[331] | 1060 | bit_op(x, y, and, &);
|
---|
[270] | 1061 | }
|
---|
| 1062 |
|
---|
| 1063 | /* 15.2.8.3.10 */
|
---|
| 1064 | /*
|
---|
| 1065 | * call-seq:
|
---|
| 1066 | * fix | integer -> integer_result
|
---|
| 1067 | *
|
---|
| 1068 | * Bitwise OR.
|
---|
| 1069 | */
|
---|
| 1070 |
|
---|
| 1071 | static mrb_value
|
---|
| 1072 | fix_or(mrb_state *mrb, mrb_value x)
|
---|
| 1073 | {
|
---|
| 1074 | mrb_value y;
|
---|
| 1075 |
|
---|
| 1076 | mrb_get_args(mrb, "o", &y);
|
---|
[331] | 1077 | bit_op(x, y, or, |);
|
---|
[270] | 1078 | }
|
---|
| 1079 |
|
---|
| 1080 | /* 15.2.8.3.11 */
|
---|
| 1081 | /*
|
---|
| 1082 | * call-seq:
|
---|
| 1083 | * fix ^ integer -> integer_result
|
---|
| 1084 | *
|
---|
| 1085 | * Bitwise EXCLUSIVE OR.
|
---|
| 1086 | */
|
---|
| 1087 |
|
---|
| 1088 | static mrb_value
|
---|
| 1089 | fix_xor(mrb_state *mrb, mrb_value x)
|
---|
| 1090 | {
|
---|
| 1091 | mrb_value y;
|
---|
| 1092 |
|
---|
| 1093 | mrb_get_args(mrb, "o", &y);
|
---|
[331] | 1094 | bit_op(x, y, or, ^);
|
---|
[270] | 1095 | }
|
---|
| 1096 |
|
---|
| 1097 | #define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1)
|
---|
| 1098 |
|
---|
| 1099 | static mrb_value
|
---|
| 1100 | lshift(mrb_state *mrb, mrb_int val, mrb_int width)
|
---|
| 1101 | {
|
---|
[331] | 1102 | if (width < 0) { /* mrb_int overflow */
|
---|
[439] | 1103 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 1104 | return mrb_fixnum_value(0);
|
---|
| 1105 | #else
|
---|
[331] | 1106 | return mrb_float_value(mrb, INFINITY);
|
---|
[439] | 1107 | #endif
|
---|
[331] | 1108 | }
|
---|
| 1109 | if (val > 0) {
|
---|
| 1110 | if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
|
---|
| 1111 | (val > (MRB_INT_MAX >> width))) {
|
---|
[439] | 1112 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 1113 | return mrb_fixnum_value(-1);
|
---|
| 1114 | #else
|
---|
[331] | 1115 | goto bit_overflow;
|
---|
[439] | 1116 | #endif
|
---|
[331] | 1117 | }
|
---|
[439] | 1118 | return mrb_fixnum_value(val << width);
|
---|
[331] | 1119 | }
|
---|
| 1120 | else {
|
---|
| 1121 | if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
|
---|
[439] | 1122 | (val <= (MRB_INT_MIN >> width))) {
|
---|
| 1123 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 1124 | return mrb_fixnum_value(0);
|
---|
| 1125 | #else
|
---|
[331] | 1126 | goto bit_overflow;
|
---|
[439] | 1127 | #endif
|
---|
[331] | 1128 | }
|
---|
[439] | 1129 | return mrb_fixnum_value(val * ((mrb_int)1 << width));
|
---|
[331] | 1130 | }
|
---|
| 1131 |
|
---|
[439] | 1132 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[331] | 1133 | bit_overflow:
|
---|
| 1134 | {
|
---|
[270] | 1135 | mrb_float f = (mrb_float)val;
|
---|
| 1136 | while (width--) {
|
---|
| 1137 | f *= 2;
|
---|
| 1138 | }
|
---|
| 1139 | return mrb_float_value(mrb, f);
|
---|
| 1140 | }
|
---|
[439] | 1141 | #endif
|
---|
[270] | 1142 | }
|
---|
| 1143 |
|
---|
| 1144 | static mrb_value
|
---|
| 1145 | rshift(mrb_int val, mrb_int width)
|
---|
| 1146 | {
|
---|
[331] | 1147 | if (width < 0) { /* mrb_int overflow */
|
---|
| 1148 | return mrb_fixnum_value(0);
|
---|
| 1149 | }
|
---|
[270] | 1150 | if (width >= NUMERIC_SHIFT_WIDTH_MAX) {
|
---|
| 1151 | if (val < 0) {
|
---|
| 1152 | return mrb_fixnum_value(-1);
|
---|
| 1153 | }
|
---|
| 1154 | return mrb_fixnum_value(0);
|
---|
| 1155 | }
|
---|
| 1156 | return mrb_fixnum_value(val >> width);
|
---|
| 1157 | }
|
---|
| 1158 |
|
---|
| 1159 | /* 15.2.8.3.12 */
|
---|
| 1160 | /*
|
---|
| 1161 | * call-seq:
|
---|
| 1162 | * fix << count -> integer or float
|
---|
| 1163 | *
|
---|
| 1164 | * Shifts _fix_ left _count_ positions (right if _count_ is negative).
|
---|
| 1165 | */
|
---|
| 1166 |
|
---|
| 1167 | static mrb_value
|
---|
| 1168 | fix_lshift(mrb_state *mrb, mrb_value x)
|
---|
| 1169 | {
|
---|
| 1170 | mrb_int width, val;
|
---|
| 1171 |
|
---|
[331] | 1172 | mrb_get_args(mrb, "i", &width);
|
---|
[270] | 1173 | if (width == 0) {
|
---|
| 1174 | return x;
|
---|
| 1175 | }
|
---|
| 1176 | val = mrb_fixnum(x);
|
---|
[331] | 1177 | if (val == 0) return x;
|
---|
[270] | 1178 | if (width < 0) {
|
---|
| 1179 | return rshift(val, -width);
|
---|
| 1180 | }
|
---|
| 1181 | return lshift(mrb, val, width);
|
---|
| 1182 | }
|
---|
| 1183 |
|
---|
| 1184 | /* 15.2.8.3.13 */
|
---|
| 1185 | /*
|
---|
| 1186 | * call-seq:
|
---|
| 1187 | * fix >> count -> integer or float
|
---|
| 1188 | *
|
---|
| 1189 | * Shifts _fix_ right _count_ positions (left if _count_ is negative).
|
---|
| 1190 | */
|
---|
| 1191 |
|
---|
| 1192 | static mrb_value
|
---|
| 1193 | fix_rshift(mrb_state *mrb, mrb_value x)
|
---|
| 1194 | {
|
---|
| 1195 | mrb_int width, val;
|
---|
| 1196 |
|
---|
[331] | 1197 | mrb_get_args(mrb, "i", &width);
|
---|
[270] | 1198 | if (width == 0) {
|
---|
| 1199 | return x;
|
---|
| 1200 | }
|
---|
| 1201 | val = mrb_fixnum(x);
|
---|
[331] | 1202 | if (val == 0) return x;
|
---|
[270] | 1203 | if (width < 0) {
|
---|
| 1204 | return lshift(mrb, val, -width);
|
---|
| 1205 | }
|
---|
| 1206 | return rshift(val, width);
|
---|
| 1207 | }
|
---|
| 1208 |
|
---|
| 1209 | /* 15.2.8.3.23 */
|
---|
| 1210 | /*
|
---|
| 1211 | * call-seq:
|
---|
| 1212 | * fix.to_f -> float
|
---|
| 1213 | *
|
---|
| 1214 | * Converts <i>fix</i> to a <code>Float</code>.
|
---|
| 1215 | *
|
---|
| 1216 | */
|
---|
| 1217 |
|
---|
[439] | 1218 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[270] | 1219 | static mrb_value
|
---|
| 1220 | fix_to_f(mrb_state *mrb, mrb_value num)
|
---|
| 1221 | {
|
---|
| 1222 | return mrb_float_value(mrb, (mrb_float)mrb_fixnum(num));
|
---|
| 1223 | }
|
---|
| 1224 |
|
---|
| 1225 | /*
|
---|
| 1226 | * Document-class: FloatDomainError
|
---|
| 1227 | *
|
---|
| 1228 | * Raised when attempting to convert special float values
|
---|
| 1229 | * (in particular infinite or NaN)
|
---|
| 1230 | * to numerical classes which don't support them.
|
---|
| 1231 | *
|
---|
[439] | 1232 | * Float::INFINITY.to_i
|
---|
[270] | 1233 | *
|
---|
| 1234 | * <em>raises the exception:</em>
|
---|
| 1235 | *
|
---|
| 1236 | * FloatDomainError: Infinity
|
---|
| 1237 | */
|
---|
| 1238 | /* ------------------------------------------------------------------------*/
|
---|
| 1239 | MRB_API mrb_value
|
---|
| 1240 | mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
|
---|
| 1241 | {
|
---|
[331] | 1242 | mrb_int z = 0;
|
---|
[270] | 1243 |
|
---|
| 1244 | if (!mrb_float_p(x)) {
|
---|
| 1245 | mrb_raise(mrb, E_TYPE_ERROR, "non float value");
|
---|
| 1246 | z = 0; /* not reached. just suppress warnings. */
|
---|
| 1247 | }
|
---|
| 1248 | else {
|
---|
| 1249 | mrb_float d = mrb_float(x);
|
---|
| 1250 |
|
---|
[439] | 1251 | mrb_check_num_exact(mrb, d);
|
---|
[331] | 1252 | if (FIXABLE_FLOAT(d)) {
|
---|
| 1253 | z = (mrb_int)d;
|
---|
| 1254 | }
|
---|
| 1255 | else {
|
---|
[439] | 1256 | mrb_raisef(mrb, E_RANGE_ERROR, "number (%v) too big for integer", x);
|
---|
[331] | 1257 | }
|
---|
[270] | 1258 | }
|
---|
| 1259 | return mrb_fixnum_value(z);
|
---|
| 1260 | }
|
---|
[439] | 1261 | #endif
|
---|
[270] | 1262 |
|
---|
[439] | 1263 | static mrb_value
|
---|
| 1264 | fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y)
|
---|
[270] | 1265 | {
|
---|
| 1266 | mrb_int a;
|
---|
| 1267 |
|
---|
| 1268 | a = mrb_fixnum(x);
|
---|
| 1269 | if (mrb_fixnum_p(y)) {
|
---|
| 1270 | mrb_int b, c;
|
---|
| 1271 |
|
---|
| 1272 | if (a == 0) return y;
|
---|
| 1273 | b = mrb_fixnum(y);
|
---|
| 1274 | if (mrb_int_add_overflow(a, b, &c)) {
|
---|
[439] | 1275 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[270] | 1276 | return mrb_float_value(mrb, (mrb_float)a + (mrb_float)b);
|
---|
[439] | 1277 | #endif
|
---|
[270] | 1278 | }
|
---|
| 1279 | return mrb_fixnum_value(c);
|
---|
| 1280 | }
|
---|
[439] | 1281 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 1282 | mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
|
---|
| 1283 | #else
|
---|
[270] | 1284 | return mrb_float_value(mrb, (mrb_float)a + mrb_to_flo(mrb, y));
|
---|
[439] | 1285 | #endif
|
---|
[270] | 1286 | }
|
---|
| 1287 |
|
---|
[439] | 1288 | MRB_API mrb_value
|
---|
| 1289 | mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y)
|
---|
| 1290 | {
|
---|
| 1291 | if (mrb_fixnum_p(x)) {
|
---|
| 1292 | return fixnum_plus(mrb, x, y);
|
---|
| 1293 | }
|
---|
| 1294 | #ifndef MRB_WITHOUT_FLOAT
|
---|
| 1295 | if (mrb_float_p(x)) {
|
---|
| 1296 | return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y));
|
---|
| 1297 | }
|
---|
| 1298 | #endif
|
---|
| 1299 | mrb_raise(mrb, E_TYPE_ERROR, "no number addition");
|
---|
| 1300 | return mrb_nil_value(); /* not reached */
|
---|
| 1301 | }
|
---|
| 1302 |
|
---|
[270] | 1303 | /* 15.2.8.3.1 */
|
---|
| 1304 | /*
|
---|
| 1305 | * call-seq:
|
---|
| 1306 | * fix + numeric -> numeric_result
|
---|
| 1307 | *
|
---|
| 1308 | * Performs addition: the class of the resulting object depends on
|
---|
| 1309 | * the class of <code>numeric</code> and on the magnitude of the
|
---|
| 1310 | * result.
|
---|
| 1311 | */
|
---|
| 1312 | static mrb_value
|
---|
| 1313 | fix_plus(mrb_state *mrb, mrb_value self)
|
---|
| 1314 | {
|
---|
| 1315 | mrb_value other;
|
---|
| 1316 |
|
---|
| 1317 | mrb_get_args(mrb, "o", &other);
|
---|
[439] | 1318 | return fixnum_plus(mrb, self, other);
|
---|
[270] | 1319 | }
|
---|
| 1320 |
|
---|
[439] | 1321 | static mrb_value
|
---|
| 1322 | fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y)
|
---|
[270] | 1323 | {
|
---|
| 1324 | mrb_int a;
|
---|
| 1325 |
|
---|
| 1326 | a = mrb_fixnum(x);
|
---|
| 1327 | if (mrb_fixnum_p(y)) {
|
---|
| 1328 | mrb_int b, c;
|
---|
| 1329 |
|
---|
| 1330 | b = mrb_fixnum(y);
|
---|
| 1331 | if (mrb_int_sub_overflow(a, b, &c)) {
|
---|
[439] | 1332 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[270] | 1333 | return mrb_float_value(mrb, (mrb_float)a - (mrb_float)b);
|
---|
[439] | 1334 | #endif
|
---|
[270] | 1335 | }
|
---|
| 1336 | return mrb_fixnum_value(c);
|
---|
| 1337 | }
|
---|
[439] | 1338 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 1339 | mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
|
---|
| 1340 | #else
|
---|
[270] | 1341 | return mrb_float_value(mrb, (mrb_float)a - mrb_to_flo(mrb, y));
|
---|
[439] | 1342 | #endif
|
---|
[270] | 1343 | }
|
---|
| 1344 |
|
---|
[439] | 1345 | MRB_API mrb_value
|
---|
| 1346 | mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y)
|
---|
| 1347 | {
|
---|
| 1348 | if (mrb_fixnum_p(x)) {
|
---|
| 1349 | return fixnum_minus(mrb, x, y);
|
---|
| 1350 | }
|
---|
| 1351 | #ifndef MRB_WITHOUT_FLOAT
|
---|
| 1352 | if (mrb_float_p(x)) {
|
---|
| 1353 | return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y));
|
---|
| 1354 | }
|
---|
| 1355 | #endif
|
---|
| 1356 | mrb_raise(mrb, E_TYPE_ERROR, "no number subtraction");
|
---|
| 1357 | return mrb_nil_value(); /* not reached */
|
---|
| 1358 | }
|
---|
| 1359 |
|
---|
[270] | 1360 | /* 15.2.8.3.2 */
|
---|
| 1361 | /* 15.2.8.3.16 */
|
---|
| 1362 | /*
|
---|
| 1363 | * call-seq:
|
---|
| 1364 | * fix - numeric -> numeric_result
|
---|
| 1365 | *
|
---|
| 1366 | * Performs subtraction: the class of the resulting object depends on
|
---|
| 1367 | * the class of <code>numeric</code> and on the magnitude of the
|
---|
| 1368 | * result.
|
---|
| 1369 | */
|
---|
| 1370 | static mrb_value
|
---|
| 1371 | fix_minus(mrb_state *mrb, mrb_value self)
|
---|
| 1372 | {
|
---|
| 1373 | mrb_value other;
|
---|
| 1374 |
|
---|
| 1375 | mrb_get_args(mrb, "o", &other);
|
---|
[439] | 1376 | return fixnum_minus(mrb, self, other);
|
---|
[270] | 1377 | }
|
---|
| 1378 |
|
---|
| 1379 |
|
---|
| 1380 | MRB_API mrb_value
|
---|
[439] | 1381 | mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
|
---|
[270] | 1382 | {
|
---|
| 1383 | char buf[MRB_INT_BIT+1];
|
---|
| 1384 | char *b = buf + sizeof buf;
|
---|
| 1385 | mrb_int val = mrb_fixnum(x);
|
---|
| 1386 |
|
---|
| 1387 | if (base < 2 || 36 < base) {
|
---|
[439] | 1388 | mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base);
|
---|
[270] | 1389 | }
|
---|
| 1390 |
|
---|
| 1391 | if (val == 0) {
|
---|
| 1392 | *--b = '0';
|
---|
| 1393 | }
|
---|
| 1394 | else if (val < 0) {
|
---|
| 1395 | do {
|
---|
| 1396 | *--b = mrb_digitmap[-(val % base)];
|
---|
| 1397 | } while (val /= base);
|
---|
| 1398 | *--b = '-';
|
---|
| 1399 | }
|
---|
| 1400 | else {
|
---|
| 1401 | do {
|
---|
| 1402 | *--b = mrb_digitmap[(int)(val % base)];
|
---|
| 1403 | } while (val /= base);
|
---|
| 1404 | }
|
---|
| 1405 |
|
---|
| 1406 | return mrb_str_new(mrb, b, buf + sizeof(buf) - b);
|
---|
| 1407 | }
|
---|
| 1408 |
|
---|
| 1409 | /* 15.2.8.3.25 */
|
---|
| 1410 | /*
|
---|
| 1411 | * call-seq:
|
---|
| 1412 | * fix.to_s(base=10) -> string
|
---|
| 1413 | *
|
---|
| 1414 | * Returns a string containing the representation of <i>fix</i> radix
|
---|
| 1415 | * <i>base</i> (between 2 and 36).
|
---|
| 1416 | *
|
---|
| 1417 | * 12345.to_s #=> "12345"
|
---|
| 1418 | * 12345.to_s(2) #=> "11000000111001"
|
---|
| 1419 | * 12345.to_s(8) #=> "30071"
|
---|
| 1420 | * 12345.to_s(10) #=> "12345"
|
---|
| 1421 | * 12345.to_s(16) #=> "3039"
|
---|
| 1422 | * 12345.to_s(36) #=> "9ix"
|
---|
| 1423 | *
|
---|
| 1424 | */
|
---|
| 1425 | static mrb_value
|
---|
| 1426 | fix_to_s(mrb_state *mrb, mrb_value self)
|
---|
| 1427 | {
|
---|
| 1428 | mrb_int base = 10;
|
---|
| 1429 |
|
---|
| 1430 | mrb_get_args(mrb, "|i", &base);
|
---|
| 1431 | return mrb_fixnum_to_str(mrb, self, base);
|
---|
| 1432 | }
|
---|
| 1433 |
|
---|
[439] | 1434 | /* compare two numbers: (1:0:-1; -2 for error) */
|
---|
| 1435 | static mrb_int
|
---|
| 1436 | cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2)
|
---|
| 1437 | {
|
---|
| 1438 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 1439 | mrb_int x, y;
|
---|
| 1440 | #else
|
---|
| 1441 | mrb_float x, y;
|
---|
| 1442 | #endif
|
---|
| 1443 |
|
---|
| 1444 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 1445 | x = mrb_fixnum(v1);
|
---|
| 1446 | #else
|
---|
| 1447 | x = mrb_to_flo(mrb, v1);
|
---|
| 1448 | #endif
|
---|
| 1449 | switch (mrb_type(v2)) {
|
---|
| 1450 | case MRB_TT_FIXNUM:
|
---|
| 1451 | #ifdef MRB_WITHOUT_FLOAT
|
---|
| 1452 | y = mrb_fixnum(v2);
|
---|
| 1453 | #else
|
---|
| 1454 | y = (mrb_float)mrb_fixnum(v2);
|
---|
| 1455 | #endif
|
---|
| 1456 | break;
|
---|
| 1457 | #ifndef MRB_WITHOUT_FLOAT
|
---|
| 1458 | case MRB_TT_FLOAT:
|
---|
| 1459 | y = mrb_float(v2);
|
---|
| 1460 | break;
|
---|
| 1461 | #endif
|
---|
| 1462 | default:
|
---|
| 1463 | return -2;
|
---|
| 1464 | }
|
---|
| 1465 | if (x > y)
|
---|
| 1466 | return 1;
|
---|
| 1467 | else {
|
---|
| 1468 | if (x < y)
|
---|
| 1469 | return -1;
|
---|
| 1470 | return 0;
|
---|
| 1471 | }
|
---|
| 1472 | }
|
---|
| 1473 |
|
---|
[270] | 1474 | /* 15.2.9.3.6 */
|
---|
| 1475 | /*
|
---|
| 1476 | * call-seq:
|
---|
| 1477 | * self.f <=> other.f => -1, 0, +1
|
---|
| 1478 | * < => -1
|
---|
| 1479 | * = => 0
|
---|
| 1480 | * > => +1
|
---|
| 1481 | * Comparison---Returns -1, 0, or +1 depending on whether <i>fix</i> is
|
---|
| 1482 | * less than, equal to, or greater than <i>numeric</i>. This is the
|
---|
| 1483 | * basis for the tests in <code>Comparable</code>.
|
---|
| 1484 | */
|
---|
| 1485 | static mrb_value
|
---|
[439] | 1486 | integral_cmp(mrb_state *mrb, mrb_value self)
|
---|
[270] | 1487 | {
|
---|
| 1488 | mrb_value other;
|
---|
[439] | 1489 | mrb_int n;
|
---|
[270] | 1490 |
|
---|
| 1491 | mrb_get_args(mrb, "o", &other);
|
---|
[439] | 1492 | n = cmpnum(mrb, self, other);
|
---|
| 1493 | if (n == -2) return mrb_nil_value();
|
---|
| 1494 | return mrb_fixnum_value(n);
|
---|
| 1495 | }
|
---|
[270] | 1496 |
|
---|
[439] | 1497 | static mrb_noreturn void
|
---|
| 1498 | cmperr(mrb_state *mrb, mrb_value v1, mrb_value v2)
|
---|
| 1499 | {
|
---|
| 1500 | mrb_raisef(mrb, E_ARGUMENT_ERROR, "comparison of %t with %t failed", v1, v2);
|
---|
| 1501 | }
|
---|
| 1502 |
|
---|
| 1503 | static mrb_value
|
---|
| 1504 | integral_lt(mrb_state *mrb, mrb_value self)
|
---|
| 1505 | {
|
---|
| 1506 | mrb_value other;
|
---|
| 1507 | mrb_int n;
|
---|
| 1508 |
|
---|
| 1509 | mrb_get_args(mrb, "o", &other);
|
---|
| 1510 | n = cmpnum(mrb, self, other);
|
---|
| 1511 | if (n == -2) cmperr(mrb, self, other);
|
---|
| 1512 | if (n < 0) return mrb_true_value();
|
---|
| 1513 | return mrb_false_value();
|
---|
| 1514 | }
|
---|
| 1515 |
|
---|
| 1516 | static mrb_value
|
---|
| 1517 | integral_le(mrb_state *mrb, mrb_value self)
|
---|
| 1518 | {
|
---|
| 1519 | mrb_value other;
|
---|
| 1520 | mrb_int n;
|
---|
| 1521 |
|
---|
| 1522 | mrb_get_args(mrb, "o", &other);
|
---|
| 1523 | n = cmpnum(mrb, self, other);
|
---|
| 1524 | if (n == -2) cmperr(mrb, self, other);
|
---|
| 1525 | if (n <= 0) return mrb_true_value();
|
---|
| 1526 | return mrb_false_value();
|
---|
| 1527 | }
|
---|
| 1528 |
|
---|
| 1529 | static mrb_value
|
---|
| 1530 | integral_gt(mrb_state *mrb, mrb_value self)
|
---|
| 1531 | {
|
---|
| 1532 | mrb_value other;
|
---|
| 1533 | mrb_int n;
|
---|
| 1534 |
|
---|
| 1535 | mrb_get_args(mrb, "o", &other);
|
---|
| 1536 | n = cmpnum(mrb, self, other);
|
---|
| 1537 | if (n == -2) cmperr(mrb, self, other);
|
---|
| 1538 | if (n > 0) return mrb_true_value();
|
---|
| 1539 | return mrb_false_value();
|
---|
| 1540 | }
|
---|
| 1541 |
|
---|
| 1542 | static mrb_value
|
---|
| 1543 | integral_ge(mrb_state *mrb, mrb_value self)
|
---|
| 1544 | {
|
---|
| 1545 | mrb_value other;
|
---|
| 1546 | mrb_int n;
|
---|
| 1547 |
|
---|
| 1548 | mrb_get_args(mrb, "o", &other);
|
---|
| 1549 | n = cmpnum(mrb, self, other);
|
---|
| 1550 | if (n == -2) cmperr(mrb, self, other);
|
---|
| 1551 | if (n >= 0) return mrb_true_value();
|
---|
| 1552 | return mrb_false_value();
|
---|
| 1553 | }
|
---|
| 1554 |
|
---|
| 1555 | MRB_API mrb_int
|
---|
| 1556 | mrb_cmp(mrb_state *mrb, mrb_value obj1, mrb_value obj2)
|
---|
| 1557 | {
|
---|
| 1558 | mrb_value v;
|
---|
| 1559 |
|
---|
| 1560 | switch (mrb_type(obj1)) {
|
---|
[270] | 1561 | case MRB_TT_FIXNUM:
|
---|
| 1562 | case MRB_TT_FLOAT:
|
---|
[439] | 1563 | return cmpnum(mrb, obj1, obj2);
|
---|
| 1564 | case MRB_TT_STRING:
|
---|
| 1565 | if (!mrb_string_p(obj2))
|
---|
| 1566 | return -2;
|
---|
| 1567 | return mrb_str_cmp(mrb, obj1, obj2);
|
---|
[270] | 1568 | default:
|
---|
[439] | 1569 | v = mrb_funcall(mrb, obj1, "<=>", 1, obj2);
|
---|
| 1570 | if (mrb_nil_p(v) || !mrb_fixnum_p(v))
|
---|
| 1571 | return -2;
|
---|
| 1572 | return mrb_fixnum(v);
|
---|
[270] | 1573 | }
|
---|
| 1574 | }
|
---|
| 1575 |
|
---|
[439] | 1576 | static mrb_value
|
---|
| 1577 | num_finite_p(mrb_state *mrb, mrb_value self)
|
---|
| 1578 | {
|
---|
| 1579 | return mrb_true_value();
|
---|
| 1580 | }
|
---|
| 1581 |
|
---|
| 1582 | static mrb_value
|
---|
| 1583 | num_infinite_p(mrb_state *mrb, mrb_value self)
|
---|
| 1584 | {
|
---|
| 1585 | return mrb_false_value();
|
---|
| 1586 | }
|
---|
| 1587 |
|
---|
[270] | 1588 | /* 15.2.9.3.1 */
|
---|
| 1589 | /*
|
---|
| 1590 | * call-seq:
|
---|
| 1591 | * float + other -> float
|
---|
| 1592 | *
|
---|
| 1593 | * Returns a new float which is the sum of <code>float</code>
|
---|
| 1594 | * and <code>other</code>.
|
---|
| 1595 | */
|
---|
[439] | 1596 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[270] | 1597 | static mrb_value
|
---|
| 1598 | flo_plus(mrb_state *mrb, mrb_value x)
|
---|
| 1599 | {
|
---|
| 1600 | mrb_value y;
|
---|
| 1601 |
|
---|
| 1602 | mrb_get_args(mrb, "o", &y);
|
---|
| 1603 | return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y));
|
---|
| 1604 | }
|
---|
[439] | 1605 | #endif
|
---|
[270] | 1606 |
|
---|
| 1607 | /* ------------------------------------------------------------------------*/
|
---|
| 1608 | void
|
---|
| 1609 | mrb_init_numeric(mrb_state *mrb)
|
---|
| 1610 | {
|
---|
[439] | 1611 | struct RClass *numeric, *integer, *fixnum, *integral;
|
---|
| 1612 | #ifndef MRB_WITHOUT_FLOAT
|
---|
| 1613 | struct RClass *fl;
|
---|
| 1614 | #endif
|
---|
[270] | 1615 |
|
---|
[439] | 1616 | integral = mrb_define_module(mrb, "Integral");
|
---|
| 1617 | mrb_define_method(mrb, integral,"**", integral_pow, MRB_ARGS_REQ(1));
|
---|
| 1618 | mrb_define_method(mrb, integral,"/", integral_div, MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.6 */
|
---|
| 1619 | mrb_define_method(mrb, integral,"quo", integral_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */
|
---|
| 1620 | mrb_define_method(mrb, integral,"div", integral_idiv, MRB_ARGS_REQ(1));
|
---|
| 1621 | mrb_define_method(mrb, integral,"<=>", integral_cmp, MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.1 */
|
---|
| 1622 | mrb_define_method(mrb, integral,"<", integral_lt, MRB_ARGS_REQ(1));
|
---|
| 1623 | mrb_define_method(mrb, integral,"<=", integral_le, MRB_ARGS_REQ(1));
|
---|
| 1624 | mrb_define_method(mrb, integral,">", integral_gt, MRB_ARGS_REQ(1));
|
---|
| 1625 | mrb_define_method(mrb, integral,">=", integral_ge, MRB_ARGS_REQ(1));
|
---|
| 1626 | mrb_define_method(mrb, integral,"__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2));
|
---|
| 1627 |
|
---|
[270] | 1628 | /* Numeric Class */
|
---|
| 1629 | numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */
|
---|
[439] | 1630 | mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE());
|
---|
| 1631 | mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE());
|
---|
[270] | 1632 |
|
---|
| 1633 | /* Integer Class */
|
---|
| 1634 | integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */
|
---|
[331] | 1635 | MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM);
|
---|
[270] | 1636 | mrb_undef_class_method(mrb, integer, "new");
|
---|
[331] | 1637 | mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */
|
---|
| 1638 | mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE());
|
---|
[439] | 1639 | #ifndef MRB_WITHOUT_FLOAT
|
---|
| 1640 | mrb_define_method(mrb, integer, "ceil", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.8 (x) */
|
---|
| 1641 | mrb_define_method(mrb, integer, "floor", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.10 (x) */
|
---|
| 1642 | mrb_define_method(mrb, integer, "round", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.12 (x) */
|
---|
| 1643 | mrb_define_method(mrb, integer, "truncate", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.15 (x) */
|
---|
| 1644 | #endif
|
---|
[270] | 1645 |
|
---|
| 1646 | /* Fixnum Class */
|
---|
| 1647 | mrb->fixnum_class = fixnum = mrb_define_class(mrb, "Fixnum", integer);
|
---|
[331] | 1648 | mrb_define_method(mrb, fixnum, "+", fix_plus, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
|
---|
| 1649 | mrb_define_method(mrb, fixnum, "-", fix_minus, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */
|
---|
| 1650 | mrb_define_method(mrb, fixnum, "*", fix_mul, MRB_ARGS_REQ(1)); /* 15.2.8.3.3 */
|
---|
| 1651 | mrb_define_method(mrb, fixnum, "%", fix_mod, MRB_ARGS_REQ(1)); /* 15.2.8.3.5 */
|
---|
| 1652 | mrb_define_method(mrb, fixnum, "==", fix_equal, MRB_ARGS_REQ(1)); /* 15.2.8.3.7 */
|
---|
| 1653 | mrb_define_method(mrb, fixnum, "~", fix_rev, MRB_ARGS_NONE()); /* 15.2.8.3.8 */
|
---|
| 1654 | mrb_define_method(mrb, fixnum, "&", fix_and, MRB_ARGS_REQ(1)); /* 15.2.8.3.9 */
|
---|
| 1655 | mrb_define_method(mrb, fixnum, "|", fix_or, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 */
|
---|
| 1656 | mrb_define_method(mrb, fixnum, "^", fix_xor, MRB_ARGS_REQ(1)); /* 15.2.8.3.11 */
|
---|
| 1657 | mrb_define_method(mrb, fixnum, "<<", fix_lshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.12 */
|
---|
| 1658 | mrb_define_method(mrb, fixnum, ">>", fix_rshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.13 */
|
---|
| 1659 | mrb_define_method(mrb, fixnum, "eql?", fix_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
|
---|
[439] | 1660 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[331] | 1661 | mrb_define_method(mrb, fixnum, "to_f", fix_to_f, MRB_ARGS_NONE()); /* 15.2.8.3.23 */
|
---|
[439] | 1662 | #endif
|
---|
| 1663 | mrb_define_method(mrb, fixnum, "to_s", fix_to_s, MRB_ARGS_OPT(1)); /* 15.2.8.3.25 */
|
---|
| 1664 | mrb_define_method(mrb, fixnum, "inspect", fix_to_s, MRB_ARGS_OPT(1));
|
---|
[331] | 1665 | mrb_define_method(mrb, fixnum, "divmod", fix_divmod, MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */
|
---|
[270] | 1666 |
|
---|
[439] | 1667 | #ifndef MRB_WITHOUT_FLOAT
|
---|
[270] | 1668 | /* Float Class */
|
---|
| 1669 | mrb->float_class = fl = mrb_define_class(mrb, "Float", numeric); /* 15.2.9 */
|
---|
[331] | 1670 | MRB_SET_INSTANCE_TT(fl, MRB_TT_FLOAT);
|
---|
[270] | 1671 | mrb_undef_class_method(mrb, fl, "new");
|
---|
[331] | 1672 | mrb_define_method(mrb, fl, "+", flo_plus, MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */
|
---|
| 1673 | mrb_define_method(mrb, fl, "-", flo_minus, MRB_ARGS_REQ(1)); /* 15.2.9.3.2 */
|
---|
| 1674 | mrb_define_method(mrb, fl, "*", flo_mul, MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */
|
---|
| 1675 | mrb_define_method(mrb, fl, "%", flo_mod, MRB_ARGS_REQ(1)); /* 15.2.9.3.5 */
|
---|
| 1676 | mrb_define_method(mrb, fl, "==", flo_eq, MRB_ARGS_REQ(1)); /* 15.2.9.3.7 */
|
---|
| 1677 | mrb_define_method(mrb, fl, "~", flo_rev, MRB_ARGS_NONE());
|
---|
| 1678 | mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1));
|
---|
| 1679 | mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1));
|
---|
| 1680 | mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1));
|
---|
[439] | 1681 | mrb_define_method(mrb, fl, ">>", flo_rshift, MRB_ARGS_REQ(1));
|
---|
| 1682 | mrb_define_method(mrb, fl, "<<", flo_lshift, MRB_ARGS_REQ(1));
|
---|
[331] | 1683 | mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */
|
---|
| 1684 | mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */
|
---|
| 1685 | mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */
|
---|
| 1686 | mrb_define_method(mrb, fl, "infinite?", flo_infinite_p, MRB_ARGS_NONE()); /* 15.2.9.3.11 */
|
---|
| 1687 | mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */
|
---|
| 1688 | mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */
|
---|
| 1689 | mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */
|
---|
| 1690 | mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE());
|
---|
| 1691 | mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */
|
---|
| 1692 | mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1));
|
---|
| 1693 | mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
|
---|
[270] | 1694 |
|
---|
[331] | 1695 | mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */
|
---|
| 1696 | mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE());
|
---|
| 1697 | mrb_define_method(mrb, fl, "nan?", flo_nan_p, MRB_ARGS_NONE());
|
---|
[270] | 1698 |
|
---|
| 1699 | #ifdef INFINITY
|
---|
| 1700 | mrb_define_const(mrb, fl, "INFINITY", mrb_float_value(mrb, INFINITY));
|
---|
| 1701 | #endif
|
---|
| 1702 | #ifdef NAN
|
---|
| 1703 | mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN));
|
---|
| 1704 | #endif
|
---|
[439] | 1705 |
|
---|
| 1706 | mrb_include_module(mrb, fl, integral);
|
---|
| 1707 | #endif
|
---|
[270] | 1708 | }
|
---|