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