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