1 | /*
|
---|
2 | ** numeric.c - Numeric, Integer, Float, Fixnum class
|
---|
3 | **
|
---|
4 | ** See Copyright Notice in mruby.h
|
---|
5 | */
|
---|
6 |
|
---|
7 | #ifndef MRB_WITHOUT_FLOAT
|
---|
8 | #include <float.h>
|
---|
9 | #include <math.h>
|
---|
10 | #endif
|
---|
11 | #include <limits.h>
|
---|
12 | #include <stdlib.h>
|
---|
13 | #include <string.h>
|
---|
14 |
|
---|
15 | #include <mruby.h>
|
---|
16 | #include <mruby/array.h>
|
---|
17 | #include <mruby/numeric.h>
|
---|
18 | #include <mruby/string.h>
|
---|
19 | #include <mruby/class.h>
|
---|
20 |
|
---|
21 | #ifndef MRB_WITHOUT_FLOAT
|
---|
22 | #ifdef MRB_USE_FLOAT
|
---|
23 | #define trunc(f) truncf(f)
|
---|
24 | #define floor(f) floorf(f)
|
---|
25 | #define ceil(f) ceilf(f)
|
---|
26 | #define fmod(x,y) fmodf(x,y)
|
---|
27 | #define FLO_TO_STR_PREC 8
|
---|
28 | #else
|
---|
29 | #define FLO_TO_STR_PREC 16
|
---|
30 | #endif
|
---|
31 | #endif
|
---|
32 |
|
---|
33 | #ifndef MRB_WITHOUT_FLOAT
|
---|
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 |
|
---|
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 |
|
---|
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
|
---|
68 | integral_pow(mrb_state *mrb, mrb_value x)
|
---|
69 | {
|
---|
70 | mrb_value y;
|
---|
71 | #ifndef MRB_WITHOUT_FLOAT
|
---|
72 | mrb_float d;
|
---|
73 | #endif
|
---|
74 |
|
---|
75 | mrb_get_args(mrb, "o", &y);
|
---|
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 |
|
---|
82 | if (exp < 0)
|
---|
83 | #ifdef MRB_WITHOUT_FLOAT
|
---|
84 | return mrb_fixnum_value(0);
|
---|
85 | #else
|
---|
86 | goto float_pow;
|
---|
87 | #endif
|
---|
88 | for (;;) {
|
---|
89 | if (exp & 1) {
|
---|
90 | if (mrb_int_mul_overflow(result, base, &result)) {
|
---|
91 | #ifndef MRB_WITHOUT_FLOAT
|
---|
92 | goto float_pow;
|
---|
93 | #endif
|
---|
94 | }
|
---|
95 | }
|
---|
96 | exp >>= 1;
|
---|
97 | if (exp == 0) break;
|
---|
98 | if (mrb_int_mul_overflow(base, base, &base)) {
|
---|
99 | #ifndef MRB_WITHOUT_FLOAT
|
---|
100 | goto float_pow;
|
---|
101 | #endif
|
---|
102 | }
|
---|
103 | }
|
---|
104 | return mrb_fixnum_value(result);
|
---|
105 | }
|
---|
106 | #ifdef MRB_WITHOUT_FLOAT
|
---|
107 | mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
|
---|
108 | #else
|
---|
109 | float_pow:
|
---|
110 | d = pow(mrb_to_flo(mrb, x), mrb_to_flo(mrb, y));
|
---|
111 | return mrb_float_value(mrb, d);
|
---|
112 | #endif
|
---|
113 | }
|
---|
114 |
|
---|
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 |
|
---|
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
|
---|
154 | integral_div(mrb_state *mrb, mrb_value x)
|
---|
155 | {
|
---|
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
|
---|
165 | mrb_float y;
|
---|
166 |
|
---|
167 | mrb_get_args(mrb, "f", &y);
|
---|
168 | return mrb_float_value(mrb, mrb_to_flo(mrb, x) / y);
|
---|
169 | #endif
|
---|
170 | }
|
---|
171 |
|
---|
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
|
---|
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 | {
|
---|
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)) {
|
---|
219 | return mrb_str_new_lit(mrb, "NaN");
|
---|
220 | }
|
---|
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 | }
|
---|
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
|
---|
291 | flodivmod(mrb_state *mrb, double x, double y, mrb_float *divp, mrb_float *modp)
|
---|
292 | {
|
---|
293 | double div, mod;
|
---|
294 |
|
---|
295 | if (isnan(y)) {
|
---|
296 | /* y is NaN so all results are NaN */
|
---|
297 | div = mod = y;
|
---|
298 | goto exit;
|
---|
299 | }
|
---|
300 | if (y == 0.0) {
|
---|
301 | if (x == 0) div = NAN;
|
---|
302 | else if (x > 0.0) div = INFINITY;
|
---|
303 | else div = -INFINITY; /* x < 0.0 */
|
---|
304 | mod = NAN;
|
---|
305 | goto exit;
|
---|
306 | }
|
---|
307 | if ((x == 0.0) || (isinf(y) && !isinf(x))) {
|
---|
308 | mod = x;
|
---|
309 | }
|
---|
310 | else {
|
---|
311 | mod = fmod(x, y);
|
---|
312 | }
|
---|
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:
|
---|
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 | }
|
---|
354 | #endif
|
---|
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 |
|
---|
378 | #ifndef MRB_WITHOUT_FLOAT
|
---|
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();
|
---|
386 | return mrb_bool_value(mrb_float(x) == mrb_float(y));
|
---|
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 |
|
---|
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 | {
|
---|
438 | if (TYPED_FIXABLE(v,int64_t)) {
|
---|
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;
|
---|
500 | if (val < 1.0) {
|
---|
501 | val = 0;
|
---|
502 | break;
|
---|
503 | }
|
---|
504 | }
|
---|
505 | #if defined(_ISOC99_SOURCE)
|
---|
506 | val = trunc(val);
|
---|
507 | #else
|
---|
508 | if (val > 0){
|
---|
509 | val = floor(val);
|
---|
510 | } else {
|
---|
511 | val = ceil(val);
|
---|
512 | }
|
---|
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 | }
|
---|
523 | return mrb_int_value(mrb, val);
|
---|
524 | }
|
---|
525 |
|
---|
526 | static mrb_value
|
---|
527 | flo_rshift(mrb_state *mrb, mrb_value x)
|
---|
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
|
---|
536 | flo_lshift(mrb_state *mrb, mrb_value x)
|
---|
537 | {
|
---|
538 | mrb_int width;
|
---|
539 |
|
---|
540 | mrb_get_args(mrb, "i", &width);
|
---|
541 | return flo_shift(mrb, x, width);
|
---|
542 | }
|
---|
543 |
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
628 | mrb_check_num_exact(mrb, f);
|
---|
629 | return mrb_int_value(mrb, f);
|
---|
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 |
|
---|
651 | mrb_check_num_exact(mrb, f);
|
---|
652 | return mrb_int_value(mrb, f);
|
---|
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 |
|
---|
696 | if (0 < ndigits && (isinf(number) || isnan(number))) {
|
---|
697 | return num;
|
---|
698 | }
|
---|
699 | mrb_check_num_exact(mrb, number);
|
---|
700 |
|
---|
701 | f = 1.0;
|
---|
702 | i = ndigits >= 0 ? ndigits : -ndigits;
|
---|
703 | if (ndigits > DBL_DIG+2) return num;
|
---|
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 | }
|
---|
734 | return mrb_int_value(mrb, number);
|
---|
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 |
|
---|
755 | mrb_check_num_exact(mrb, f);
|
---|
756 | return mrb_int_value(mrb, f);
|
---|
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 | }
|
---|
764 | #endif
|
---|
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 |
|
---|
789 | static mrb_value
|
---|
790 | fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
|
---|
791 | {
|
---|
792 | mrb_int a;
|
---|
793 |
|
---|
794 | a = mrb_fixnum(x);
|
---|
795 | if (mrb_fixnum_p(y)) {
|
---|
796 | mrb_int b, c;
|
---|
797 |
|
---|
798 | if (a == 0) return x;
|
---|
799 | b = mrb_fixnum(y);
|
---|
800 | if (mrb_int_mul_overflow(a, b, &c)) {
|
---|
801 | #ifndef MRB_WITHOUT_FLOAT
|
---|
802 | return mrb_float_value(mrb, (mrb_float)a * (mrb_float)b);
|
---|
803 | #endif
|
---|
804 | }
|
---|
805 | return mrb_fixnum_value(c);
|
---|
806 | }
|
---|
807 | #ifdef MRB_WITHOUT_FLOAT
|
---|
808 | mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
|
---|
809 | #else
|
---|
810 | return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
|
---|
811 | #endif
|
---|
812 | }
|
---|
813 |
|
---|
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 |
|
---|
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);
|
---|
845 | return fixnum_mul(mrb, x, y);
|
---|
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;
|
---|
890 | mrb_int a, b;
|
---|
891 |
|
---|
892 | mrb_get_args(mrb, "o", &y);
|
---|
893 | a = mrb_fixnum(x);
|
---|
894 | if (mrb_fixnum_p(y) && a != MRB_INT_MIN && (b=mrb_fixnum(y)) != MRB_INT_MIN) {
|
---|
895 | mrb_int mod;
|
---|
896 |
|
---|
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);
|
---|
904 | return mrb_float_value(mrb, NAN);
|
---|
905 | #endif
|
---|
906 | }
|
---|
907 | fixdivmod(mrb, a, b, NULL, &mod);
|
---|
908 | return mrb_fixnum_value(mod);
|
---|
909 | }
|
---|
910 | #ifdef MRB_WITHOUT_FLOAT
|
---|
911 | mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
|
---|
912 | #else
|
---|
913 | else {
|
---|
914 | mrb_float mod;
|
---|
915 |
|
---|
916 | flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), NULL, &mod);
|
---|
917 | return mrb_float_value(mrb, mod);
|
---|
918 | }
|
---|
919 | #endif
|
---|
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) {
|
---|
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
|
---|
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 | }
|
---|
951 | #ifdef MRB_WITHOUT_FLOAT
|
---|
952 | mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
|
---|
953 | #else
|
---|
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);
|
---|
959 | a = mrb_int_value(mrb, div);
|
---|
960 | b = mrb_float_value(mrb, mod);
|
---|
961 | return mrb_assoc_new(mrb, a, b);
|
---|
962 | }
|
---|
963 | #endif
|
---|
964 | }
|
---|
965 |
|
---|
966 | #ifndef MRB_WITHOUT_FLOAT
|
---|
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);
|
---|
977 | a = mrb_int_value(mrb, div);
|
---|
978 | b = mrb_float_value(mrb, mod);
|
---|
979 | return mrb_assoc_new(mrb, a, b);
|
---|
980 | }
|
---|
981 | #endif
|
---|
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));
|
---|
1004 | #ifndef MRB_WITHOUT_FLOAT
|
---|
1005 | case MRB_TT_FLOAT:
|
---|
1006 | return mrb_bool_value((mrb_float)mrb_fixnum(x) == mrb_float(y));
|
---|
1007 | #endif
|
---|
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 |
|
---|
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
|
---|
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));\
|
---|
1042 | return flo_ ## op1(mrb, mrb_float_value(mrb, (mrb_float)mrb_fixnum(x)));\
|
---|
1043 | } while(0)
|
---|
1044 | #endif
|
---|
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);
|
---|
1060 | bit_op(x, y, and, &);
|
---|
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);
|
---|
1077 | bit_op(x, y, or, |);
|
---|
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);
|
---|
1094 | bit_op(x, y, or, ^);
|
---|
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 | {
|
---|
1102 | if (width < 0) { /* mrb_int overflow */
|
---|
1103 | #ifdef MRB_WITHOUT_FLOAT
|
---|
1104 | return mrb_fixnum_value(0);
|
---|
1105 | #else
|
---|
1106 | return mrb_float_value(mrb, INFINITY);
|
---|
1107 | #endif
|
---|
1108 | }
|
---|
1109 | if (val > 0) {
|
---|
1110 | if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
|
---|
1111 | (val > (MRB_INT_MAX >> width))) {
|
---|
1112 | #ifdef MRB_WITHOUT_FLOAT
|
---|
1113 | return mrb_fixnum_value(-1);
|
---|
1114 | #else
|
---|
1115 | goto bit_overflow;
|
---|
1116 | #endif
|
---|
1117 | }
|
---|
1118 | return mrb_fixnum_value(val << width);
|
---|
1119 | }
|
---|
1120 | else {
|
---|
1121 | if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
|
---|
1122 | (val <= (MRB_INT_MIN >> width))) {
|
---|
1123 | #ifdef MRB_WITHOUT_FLOAT
|
---|
1124 | return mrb_fixnum_value(0);
|
---|
1125 | #else
|
---|
1126 | goto bit_overflow;
|
---|
1127 | #endif
|
---|
1128 | }
|
---|
1129 | return mrb_fixnum_value(val * ((mrb_int)1 << width));
|
---|
1130 | }
|
---|
1131 |
|
---|
1132 | #ifndef MRB_WITHOUT_FLOAT
|
---|
1133 | bit_overflow:
|
---|
1134 | {
|
---|
1135 | mrb_float f = (mrb_float)val;
|
---|
1136 | while (width--) {
|
---|
1137 | f *= 2;
|
---|
1138 | }
|
---|
1139 | return mrb_float_value(mrb, f);
|
---|
1140 | }
|
---|
1141 | #endif
|
---|
1142 | }
|
---|
1143 |
|
---|
1144 | static mrb_value
|
---|
1145 | rshift(mrb_int val, mrb_int width)
|
---|
1146 | {
|
---|
1147 | if (width < 0) { /* mrb_int overflow */
|
---|
1148 | return mrb_fixnum_value(0);
|
---|
1149 | }
|
---|
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 |
|
---|
1172 | mrb_get_args(mrb, "i", &width);
|
---|
1173 | if (width == 0) {
|
---|
1174 | return x;
|
---|
1175 | }
|
---|
1176 | val = mrb_fixnum(x);
|
---|
1177 | if (val == 0) return x;
|
---|
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 |
|
---|
1197 | mrb_get_args(mrb, "i", &width);
|
---|
1198 | if (width == 0) {
|
---|
1199 | return x;
|
---|
1200 | }
|
---|
1201 | val = mrb_fixnum(x);
|
---|
1202 | if (val == 0) return x;
|
---|
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 |
|
---|
1218 | #ifndef MRB_WITHOUT_FLOAT
|
---|
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 | *
|
---|
1232 | * Float::INFINITY.to_i
|
---|
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 | {
|
---|
1242 | mrb_int z = 0;
|
---|
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 |
|
---|
1251 | mrb_check_num_exact(mrb, d);
|
---|
1252 | if (FIXABLE_FLOAT(d)) {
|
---|
1253 | z = (mrb_int)d;
|
---|
1254 | }
|
---|
1255 | else {
|
---|
1256 | mrb_raisef(mrb, E_RANGE_ERROR, "number (%v) too big for integer", x);
|
---|
1257 | }
|
---|
1258 | }
|
---|
1259 | return mrb_fixnum_value(z);
|
---|
1260 | }
|
---|
1261 | #endif
|
---|
1262 |
|
---|
1263 | static mrb_value
|
---|
1264 | fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y)
|
---|
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)) {
|
---|
1275 | #ifndef MRB_WITHOUT_FLOAT
|
---|
1276 | return mrb_float_value(mrb, (mrb_float)a + (mrb_float)b);
|
---|
1277 | #endif
|
---|
1278 | }
|
---|
1279 | return mrb_fixnum_value(c);
|
---|
1280 | }
|
---|
1281 | #ifdef MRB_WITHOUT_FLOAT
|
---|
1282 | mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
|
---|
1283 | #else
|
---|
1284 | return mrb_float_value(mrb, (mrb_float)a + mrb_to_flo(mrb, y));
|
---|
1285 | #endif
|
---|
1286 | }
|
---|
1287 |
|
---|
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 |
|
---|
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);
|
---|
1318 | return fixnum_plus(mrb, self, other);
|
---|
1319 | }
|
---|
1320 |
|
---|
1321 | static mrb_value
|
---|
1322 | fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y)
|
---|
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)) {
|
---|
1332 | #ifndef MRB_WITHOUT_FLOAT
|
---|
1333 | return mrb_float_value(mrb, (mrb_float)a - (mrb_float)b);
|
---|
1334 | #endif
|
---|
1335 | }
|
---|
1336 | return mrb_fixnum_value(c);
|
---|
1337 | }
|
---|
1338 | #ifdef MRB_WITHOUT_FLOAT
|
---|
1339 | mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
|
---|
1340 | #else
|
---|
1341 | return mrb_float_value(mrb, (mrb_float)a - mrb_to_flo(mrb, y));
|
---|
1342 | #endif
|
---|
1343 | }
|
---|
1344 |
|
---|
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 |
|
---|
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);
|
---|
1376 | return fixnum_minus(mrb, self, other);
|
---|
1377 | }
|
---|
1378 |
|
---|
1379 |
|
---|
1380 | MRB_API mrb_value
|
---|
1381 | mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
|
---|
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) {
|
---|
1388 | mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base);
|
---|
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 |
|
---|
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 |
|
---|
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
|
---|
1486 | integral_cmp(mrb_state *mrb, mrb_value self)
|
---|
1487 | {
|
---|
1488 | mrb_value other;
|
---|
1489 | mrb_int n;
|
---|
1490 |
|
---|
1491 | mrb_get_args(mrb, "o", &other);
|
---|
1492 | n = cmpnum(mrb, self, other);
|
---|
1493 | if (n == -2) return mrb_nil_value();
|
---|
1494 | return mrb_fixnum_value(n);
|
---|
1495 | }
|
---|
1496 |
|
---|
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)) {
|
---|
1561 | case MRB_TT_FIXNUM:
|
---|
1562 | case MRB_TT_FLOAT:
|
---|
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);
|
---|
1568 | default:
|
---|
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);
|
---|
1573 | }
|
---|
1574 | }
|
---|
1575 |
|
---|
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 |
|
---|
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 | */
|
---|
1596 | #ifndef MRB_WITHOUT_FLOAT
|
---|
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 | }
|
---|
1605 | #endif
|
---|
1606 |
|
---|
1607 | /* ------------------------------------------------------------------------*/
|
---|
1608 | void
|
---|
1609 | mrb_init_numeric(mrb_state *mrb)
|
---|
1610 | {
|
---|
1611 | struct RClass *numeric, *integer, *fixnum, *integral;
|
---|
1612 | #ifndef MRB_WITHOUT_FLOAT
|
---|
1613 | struct RClass *fl;
|
---|
1614 | #endif
|
---|
1615 |
|
---|
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 |
|
---|
1628 | /* Numeric Class */
|
---|
1629 | numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */
|
---|
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());
|
---|
1632 |
|
---|
1633 | /* Integer Class */
|
---|
1634 | integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */
|
---|
1635 | MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM);
|
---|
1636 | mrb_undef_class_method(mrb, integer, "new");
|
---|
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());
|
---|
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
|
---|
1645 |
|
---|
1646 | /* Fixnum Class */
|
---|
1647 | mrb->fixnum_class = fixnum = mrb_define_class(mrb, "Fixnum", integer);
|
---|
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 */
|
---|
1660 | #ifndef MRB_WITHOUT_FLOAT
|
---|
1661 | mrb_define_method(mrb, fixnum, "to_f", fix_to_f, MRB_ARGS_NONE()); /* 15.2.8.3.23 */
|
---|
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));
|
---|
1665 | mrb_define_method(mrb, fixnum, "divmod", fix_divmod, MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */
|
---|
1666 |
|
---|
1667 | #ifndef MRB_WITHOUT_FLOAT
|
---|
1668 | /* Float Class */
|
---|
1669 | mrb->float_class = fl = mrb_define_class(mrb, "Float", numeric); /* 15.2.9 */
|
---|
1670 | MRB_SET_INSTANCE_TT(fl, MRB_TT_FLOAT);
|
---|
1671 | mrb_undef_class_method(mrb, fl, "new");
|
---|
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));
|
---|
1681 | mrb_define_method(mrb, fl, ">>", flo_rshift, MRB_ARGS_REQ(1));
|
---|
1682 | mrb_define_method(mrb, fl, "<<", flo_lshift, MRB_ARGS_REQ(1));
|
---|
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 */
|
---|
1694 |
|
---|
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());
|
---|
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
|
---|
1705 |
|
---|
1706 | mrb_include_module(mrb, fl, integral);
|
---|
1707 | #endif
|
---|
1708 | }
|
---|