Coverage Report

Created: 2025-09-05 07:21

/src/mruby/src/numeric.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
** numeric.c - Numeric, Integer, Float class
3
**
4
** See Copyright Notice in mruby.h
5
*/
6
7
#include <mruby.h>
8
#include <mruby/array.h>
9
#include <mruby/numeric.h>
10
#include <mruby/string.h>
11
#include <mruby/class.h>
12
#include <mruby/internal.h>
13
#include <mruby/presym.h>
14
#include <string.h>
15
16
#ifndef MRB_NO_FLOAT
17
#ifdef MRB_USE_FLOAT32
18
#define trunc(f) truncf(f)
19
#define fmod(x,y) fmodf(x,y)
20
#else
21
#endif
22
#endif
23
24
/**
25
 * This function is called to raise a RangeError when an integer operation
26
 * results in an overflow. It's marked mrb_noreturn as it always raises an
27
 * exception and does not return.
28
 *
29
 * @param mrb The mruby state.
30
 * @param reason A string describing the operation that caused the overflow
31
 *               (e.g., "addition", "multiplication").
32
 */
33
mrb_noreturn void
34
mrb_int_overflow(mrb_state *mrb, const char *reason)
35
0
{
36
0
  mrb_raisef(mrb, E_RANGE_ERROR, "integer overflow in %s", reason);
37
0
}
38
39
/**
40
 * This function is called to raise a ZeroDivisionError. It's marked
41
 * mrb_noreturn as it always raises an exception and does not return.
42
 *
43
 * @param mrb The mruby state.
44
 */
45
mrb_noreturn void
46
mrb_int_zerodiv(mrb_state *mrb)
47
30
{
48
30
  mrb_raise(mrb, E_ZERODIV_ERROR, "divided by 0");
49
30
}
50
51
static mrb_noreturn void
52
mrb_int_noconv(mrb_state *mrb, mrb_value y)
53
9
{
54
9
  mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %Y into Integer", y);
55
9
}
56
57
/**
58
 * Calculates x raised to the power of y, where x is an integer.
59
 * y can be an integer or float. The result type can be Integer,
60
 * Float, or BigInt depending on the inputs and intermediate calculations.
61
 *
62
 * @param mrb The mruby state.
63
 * @param x The base (must be an integer type, possibly BigInt).
64
 * @param y The exponent (can be Integer or Float).
65
 * @return An mrb_value representing the result of the exponentiation.
66
 *         This can be an Integer, Float, or BigInt.
67
 * Handles potential overflows by promoting to BigInt if MRB_USE_BIGINT is defined,
68
 * or by raising RangeError if not.
69
 * Handles negative exponents by returning a Float if MRB_NO_FLOAT is not defined,
70
 * or raising RangeError if it is.
71
 */
72
mrb_value
73
mrb_int_pow(mrb_state *mrb, mrb_value x, mrb_value y)
74
3.11k
{
75
3.11k
#ifdef MRB_USE_BIGINT
76
3.11k
  if (mrb_bigint_p(x)) {
77
2
#ifndef MRB_NO_FLOAT
78
2
    if (mrb_float_p(y)) {
79
0
      return mrb_float_value(mrb, pow(mrb_bint_as_float(mrb, x), mrb_float(y)));
80
0
    }
81
2
#endif
82
2
    return mrb_bint_pow(mrb, x, y);
83
2
  }
84
3.11k
#endif
85
3.11k
  mrb_int base = mrb_integer(x);
86
3.11k
  mrb_int result = 1;
87
3.11k
  mrb_int exp;
88
89
3.11k
#ifndef MRB_NO_FLOAT
90
3.11k
  if (mrb_float_p(y)) {
91
483
    return mrb_float_value(mrb, pow((double)base, mrb_float(y)));
92
483
  }
93
2.63k
  else if (mrb_integer_p(y)) {
94
2.63k
    exp = mrb_integer(y);
95
2.63k
  }
96
2
  else
97
2
#endif
98
2
  {
99
2
    exp = mrb_as_int(mrb, y);
100
2
  }
101
2.63k
  if (exp < 0) {
102
485
#ifndef MRB_NO_FLOAT
103
485
    return mrb_float_value(mrb, pow((double)base, (double)exp));
104
#else
105
    mrb_int_overflow(mrb, "negative power");
106
#endif
107
485
  }
108
5.77k
  for (;;) {
109
5.77k
    if (exp & 1) {
110
2.18k
      if (mrb_int_mul_overflow(result, base, &result)) {
111
10
#ifdef MRB_USE_BIGINT
112
10
        return mrb_bint_pow(mrb, mrb_bint_new_int(mrb, mrb_integer(x)), y);
113
#else
114
        mrb_int_overflow(mrb, "power");
115
#endif
116
10
      }
117
2.18k
    }
118
5.76k
    exp >>= 1;
119
5.76k
    if (exp == 0) break;
120
5.26k
    if (mrb_int_mul_overflow(base, base, &base)) {
121
1.64k
#ifdef MRB_USE_BIGINT
122
1.64k
      return mrb_bint_pow(mrb, mrb_bint_new_int(mrb, mrb_integer(x)), y);
123
#else
124
      mrb_int_overflow(mrb, "power");
125
#endif
126
1.64k
    }
127
5.26k
  }
128
494
  return mrb_int_value(mrb, result);
129
2.14k
}
130
131
/*
132
 * call-seq:
133
 *
134
 *  num ** other  ->  num
135
 *
136
 * Raises `num` the `other` power.
137
 *
138
 *    2.0**3      #=> 8.0
139
 */
140
static mrb_value
141
int_pow(mrb_state *mrb, mrb_value x)
142
3.11k
{
143
3.11k
  return mrb_int_pow(mrb, x, mrb_get_arg1(mrb));
144
3.11k
}
145
146
/**
147
 * Performs integer division of x by y. This function implements specific
148
 * rounding behavior for negative numbers to match Ruby's / operator for
149
 * integers (floor division).
150
 *
151
 * @param x The dividend.
152
 * @param y The divisor.
153
 * @return The result of the integer division (mrb_int).
154
 * Note: This function does not handle division by zero; the caller is
155
 *       expected to check for this.
156
 */
157
mrb_int
158
mrb_div_int(mrb_int x, mrb_int y)
159
9.54k
{
160
9.54k
  mrb_int div = x / y;
161
162
9.54k
  if ((x ^ y) < 0 && x != div * y) {
163
655
    div -= 1;
164
655
  }
165
9.54k
  return div;
166
9.54k
}
167
168
/**
169
 * Performs integer division of x by y and returns the result as an mrb_value.
170
 * It uses mrb_div_int for the division logic.
171
 *
172
 * @param mrb The mruby state.
173
 * @param x The dividend.
174
 * @param y The divisor.
175
 * @return An mrb_value (integer) representing the result of the division.
176
 * @raise ZeroDivisionError if y is 0.
177
 * @raise RangeError for overflow conditions (specifically MRB_INT_MIN / -1).
178
 */
179
mrb_value
180
mrb_div_int_value(mrb_state *mrb, mrb_int x, mrb_int y)
181
6.65k
{
182
6.65k
  if (y == 0) {
183
5
    mrb_int_zerodiv(mrb);
184
5
  }
185
6.64k
  else if (x == MRB_INT_MIN && y == -1) {
186
693
#ifdef MRB_USE_BIGINT
187
693
    return mrb_bint_mul_ii(mrb, x, y);
188
#else
189
    mrb_int_overflow(mrb, "division");
190
#endif
191
693
  }
192
5.95k
  return mrb_int_value(mrb, mrb_div_int(x, y));
193
6.65k
}
194
195
/* 15.2.8.3.6 */
196
/*
197
 * call-seq:
198
 *   int / num  ->  num
199
 *
200
 * Performs division: the class of the resulting object depends on
201
 * the class of `num` and on the magnitude of the
202
 * result.
203
 */
204
static mrb_value
205
int_div(mrb_state *mrb, mrb_value x)
206
9.34k
{
207
9.34k
  mrb_value y = mrb_get_arg1(mrb);
208
9.34k
#ifdef MRB_USE_BIGINT
209
9.34k
  if (mrb_bigint_p(x)) {
210
4.59k
    if (mrb_bigint_p(y) || mrb_integer_p(y)) {
211
4.58k
      return mrb_bint_div(mrb, x, y);
212
4.58k
    }
213
4.59k
  } else
214
4.75k
#endif
215
4.75k
  if (mrb_integer_p(y)) {
216
4.23k
    return mrb_div_int_value(mrb, mrb_integer(x), mrb_integer(y));
217
4.23k
  }
218
515
  switch (mrb_type(y)) {
219
0
#ifdef MRB_USE_BIGINT
220
0
  case MRB_TT_INTEGER:
221
510
  case MRB_TT_BIGINT:
222
510
    return mrb_bint_div(mrb, mrb_as_bint(mrb, x), y);
223
0
#endif
224
0
#ifdef MRB_USE_RATIONAL
225
1
  case MRB_TT_RATIONAL:
226
1
    return mrb_rational_div(mrb, mrb_as_rational(mrb, x), y);
227
0
#endif
228
0
#ifdef MRB_USE_COMPLEX
229
0
  case MRB_TT_COMPLEX:
230
0
    x = mrb_complex_new(mrb, mrb_as_float(mrb, x), 0);
231
0
    return mrb_complex_div(mrb, x, y);
232
0
#endif
233
0
#ifndef MRB_NO_FLOAT
234
0
  case MRB_TT_FLOAT:
235
0
    return mrb_float_value(mrb, mrb_div_float(mrb_as_float(mrb, x), mrb_as_float(mrb, y)));
236
0
#endif
237
4
  default:
238
4
    mrb_int_noconv(mrb, y);
239
515
  }
240
515
}
241
242
/* 15.2.9.3.19(x) */
243
/*
244
 *  call-seq:
245
 *     num.quo(numeric)  ->  real
246
 *
247
 *  Returns most exact division.
248
 */
249
250
/*
251
 * call-seq:
252
 *   int.div(other)  ->  int
253
 *
254
 * Performs division: resulting integer.
255
 */
256
static mrb_value
257
int_idiv(mrb_state *mrb, mrb_value x)
258
0
{
259
0
#ifdef MRB_USE_BIGINT
260
0
  if (mrb_bigint_p(x)) {
261
0
    return mrb_bint_div(mrb, x, mrb_get_arg1(mrb));
262
0
  }
263
0
#endif
264
0
  mrb_int y = mrb_as_int(mrb,  mrb_get_arg1(mrb));
265
0
  return mrb_div_int_value(mrb, mrb_integer(x), y);
266
0
}
267
268
#ifndef MRB_NO_FLOAT
269
static mrb_value
270
int_fdiv(mrb_state *mrb, mrb_value x)
271
0
{
272
0
  mrb_float y = mrb_as_float(mrb,  mrb_get_arg1(mrb));
273
274
0
  if (y == 0) {
275
0
    mrb_int_zerodiv(mrb);
276
0
  }
277
0
#ifdef MRB_USE_BIGINT
278
0
  if (mrb_bigint_p(x)) {
279
0
    return mrb_float_value(mrb, mrb_bint_as_float(mrb, x) / y);
280
0
  }
281
0
#endif
282
0
  return mrb_float_value(mrb, mrb_integer(x) / y);
283
0
}
284
#endif
285
286
static mrb_value
287
int_quo(mrb_state *mrb, mrb_value x)
288
0
{
289
#ifndef MRB_USE_RATIONAL
290
291
#ifdef MRB_NO_FLOAT
292
  return int_idiv(mrb, x);
293
#else
294
  return int_fdiv(mrb, x);
295
#endif
296
297
#else
298
0
  mrb_int a = mrb_integer(x);
299
0
  mrb_value y = mrb_get_arg1(mrb);
300
0
  if (mrb_integer_p(y) && mrb_class_defined_id(mrb, MRB_SYM(Rational))) {
301
0
    return mrb_rational_new(mrb, a, mrb_integer(y));
302
0
  }
303
0
  switch (mrb_type(y)) {
304
0
  case MRB_TT_RATIONAL:
305
0
    x = mrb_rational_new(mrb, a, 1);
306
0
    return mrb_rational_div(mrb, x, y);
307
0
  default:
308
0
#ifndef MRB_NO_FLOAT
309
0
    return mrb_float_value(mrb, mrb_div_float((mrb_float)a, mrb_as_float(mrb, y)));
310
#else
311
    mrb_int_noconv(mrb, y);
312
    break;
313
#endif
314
0
  }
315
0
#endif
316
0
}
317
318
static mrb_value
319
coerce_step_counter(mrb_state *mrb, mrb_value self)
320
0
{
321
0
  mrb->c->ci->mid = 0;
322
0
#ifndef MRB_NO_FLOAT
323
0
  mrb_value step = mrb_get_arg1(mrb);
324
0
  if (mrb_float_p(step)) {
325
0
    return mrb_ensure_float_type(mrb, self);
326
0
  }
327
0
#endif
328
0
  return self;
329
0
}
330
331
#ifndef MRB_NO_FLOAT
332
/********************************************************************
333
 *
334
 * Document-class: Float
335
 *
336
 *  `Float` objects represent inexact real numbers using
337
 *  the native architecture's double-precision floating-point
338
 *  representation.
339
 */
340
341
static mrb_value
342
flo_pow(mrb_state *mrb, mrb_value x)
343
4
{
344
4
  mrb_value y = mrb_get_arg1(mrb);
345
4
  mrb_float d = pow(mrb_as_float(mrb, x), mrb_as_float(mrb, y));
346
4
  return mrb_float_value(mrb, d);
347
4
}
348
349
static mrb_value
350
flo_idiv(mrb_state *mrb, mrb_value xv)
351
0
{
352
0
  mrb_float x = mrb_float(xv);
353
0
  mrb_check_num_exact(mrb, x);
354
0
  mrb_int y = mrb_as_int(mrb, mrb_get_arg1(mrb));
355
0
  return mrb_div_int_value(mrb, (mrb_int)x, y);
356
0
}
357
358
mrb_float
359
mrb_div_float(mrb_float x, mrb_float y)
360
573
{
361
573
  if (y != 0.0) {
362
573
    return x / y;
363
573
  }
364
0
  else if (x == 0.0) {
365
0
    return NAN;
366
0
  }
367
0
  else {
368
0
    return x * (signbit(y) ? -1.0 : 1.0) * INFINITY;
369
0
  }
370
573
}
371
372
/* 15.2.9.3.6 */
373
/*
374
 * call-seq:
375
 *   float / num  ->  float
376
 *
377
 * Returns a new Float which is the result of dividing float by num.
378
 */
379
static mrb_value
380
flo_div(mrb_state *mrb, mrb_value x)
381
2
{
382
2
  mrb_value y = mrb_get_arg1(mrb);
383
2
  mrb_float a = mrb_float(x);
384
385
2
  switch(mrb_type(y)) {
386
0
#ifdef MRB_USE_COMPLEX
387
0
  case MRB_TT_COMPLEX:
388
0
    return mrb_complex_div(mrb, mrb_complex_new(mrb, a, 0), y);
389
0
#endif
390
0
  case MRB_TT_FLOAT:
391
0
    a = mrb_div_float(a, mrb_float(y));
392
0
    return mrb_float_value(mrb, a);
393
2
  default:
394
2
    a = mrb_div_float(a, mrb_as_float(mrb, y));
395
2
    return mrb_float_value(mrb, a);
396
2
  }
397
0
  return mrb_float_value(mrb, a);
398
2
}
399
400
static mrb_value
401
num_fdiv(mrb_state *mrb, mrb_value x)
402
0
{
403
0
  return flo_div(mrb, mrb_ensure_float_type(mrb, x));
404
0
}
405
406
/**
407
 * Converts an mrb_value float to a new mrb_value string.
408
 * It handles formatting to ensure the string representation includes a
409
 * decimal point and fractional part (e.g., ".0" is appended if not present).
410
 *
411
 * @param mrb The mruby state.
412
 * @param flo The float mrb_value to convert.
413
 * @param fmt This argument is noted as no longer used and can be NULL.
414
 *            The function uses a default format.
415
 * @return A new mrb_value string representing the float.
416
 */
417
/* the argument `fmt` is no longer used; you can pass `NULL` */
418
mrb_value
419
mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt)
420
39.4k
{
421
39.4k
  char buf[25];
422
#ifdef MRB_USE_FLOAT32
423
  const int prec =  7;
424
#else
425
39.4k
  const int prec =  15;
426
39.4k
#endif
427
428
39.4k
  mrb_format_float(mrb_float(flo), buf, sizeof(buf), 'g', prec, '\0');
429
119k
  for (char *p = buf; *p; p++) {
430
86.8k
    if (*p == '.') goto exit;
431
79.9k
    if (*p == 'e') {
432
0
      memmove(p+2, p, strlen(p)+1);
433
0
      p[0] = '.';
434
0
      p[1] = '0';
435
0
      goto exit;
436
0
    }
437
79.9k
  }
438
32.6k
  strcat(buf, ".0");
439
39.4k
 exit:
440
39.4k
  return mrb_str_new_cstr(mrb, buf);
441
32.6k
}
442
443
/* 15.2.9.3.16(x) */
444
/*
445
 *  call-seq:
446
 *     flt.to_s  ->  string
447
 *     flt.inspect  ->  string
448
 *
449
 *  Returns a string containing a representation of self. As well as a
450
 *  fixed or exponential form of the number, the call may return
451
 *  "`NaN`", "`Infinity`", and
452
 *  "`-Infinity`".
453
 *
454
 *     3.0.to_s   #=> 3.0
455
 *     3.25.to_s  #=> 3.25
456
 */
457
458
static mrb_value
459
flo_to_s(mrb_state *mrb, mrb_value flt)
460
39.4k
{
461
39.4k
  mrb_float f = mrb_float(flt);
462
39.4k
  mrb_value str;
463
464
39.4k
  if (isinf(f)) {
465
0
    str = f < 0 ? mrb_str_new_lit(mrb, "-Infinity")
466
0
                : mrb_str_new_lit(mrb, "Infinity");
467
0
  }
468
39.4k
  else if (isnan(f)) {
469
0
    str = mrb_str_new_lit(mrb, "NaN");
470
0
  }
471
39.4k
  else {
472
39.4k
    str = mrb_float_to_str(mrb, flt, NULL);
473
39.4k
  }
474
475
39.4k
  RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
476
39.4k
  return str;
477
39.4k
}
478
479
/* 15.2.9.3.3 */
480
/*
481
 * call-seq:
482
 *   float + other  ->  float
483
 *
484
 * Returns a new float which is the sum of `float`
485
 * and `other`.
486
 */
487
static mrb_value
488
flo_add(mrb_state *mrb, mrb_value x)
489
3.33k
{
490
3.33k
  mrb_value y = mrb_get_arg1(mrb);
491
3.33k
  mrb_float a = mrb_float(x);
492
493
3.33k
  switch (mrb_type(y)) {
494
0
  case MRB_TT_FLOAT:
495
0
    return mrb_float_value(mrb, a + mrb_float(y));
496
0
#if defined(MRB_USE_COMPLEX)
497
0
  case MRB_TT_COMPLEX:
498
0
    return mrb_complex_add(mrb, y, x);
499
0
#endif
500
3.33k
  default:
501
3.33k
    return mrb_float_value(mrb, a + mrb_as_float(mrb, y));
502
3.33k
  }
503
3.33k
}
504
505
/* 15.2.9.3.4 */
506
/*
507
 * call-seq:
508
 *   float - other  ->  float
509
 *
510
 * Returns a new float which is the difference of `float`
511
 * and `other`.
512
 */
513
514
static mrb_value
515
flo_sub(mrb_state *mrb, mrb_value x)
516
8.30k
{
517
8.30k
  mrb_value y = mrb_get_arg1(mrb);
518
8.30k
  mrb_float a = mrb_float(x);
519
520
8.30k
  switch (mrb_type(y)) {
521
0
  case MRB_TT_FLOAT:
522
0
    return mrb_float_value(mrb, a - mrb_float(y));
523
0
#if defined(MRB_USE_COMPLEX)
524
0
  case MRB_TT_COMPLEX:
525
0
    return mrb_complex_sub(mrb, mrb_complex_new(mrb, a, 0), y);
526
0
#endif
527
8.30k
  default:
528
8.30k
    return mrb_float_value(mrb, a - mrb_as_float(mrb, y));
529
8.30k
  }
530
8.30k
}
531
532
/* 15.2.9.3.5 */
533
/*
534
 * call-seq:
535
 *   float * other  ->  float
536
 *
537
 * Returns a new float which is the product of `float`
538
 * and `other`.
539
 */
540
541
static mrb_value
542
flo_mul(mrb_state *mrb, mrb_value x)
543
0
{
544
0
  mrb_value y = mrb_get_arg1(mrb);
545
0
  mrb_float a = mrb_float(x);
546
547
0
  switch (mrb_type(y)) {
548
0
  case MRB_TT_FLOAT:
549
0
    return mrb_float_value(mrb, a * mrb_float(y));
550
0
#if defined(MRB_USE_COMPLEX)
551
0
  case MRB_TT_COMPLEX:
552
0
    return mrb_complex_mul(mrb, y, x);
553
0
#endif
554
0
  default:
555
0
    return mrb_float_value(mrb, a * mrb_as_float(mrb, y));
556
0
  }
557
0
}
558
559
static void
560
flodivmod(mrb_state *mrb, double x, double y, mrb_float *divp, mrb_float *modp)
561
1.78k
{
562
1.78k
  double div, mod;
563
564
1.78k
  if (isnan(y)) {
565
    /* y is NaN so all results are NaN */
566
0
    div = mod = y;
567
0
    goto exit;
568
0
  }
569
1.78k
  if (y == 0.0) {
570
0
    mrb_int_zerodiv(mrb);
571
0
  }
572
1.78k
  if (isinf(y) && !isinf(x)) {
573
0
    mod = x;
574
0
  }
575
1.78k
  else {
576
1.78k
    mod = fmod(x, y);
577
1.78k
  }
578
1.78k
  if (isinf(x) && !isinf(y)) {
579
0
    div = x;
580
0
  }
581
1.78k
  else {
582
1.78k
    div = (x - mod) / y;
583
1.78k
    if (modp && divp) div = round(div);
584
1.78k
  }
585
1.78k
  if (div == 0) div = 0.0;
586
1.78k
  if (mod == 0) mod = 0.0;
587
1.78k
  if (y*mod < 0) {
588
3
    mod += y;
589
3
    div -= 1.0;
590
3
  }
591
1.78k
 exit:
592
1.78k
  if (modp) *modp = mod;
593
1.78k
  if (divp) *divp = div;
594
1.78k
}
595
596
/* 15.2.9.3.5 */
597
/*
598
 *  call-seq:
599
 *     flt % other        ->  float
600
 *     flt.modulo(other)  ->  float
601
 *
602
 *  Return the modulo after division of `flt` by `other`.
603
 *
604
 *     6543.21.modulo(137)      #=> 104.21
605
 *     6543.21.modulo(137.24)   #=> 92.9299999999996
606
 */
607
608
static mrb_value
609
flo_mod(mrb_state *mrb, mrb_value x)
610
3
{
611
3
  mrb_value y = mrb_get_arg1(mrb);
612
3
  mrb_float mod;
613
614
3
  flodivmod(mrb, mrb_float(x), mrb_as_float(mrb, y), NULL, &mod);
615
3
  return mrb_float_value(mrb, mod);
616
3
}
617
#endif
618
619
/* 15.2.8.3.16 */
620
/*
621
 *  call-seq:
622
 *     num.eql?(numeric)  ->  true or false
623
 *
624
 *  Returns `true` if `num` and `numeric` are the
625
 *  same type and have equal values.
626
 *
627
 *     1 == 1.0          #=> true
628
 *     1.eql?(1.0)       #=> false
629
 *     (1.0).eql?(1.0)   #=> true
630
 */
631
static mrb_value
632
num_eql(mrb_state *mrb, mrb_value x)
633
299
{
634
299
  mrb_value y = mrb_get_arg1(mrb);
635
636
299
#ifdef MRB_USE_BIGINT
637
299
  if (mrb_bigint_p(x)) {
638
0
    return mrb_bool_value(mrb_bint_cmp(mrb, x, y) == 0);
639
0
  }
640
299
#endif
641
299
#ifndef MRB_NO_FLOAT
642
299
  if (mrb_float_p(x)) {
643
0
    if (!mrb_float_p(y)) return mrb_false_value();
644
0
    return mrb_bool_value(mrb_float(x) == mrb_float(y));
645
0
  }
646
299
#endif
647
299
  if (mrb_integer_p(x)) {
648
299
    if (!mrb_integer_p(y)) return mrb_false_value();
649
14
    return mrb_bool_value(mrb_integer(x) == mrb_integer(y));
650
299
  }
651
0
  return mrb_bool_value(mrb_equal(mrb, x, y));
652
299
}
653
654
#ifndef MRB_NO_FLOAT
655
/* 15.2.9.3.7 */
656
/*
657
 *  call-seq:
658
 *     flt == obj  ->  true or false
659
 *
660
 *  Returns `true` only if *obj* has the same value
661
 *  as *flt*. Contrast this with `Float#eql?`, which
662
 *  requires *obj* to be a `Float`.
663
 *
664
 *     1.0 == 1   #=> true
665
 *
666
 */
667
668
static mrb_value
669
flo_eq(mrb_state *mrb, mrb_value x)
670
5
{
671
5
  mrb_value y = mrb_get_arg1(mrb);
672
673
5
  switch (mrb_type(y)) {
674
0
  case MRB_TT_INTEGER:
675
0
    return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_integer(y));
676
0
  case MRB_TT_FLOAT:
677
0
    return mrb_bool_value(mrb_float(x) == mrb_float(y));
678
0
#ifdef MRB_USE_RATIONAL
679
0
  case MRB_TT_RATIONAL:
680
0
    return mrb_bool_value(mrb_float(x) == mrb_as_float(mrb, y));
681
0
#endif
682
0
#ifdef MRB_USE_COMPLEX
683
0
  case MRB_TT_COMPLEX:
684
0
    return mrb_bool_value(mrb_equal(mrb, y, x));
685
0
#endif
686
5
  default:
687
5
    return mrb_false_value();
688
5
  }
689
5
}
690
691
/* 15.2.9.3.13 */
692
/*
693
 * Document-method: Float#to_f
694
 *
695
 * call-seq:
696
 *   flt.to_f  ->  self
697
 *
698
 * As `flt` is already a float, returns `self`.
699
 */
700
701
/* 15.2.9.3.11 */
702
/*
703
 *  call-seq:
704
 *     flt.infinite?  ->  nil, -1, +1
705
 *
706
 *  Returns `nil`, -1, or +1 depending on whether *flt*
707
 *  is finite, -infinity, or +infinity.
708
 *
709
 *     (0.0).infinite?        #=> nil
710
 *     (-1.0/0.0).infinite?   #=> -1
711
 *     (+1.0/0.0).infinite?   #=> 1
712
 */
713
714
static mrb_value
715
flo_infinite_p(mrb_state *mrb, mrb_value num)
716
0
{
717
0
  mrb_float value = mrb_float(num);
718
719
0
  if (isinf(value)) {
720
0
    return mrb_fixnum_value(value < 0 ? -1 : 1);
721
0
  }
722
0
  return mrb_nil_value();
723
0
}
724
725
/* 15.2.9.3.9 */
726
/*
727
 *  call-seq:
728
 *     flt.finite?  ->  true or false
729
 *
730
 *  Returns `true` if *flt* is a valid IEEE floating
731
 *  point number (it is not infinite, and `nan?` is
732
 *  `false`).
733
 *
734
 */
735
736
static mrb_value
737
flo_finite_p(mrb_state *mrb, mrb_value num)
738
16.3k
{
739
16.3k
  return mrb_bool_value(isfinite(mrb_float(num)));
740
16.3k
}
741
742
/*
743
 *  Document-class: FloatDomainError
744
 *
745
 *  Raised when attempting to convert special float values
746
 *  (in particular infinite or NaN)
747
 *  to numerical classes which don't support them.
748
 *
749
 *     Float::INFINITY.to_i
750
 *
751
 *  <em>raises the exception:</em>
752
 *
753
 *     FloatDomainError: Infinity
754
 */
755
/* ------------------------------------------------------------------------*/
756
/**
757
 * Checks if a mrb_float value is Infinity or NaN. If it is, this function
758
 * raises a FloatDomainError. This is used to prevent conversions of these
759
 * special float values to exact number types like Integer.
760
 *
761
 * @param mrb The mruby state.
762
 * @param num The float value to check.
763
 * It does not return a value (void function) but will raise an exception
764
 * if the number is not exact.
765
 */
766
void
767
mrb_check_num_exact(mrb_state *mrb, mrb_float num)
768
274
{
769
274
  if (isinf(num)) {
770
0
    mrb_raise(mrb, E_FLOATDOMAIN_ERROR, num < 0 ? "-Infinity" : "Infinity");
771
0
  }
772
274
  if (isnan(num)) {
773
0
    mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
774
0
  }
775
274
}
776
777
static mrb_value
778
flo_rounding_int(mrb_state *mrb, mrb_float f)
779
0
{
780
0
  if (!FIXABLE_FLOAT(f)) {
781
0
#ifdef MRB_USE_BIGINT
782
0
    return mrb_bint_new_float(mrb, f);
783
#else
784
    mrb_int_overflow(mrb, "rounding");
785
#endif
786
0
  }
787
0
  return mrb_int_value(mrb, (mrb_int)f);
788
0
}
789
790
static mrb_value
791
flo_rounding(mrb_state *mrb, mrb_value num, double (*func)(double))
792
0
{
793
0
  mrb_float f = mrb_float(num);
794
0
  mrb_int ndigits = 0;
795
#ifdef MRB_USE_FLOAT32
796
  const int fprec =  7;
797
#else
798
0
  const int fprec =  15;
799
0
#endif
800
801
0
  mrb_get_args(mrb, "|i", &ndigits);
802
0
  if (f == 0.0) {
803
0
    return ndigits > 0 ? mrb_float_value(mrb, f) : mrb_fixnum_value(0);
804
0
  }
805
0
  if (ndigits > 0) {
806
0
    if (ndigits > fprec) return num;
807
0
    mrb_float d = pow(10, (double)ndigits);
808
0
    f = func(f * d) / d;
809
0
    mrb_check_num_exact(mrb, f);
810
0
    return mrb_float_value(mrb, f);
811
0
  }
812
0
  if (ndigits < 0) {
813
0
    mrb_float d = pow(10, -(double)ndigits);
814
0
    f = func(f / d) * d;
815
0
  }
816
0
  else {                        /* ndigits == 0 */
817
0
    f = func(f);
818
0
  }
819
0
  mrb_check_num_exact(mrb, f);
820
0
  return flo_rounding_int(mrb, f);
821
0
}
822
823
/* 15.2.9.3.10 */
824
/*
825
 *  call-seq:
826
 *     float.floor([ndigits])  ->  integer or float
827
 *
828
 *  Returns the largest number less than or equal to `float` with
829
 *  a precision of `ndigits` decimal digits (default: 0).
830
 *
831
 *  When the precision is negative, the returned value is an integer
832
 *  with at least `ndigits.abs` trailing zeros.
833
 *
834
 *  Returns a floating-point number when `ndigits` is positive,
835
 *  otherwise returns an integer.
836
 *
837
 *     1.2.floor      #=> 1
838
 *     2.0.floor      #=> 2
839
 *     (-1.2).floor   #=> -2
840
 *     (-2.0).floor   #=> -2
841
 *
842
 *     1.234567.floor(2)   #=> 1.23
843
 *     1.234567.floor(3)   #=> 1.234
844
 *     1.234567.floor(4)   #=> 1.2345
845
 *     1.234567.floor(5)   #=> 1.23456
846
 *
847
 *     34567.89.floor(-5)  #=> 0
848
 *     34567.89.floor(-4)  #=> 30000
849
 *     34567.89.floor(-3)  #=> 34000
850
 *     34567.89.floor(-2)  #=> 34500
851
 *     34567.89.floor(-1)  #=> 34560
852
 *     34567.89.floor(0)   #=> 34567
853
 *     34567.89.floor(1)   #=> 34567.8
854
 *     34567.89.floor(2)   #=> 34567.89
855
 *     34567.89.floor(3)   #=> 34567.89
856
 *
857
 *  Note that the limited precision of floating-point arithmetic
858
 *  might lead to surprising results:
859
 *
860
 *     (0.3 / 0.1).floor  #=> 2 (!)
861
 */
862
static mrb_value
863
flo_floor(mrb_state *mrb, mrb_value num)
864
0
{
865
0
  return flo_rounding(mrb, num, floor);
866
0
}
867
868
/* 15.2.9.3.8 */
869
/*
870
 *  call-seq:
871
 *     float.ceil([ndigits])  ->  integer or float
872
 *
873
 *  Returns the smallest number greater than or equal to `float` with
874
 *  a precision of `ndigits` decimal digits (default: 0).
875
 *
876
 *  When the precision is negative, the returned value is an integer
877
 *  with at least `ndigits.abs` trailing zeros.
878
 *
879
 *  Returns a floating-point number when `ndigits` is positive,
880
 *  otherwise returns an integer.
881
 *
882
 *     1.2.ceil      #=> 2
883
 *     2.0.ceil      #=> 2
884
 *     (-1.2).ceil   #=> -1
885
 *     (-2.0).ceil   #=> -2
886
 *
887
 *     1.234567.ceil(2)   #=> 1.24
888
 *     1.234567.ceil(3)   #=> 1.235
889
 *     1.234567.ceil(4)   #=> 1.2346
890
 *     1.234567.ceil(5)   #=> 1.23457
891
 *
892
 *     34567.89.ceil(-5)  #=> 100000
893
 *     34567.89.ceil(-4)  #=> 40000
894
 *     34567.89.ceil(-3)  #=> 35000
895
 *     34567.89.ceil(-2)  #=> 34600
896
 *     34567.89.ceil(-1)  #=> 34570
897
 *     34567.89.ceil(0)   #=> 34568
898
 *     34567.89.ceil(1)   #=> 34567.9
899
 *     34567.89.ceil(2)   #=> 34567.89
900
 *     34567.89.ceil(3)   #=> 34567.89
901
 *
902
 *  Note that the limited precision of floating-point arithmetic
903
 *  might lead to surprising results:
904
 *
905
 *     (2.1 / 0.7).ceil  #=> 4 (!)
906
 */
907
908
static mrb_value
909
flo_ceil(mrb_state *mrb, mrb_value num)
910
0
{
911
0
  return flo_rounding(mrb, num, ceil);
912
0
}
913
914
/* 15.2.9.3.12 */
915
/*
916
 *  call-seq:
917
 *     flt.round([ndigits])  ->  integer or float
918
 *
919
 *  Rounds *flt* to a given precision in decimal digits (default 0 digits).
920
 *  Precision may be negative.  Returns a floating-point number when ndigits
921
 *  is more than zero.
922
 *
923
 *     1.4.round      #=> 1
924
 *     1.5.round      #=> 2
925
 *     1.6.round      #=> 2
926
 *     (-1.5).round   #=> -2
927
 *
928
 *     1.234567.round(2)  #=> 1.23
929
 *     1.234567.round(3)  #=> 1.235
930
 *     1.234567.round(4)  #=> 1.2346
931
 *     1.234567.round(5)  #=> 1.23457
932
 *
933
 *     34567.89.round(-5) #=> 0
934
 *     34567.89.round(-4) #=> 30000
935
 *     34567.89.round(-3) #=> 35000
936
 *     34567.89.round(-2) #=> 34600
937
 *     34567.89.round(-1) #=> 34570
938
 *     34567.89.round(0)  #=> 34568
939
 *     34567.89.round(1)  #=> 34567.9
940
 *     34567.89.round(2)  #=> 34567.89
941
 *     34567.89.round(3)  #=> 34567.89
942
 *
943
 */
944
945
static mrb_value
946
flo_round(mrb_state *mrb, mrb_value num)
947
6
{
948
6
  double number, f;
949
6
  mrb_int ndigits = 0;
950
6
  mrb_int i;
951
952
6
  mrb_get_args(mrb, "|i", &ndigits);
953
6
  number = mrb_float(num);
954
955
6
  if (0 < ndigits && (isinf(number) || isnan(number))) {
956
0
    return num;
957
0
  }
958
6
  mrb_check_num_exact(mrb, number);
959
960
6
  f = 1.0;
961
6
  if (ndigits < -DBL_DIG-2) return mrb_fixnum_value(0);
962
6
  i = ndigits >= 0 ? ndigits : -ndigits;
963
6
  if (ndigits > DBL_DIG+2) return num;
964
102
  while  (--i >= 0)
965
96
    f = f*10.0;
966
967
6
  if (isinf(f)) {
968
0
    if (ndigits < 0) number = 0;
969
0
  }
970
6
  else {
971
6
    double d;
972
973
6
    if (ndigits < 0) number /= f;
974
6
    else number *= f;
975
976
    /* home-made inline implementation of round(3) */
977
6
    if (number > 0.0) {
978
0
      d = floor(number);
979
0
      number = d + (number - d >= 0.5);
980
0
    }
981
6
    else if (number < 0.0) {
982
6
      d = ceil(number);
983
6
      number = d - (d - number >= 0.5);
984
6
    }
985
986
6
    if (ndigits < 0) number *= f;
987
6
    else number /= f;
988
6
  }
989
990
6
  if (ndigits > 0) {
991
6
    if (!isfinite(number)) return num;
992
6
    return mrb_float_value(mrb, number);
993
6
  }
994
0
  if (!FIXABLE_FLOAT(number))
995
0
    return mrb_float_value(mrb, number);
996
0
  return mrb_int_value(mrb, (mrb_int)number);
997
0
}
998
999
/* 15.2.9.3.14 */
1000
static mrb_value
1001
flo_to_i(mrb_state *mrb, mrb_value num)
1002
235
{
1003
235
  mrb_float f = mrb_float(num);
1004
1005
235
  mrb_check_num_exact(mrb, f);
1006
235
  if (!FIXABLE_FLOAT(f)) {
1007
0
#ifdef MRB_USE_BIGINT
1008
0
    return mrb_bint_new_float(mrb, f);
1009
#else
1010
    mrb_int_overflow(mrb, "to_f");
1011
#endif
1012
0
  }
1013
235
  if (f > 0.0) f = floor(f);
1014
235
  if (f < 0.0) f = ceil(f);
1015
1016
235
  return mrb_int_value(mrb, (mrb_int)f);
1017
235
}
1018
1019
/* 15.2.9.3.15 */
1020
/*
1021
 *  call-seq:
1022
 *     flt.to_i      ->  integer
1023
 *     flt.truncate  ->  integer
1024
 *
1025
 *  Returns *flt* truncated to an `Integer`.
1026
 */
1027
1028
static mrb_value
1029
flo_truncate(mrb_state *mrb, mrb_value num)
1030
0
{
1031
0
  if (signbit(mrb_float(num))) return flo_ceil(mrb, num);
1032
0
  return flo_floor(mrb, num);
1033
0
}
1034
1035
static mrb_value
1036
flo_nan_p(mrb_state *mrb, mrb_value num)
1037
0
{
1038
0
  return mrb_bool_value(isnan(mrb_float(num)));
1039
0
}
1040
1041
static mrb_value
1042
flo_abs(mrb_state *mrb, mrb_value num)
1043
0
{
1044
0
  mrb_float f = mrb_float(num);
1045
1046
0
  if (signbit(f)) return mrb_float_value(mrb, -f);
1047
0
  return num;
1048
0
}
1049
#endif
1050
1051
/*
1052
 * Document-class: Integer
1053
 *
1054
 *  `Integer` is hold whole numbers.
1055
 *
1056
 */
1057
1058
/* 15.2.9.3.24 */
1059
/*
1060
 *  Document-method: Integer#to_i
1061
 *  Document-method: Integer#to_int
1062
 *
1063
 *  call-seq:
1064
 *     int.to_i      ->  integer
1065
 *     int.to_int    ->  integer
1066
 *
1067
 *  As *int* is already an `Integer`, all these
1068
 *  methods simply return the receiver.
1069
 */
1070
1071
/**
1072
 * Multiplies two mrb_values, x and y, where x is expected to be an integer.
1073
 * y can be an integer, BigInt, Rational, Complex, or Float. The function
1074
 * handles type promotion and dispatches to appropriate handlers
1075
 * (e.g., mrb_bint_mul for BigInts).
1076
 *
1077
 * @param mrb The mruby state.
1078
 * @param x The first operand (integer).
1079
 * @param y The second operand (can be various numeric types).
1080
 * @return An mrb_value representing the product. The type of the result
1081
 *         depends on the types of the inputs and the magnitude of the result
1082
 *         (e.g., could be Integer, BigInt, Float, Rational, Complex).
1083
 * Handles potential integer overflows by promoting to BigInt if MRB_USE_BIGINT
1084
 * is defined, or raising RangeError otherwise.
1085
 * If y is not a recognized numeric type, it raises E_TYPE_ERROR.
1086
 */
1087
mrb_value
1088
mrb_int_mul(mrb_state *mrb, mrb_value x, mrb_value y)
1089
5.08k
{
1090
5.08k
  mrb_int a;
1091
1092
5.08k
  a = mrb_integer(x);
1093
5.08k
  if (mrb_integer_p(y)) {
1094
2.11k
    mrb_int b, c;
1095
1096
2.11k
    if (a == 0) return x;
1097
2.11k
    if (a == 1) return y;
1098
2.11k
    b = mrb_integer(y);
1099
2.11k
    if (b == 0) return y;
1100
2.11k
    if (b == 1) return x;
1101
0
    if (mrb_int_mul_overflow(a, b, &c)) {
1102
0
#ifdef MRB_USE_BIGINT
1103
0
      x = mrb_bint_new_int(mrb, a);
1104
0
      return mrb_bint_mul(mrb, x, y);
1105
#else
1106
      mrb_int_overflow(mrb, "multiplication");
1107
#endif
1108
0
    }
1109
0
    return mrb_int_value(mrb, c);
1110
0
  }
1111
2.96k
  switch (mrb_type(y)) {
1112
0
#ifdef MRB_USE_BIGINT
1113
2.95k
  case MRB_TT_BIGINT:
1114
2.95k
    if (a == 0) return x;
1115
2.57k
    if (a == 1) return y;
1116
1.85k
    return mrb_bint_mul(mrb, y, x);
1117
0
#endif
1118
0
#ifdef MRB_USE_RATIONAL
1119
3
  case MRB_TT_RATIONAL:
1120
3
    if (a == 0) return x;
1121
3
    if (a == 1) return y;
1122
3
    return mrb_rational_mul(mrb, y, x);
1123
0
#endif
1124
0
#ifdef MRB_USE_COMPLEX
1125
3
  case MRB_TT_COMPLEX:
1126
3
    if (a == 0) return x;
1127
3
    if (a == 1) return y;
1128
3
    return mrb_complex_mul(mrb, y, x);
1129
0
#endif
1130
0
#ifndef MRB_NO_FLOAT
1131
0
  case MRB_TT_FLOAT:
1132
0
    return mrb_float_value(mrb, (mrb_float)a * mrb_as_float(mrb, y));
1133
0
#endif
1134
5
  default:
1135
5
    mrb_int_noconv(mrb, y);
1136
2.96k
  }
1137
2.96k
}
1138
1139
/* 15.2.8.3.5 */
1140
/*
1141
 * call-seq:
1142
 *   int * numeric  ->  numeric_result
1143
 *
1144
 * Performs multiplication: the class of the resulting object depends on
1145
 * the class of `numeric` and on the magnitude of the
1146
 * result.
1147
 */
1148
1149
static mrb_value
1150
int_mul(mrb_state *mrb, mrb_value x)
1151
14.6k
{
1152
14.6k
  mrb_value y = mrb_get_arg1(mrb);
1153
1154
14.6k
#ifdef MRB_USE_BIGINT
1155
14.6k
  if (mrb_bigint_p(x)) {
1156
9.55k
    return mrb_bint_mul(mrb, x, y);
1157
9.55k
  }
1158
5.08k
#endif
1159
5.08k
  return mrb_int_mul(mrb, x, y);
1160
14.6k
}
1161
1162
static void
1163
intdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp)
1164
0
{
1165
0
  if (y == 0) {
1166
0
    mrb_int_zerodiv(mrb);
1167
0
  }
1168
0
  else if (x == MRB_INT_MIN && y == -1) {
1169
0
    mrb_int_overflow(mrb, "division");
1170
0
  }
1171
0
  else {
1172
0
    mrb_int div = x / y;
1173
0
    mrb_int mod = x - div * y;
1174
1175
0
    if ((x ^ y) < 0 && x != div * y) {
1176
0
      mod += y;
1177
0
      div -= 1;
1178
0
    }
1179
0
    if (divp) *divp = div;
1180
0
    if (modp) *modp = mod;
1181
0
  }
1182
0
}
1183
1184
/* 15.2.8.3.7 */
1185
/*
1186
 *  call-seq:
1187
 *    int % num        ->  num
1188
 *
1189
 *  Returns `int` modulo `other`.
1190
 *  See `numeric.divmod` for more information.
1191
 */
1192
1193
static mrb_value
1194
int_mod(mrb_state *mrb, mrb_value x)
1195
6.07k
{
1196
6.07k
  mrb_value y = mrb_get_arg1(mrb);
1197
6.07k
  mrb_int a, b;
1198
1199
6.07k
#ifdef MRB_USE_BIGINT
1200
6.07k
  if (mrb_bigint_p(x)) {
1201
2.37k
    return mrb_bint_mod(mrb, x, y);
1202
2.37k
  }
1203
3.70k
  if (mrb_bigint_p(y)) {
1204
1.14k
    return mrb_bint_mod(mrb, mrb_as_bint(mrb, x), y);
1205
1.14k
  }
1206
2.55k
#endif
1207
2.55k
  a = mrb_integer(x);
1208
2.55k
  if (a == 0) return x;
1209
2.35k
  if (mrb_integer_p(y)) {
1210
574
    b = mrb_integer(y);
1211
574
    if (b == 0) mrb_int_zerodiv(mrb);
1212
570
    if (a == MRB_INT_MIN && b == -1) return mrb_fixnum_value(0);
1213
570
    mrb_int mod = a % b;
1214
570
    if ((a < 0) != (b < 0) && mod != 0) {
1215
115
      mod += b;
1216
115
    }
1217
570
    return mrb_int_value(mrb, mod);
1218
570
  }
1219
#ifdef MRB_NO_FLOAT
1220
  mrb_raise(mrb, E_TYPE_ERROR, "non integer modulo");
1221
#else
1222
1.77k
  mrb_float mod;
1223
1224
1.77k
  flodivmod(mrb, (mrb_float)a, mrb_as_float(mrb, y), NULL, &mod);
1225
1.77k
  return mrb_float_value(mrb, mod);
1226
2.35k
#endif
1227
2.35k
}
1228
1229
#ifndef MRB_NO_FLOAT
1230
static mrb_value flo_divmod(mrb_state *mrb, mrb_value x);
1231
#endif
1232
1233
/*
1234
 *  call-seq:
1235
 *     int.divmod(numeric)  ->  array
1236
 *
1237
 *  See `Numeric#divmod`.
1238
 */
1239
static mrb_value
1240
int_divmod(mrb_state *mrb, mrb_value x)
1241
0
{
1242
0
  mrb_value y = mrb_get_arg1(mrb);
1243
1244
0
#ifdef MRB_USE_BIGINT
1245
0
  if (mrb_bigint_p(x)) {
1246
0
#ifndef MRB_NO_FLOAT
1247
0
    if (mrb_float_p(y)) {
1248
0
      mrb_float f = mrb_bint_as_float(mrb, x);
1249
0
      return flo_divmod(mrb, mrb_float_value(mrb, f));
1250
0
    }
1251
0
#endif
1252
0
    return mrb_bint_divmod(mrb, x, y);
1253
0
  }
1254
0
  if (mrb_bigint_p(y)) {
1255
0
    return mrb_bint_divmod(mrb, mrb_as_bint(mrb, x), y);
1256
0
  }
1257
0
#endif
1258
0
  if (mrb_integer_p(y)) {
1259
0
    mrb_int div, mod;
1260
1261
0
    intdivmod(mrb, mrb_integer(x), mrb_integer(y), &div, &mod);
1262
0
    return mrb_assoc_new(mrb, mrb_int_value(mrb, div), mrb_int_value(mrb, mod));
1263
0
  }
1264
#ifdef MRB_NO_FLOAT
1265
  mrb_raise(mrb, E_TYPE_ERROR, "non integer divmod");
1266
#else
1267
0
  return flo_divmod(mrb, x);
1268
0
#endif
1269
0
}
1270
1271
#ifndef MRB_NO_FLOAT
1272
static mrb_value
1273
flo_divmod(mrb_state *mrb, mrb_value x)
1274
0
{
1275
0
  mrb_value y = mrb_get_arg1(mrb);
1276
0
  mrb_float div, mod;
1277
0
  mrb_value a, b;
1278
1279
0
  flodivmod(mrb, mrb_float(x), mrb_as_float(mrb, y), &div, &mod);
1280
0
  if (!FIXABLE_FLOAT(div))
1281
0
    a = mrb_float_value(mrb, div);
1282
0
  else
1283
0
    a = mrb_int_value(mrb, (mrb_int)div);
1284
0
  b = mrb_float_value(mrb, mod);
1285
0
  return mrb_assoc_new(mrb, a, b);
1286
0
}
1287
#endif
1288
1289
/* 15.2.8.3.2 */
1290
/*
1291
 * call-seq:
1292
 *   int == other  ->  true or false
1293
 *
1294
 * Return `true` if `int` equals `other`
1295
 * numerically.
1296
 *
1297
 *   1 == 2      #=> false
1298
 *   1 == 1.0    #=> true
1299
 */
1300
1301
static mrb_value
1302
int_equal(mrb_state *mrb, mrb_value x)
1303
24.3k
{
1304
24.3k
  mrb_value y = mrb_get_arg1(mrb);
1305
1306
24.3k
  switch (mrb_type(y)) {
1307
24.0k
  case MRB_TT_INTEGER:
1308
24.0k
    return mrb_bool_value(mrb_integer(x) == mrb_integer(y));
1309
0
#ifndef MRB_NO_FLOAT
1310
0
  case MRB_TT_FLOAT:
1311
0
    return mrb_bool_value((mrb_float)mrb_integer(x) == mrb_float(y));
1312
0
#endif
1313
0
#ifdef MRB_USE_BIGINT
1314
46
  case MRB_TT_BIGINT:
1315
46
    return mrb_bool_value(mrb_bint_cmp(mrb, y, x) == 0);
1316
0
#endif
1317
0
#ifdef MRB_USE_RATIONAL
1318
0
  case MRB_TT_RATIONAL:
1319
0
    return mrb_bool_value(mrb_equal(mrb, y, x));
1320
0
#endif
1321
0
#ifdef MRB_USE_COMPLEX
1322
0
  case MRB_TT_COMPLEX:
1323
0
    return mrb_bool_value(mrb_equal(mrb, y, x));
1324
0
#endif
1325
264
  default:
1326
264
    return mrb_false_value();
1327
24.3k
  }
1328
24.3k
}
1329
1330
/* 15.2.8.3.8 */
1331
/*
1332
 * call-seq:
1333
 *   ~int  ->  integer
1334
 *
1335
 * One's complement: returns a number where each bit is flipped.
1336
 *   ex.0---00001 (1)-> 1---11110 (-2)
1337
 *   ex.0---00010 (2)-> 1---11101 (-3)
1338
 *   ex.0---00100 (4)-> 1---11011 (-5)
1339
 */
1340
1341
static mrb_value
1342
int_rev(mrb_state *mrb, mrb_value num)
1343
0
{
1344
0
#ifdef MRB_USE_BIGINT
1345
0
  if (mrb_bigint_p(num)) {
1346
0
    return mrb_bint_rev(mrb, num);
1347
0
  }
1348
0
#endif
1349
0
  mrb_int val = mrb_integer(num);
1350
0
  return mrb_int_value(mrb, ~val);
1351
0
}
1352
1353
4.29k
#define bit_op(x,y,op1,op2) do {\
1354
4.29k
  return mrb_int_value(mrb, (mrb_integer(x) op2 mrb_integer(y)));\
1355
4.29k
} while(0)
1356
1357
/* 15.2.8.3.9 */
1358
/*
1359
 * call-seq:
1360
 *   int & integer  ->  integer_result
1361
 *
1362
 * Bitwise AND.
1363
 */
1364
1365
static mrb_value
1366
int_and(mrb_state *mrb, mrb_value x)
1367
1.96k
{
1368
1.96k
  mrb_value y = mrb_get_arg1(mrb);
1369
1370
1.96k
#ifdef MRB_USE_BIGINT
1371
1.96k
  if (mrb_bigint_p(x)) {
1372
0
    return mrb_bint_and(mrb, x, y);
1373
0
  }
1374
1.96k
  if (mrb_bigint_p(y)) {
1375
10
    return mrb_bint_and(mrb, mrb_as_bint(mrb, x), y);
1376
10
  }
1377
1.95k
#endif
1378
1.95k
  bit_op(x, y, and, &);
1379
1.95k
}
1380
1381
/* 15.2.8.3.10 */
1382
/*
1383
 * call-seq:
1384
 *   int | integer  ->  integer_result
1385
 *
1386
 * Bitwise OR.
1387
 */
1388
1389
static mrb_value
1390
int_or(mrb_state *mrb, mrb_value x)
1391
60
{
1392
60
  mrb_value y = mrb_get_arg1(mrb);
1393
1394
60
#ifdef MRB_USE_BIGINT
1395
60
  if (mrb_bigint_p(x)) {
1396
52
    return mrb_bint_or(mrb, x, y);
1397
52
  }
1398
8
  if (mrb_bigint_p(y)) {
1399
2
    return mrb_bint_or(mrb, mrb_as_bint(mrb, x), y);
1400
2
  }
1401
6
#endif
1402
6
  bit_op(x, y, or, |);
1403
6
}
1404
1405
/* 15.2.8.3.11 */
1406
/*
1407
 * call-seq:
1408
 *   int ^ integer  ->  integer_result
1409
 *
1410
 * Bitwise EXCLUSIVE OR.
1411
 */
1412
1413
static mrb_value
1414
int_xor(mrb_state *mrb, mrb_value x)
1415
4.82k
{
1416
4.82k
  mrb_value y = mrb_get_arg1(mrb);
1417
1418
4.82k
#ifdef MRB_USE_BIGINT
1419
4.82k
  if (mrb_bigint_p(x)) {
1420
1.78k
    return mrb_bint_xor(mrb, x, y);
1421
1.78k
  }
1422
3.03k
  if (mrb_bigint_p(y)) {
1423
700
    return mrb_bint_xor(mrb, mrb_as_bint(mrb, x), y);
1424
700
  }
1425
2.33k
#endif
1426
2.33k
  bit_op(x, y, xor, ^);
1427
2.33k
}
1428
1429
5.27k
#define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1)
1430
1431
/**
1432
 * Performs a bitwise shift operation (left or right) on an mrb_int value
1433
 * (val) by width positions.
1434
 *
1435
 * @param mrb The mruby state (though not directly used in the function
1436
 *            logic, it's often part of MRB_API signatures).
1437
 * @param val The integer value to be shifted.
1438
 * @param width The number of positions to shift. Positive for left shift,
1439
 *              negative for right shift.
1440
 * @param num A pointer to an mrb_int where the result of the shift will be
1441
 *            stored.
1442
 * @return An mrb_bool indicating whether the shift was successful.
1443
 *         - TRUE if the shift was performed without overflow.
1444
 *         - FALSE if the shift would result in an overflow (e.g., shifting
1445
 *           a large positive number too far left, or a negative number
1446
 *           too far left).
1447
 * Special handling for right shifts of negative numbers (arithmetic shift)
1448
 * and large shift widths.
1449
 */
1450
mrb_bool
1451
mrb_num_shift(mrb_state *mrb, mrb_int val, mrb_int width, mrb_int *num)
1452
4.85k
{
1453
4.85k
  if (width < 0) {              /* rshift */
1454
2.21k
    if (width == MRB_INT_MIN || -width >= NUMERIC_SHIFT_WIDTH_MAX) {
1455
199
      if (val < 0) {
1456
69
        *num = -1;
1457
69
      }
1458
130
      else {
1459
130
        *num = 0;
1460
130
      }
1461
199
    }
1462
2.01k
    else {
1463
2.01k
      *num = val >> -width;
1464
2.01k
    }
1465
2.21k
  }
1466
2.63k
  else if (val > 0) {
1467
2.08k
    if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
1468
2.08k
        (val   > (MRB_INT_MAX >> width))) {
1469
359
      return FALSE;
1470
359
    }
1471
1.72k
    *num = val << width;
1472
1.72k
  }
1473
553
  else {
1474
553
    if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
1475
553
        (val   < (MRB_INT_MIN >> width))) {
1476
130
      return FALSE;
1477
130
    }
1478
423
    if (width == NUMERIC_SHIFT_WIDTH_MAX)
1479
130
      *num = MRB_INT_MIN;
1480
293
    else
1481
293
      *num = val * ((mrb_int)1 << width);
1482
423
  }
1483
4.36k
  return TRUE;
1484
4.85k
}
1485
1486
/* 15.2.8.3.12 */
1487
/*
1488
 * call-seq:
1489
 *   int << count  ->  integer or float
1490
 *
1491
 * Shifts _int_ left _count_ positions (right if _count_ is negative).
1492
 */
1493
1494
static mrb_value
1495
int_lshift(mrb_state *mrb, mrb_value x)
1496
269
{
1497
269
  mrb_int width, val;
1498
1499
269
  width = mrb_as_int(mrb, mrb_get_arg1(mrb));
1500
269
  if (width == 0) {
1501
1
    return x;
1502
1
  }
1503
268
  if (width == MRB_INT_MIN) mrb_int_overflow(mrb, "bit shift");
1504
268
#ifdef MRB_USE_BIGINT
1505
268
  if (mrb_bigint_p(x)) {
1506
18
    return mrb_bint_lshift(mrb, x, width);
1507
18
  }
1508
250
#endif
1509
250
  val = mrb_integer(x);
1510
250
  if (val == 0) return x;
1511
50
  if (!mrb_num_shift(mrb, val, width, &val)) {
1512
48
#ifdef MRB_USE_BIGINT
1513
48
    return mrb_bint_lshift(mrb, mrb_bint_new_int(mrb, val), width);
1514
#else
1515
    mrb_int_overflow(mrb, "bit shift");
1516
#endif
1517
48
  }
1518
2
  return mrb_int_value(mrb, val);
1519
50
}
1520
1521
/* 15.2.8.3.13 */
1522
/*
1523
 * call-seq:
1524
 *   int >> count  ->  integer or float
1525
 *
1526
 * Shifts _int_ right _count_ positions (left if _count_ is negative).
1527
 */
1528
1529
static mrb_value
1530
int_rshift(mrb_state *mrb, mrb_value x)
1531
1.13k
{
1532
1.13k
  mrb_int width, val;
1533
1534
1.13k
  width = mrb_as_int(mrb, mrb_get_arg1(mrb));
1535
1.13k
  if (width == 0) {
1536
217
    return x;
1537
217
  }
1538
920
  if (width == MRB_INT_MIN) mrb_int_overflow(mrb, "bit shift");
1539
920
#ifdef MRB_USE_BIGINT
1540
920
  if (mrb_bigint_p(x)) {
1541
272
    return mrb_bint_rshift(mrb, x, width);
1542
272
  }
1543
648
#endif
1544
648
  val = mrb_integer(x);
1545
648
  if (val == 0) return x;
1546
542
  if (!mrb_num_shift(mrb, val, -width, &val)) {
1547
203
#ifdef MRB_USE_BIGINT
1548
203
    return mrb_bint_rshift(mrb, mrb_bint_new_int(mrb, val), width);
1549
#else
1550
    mrb_int_overflow(mrb, "bit shift");
1551
#endif
1552
203
  }
1553
339
  return mrb_int_value(mrb, val);
1554
542
}
1555
1556
static mrb_value
1557
prepare_int_rounding(mrb_state *mrb, mrb_value x)
1558
2
{
1559
2
  mrb_int nd = 0;
1560
2
  size_t bytes;
1561
1562
2
  mrb_get_args(mrb, "|i", &nd);
1563
2
  if (nd >= 0) {
1564
0
    return mrb_nil_value();
1565
0
  }
1566
2
#ifdef MRB_USE_BIGINT
1567
2
  if (mrb_bigint_p(x)) {
1568
0
    bytes = mrb_bint_memsize(x);
1569
0
  }
1570
2
  else
1571
2
#endif
1572
2
    bytes = sizeof(mrb_int);
1573
2
  if (-0.415241 * nd - 0.125 > bytes) {
1574
2
    return mrb_undef_value();
1575
2
  }
1576
0
  return mrb_int_pow(mrb, mrb_fixnum_value(10), mrb_fixnum_value(-nd));
1577
2
}
1578
1579
/* 15.2.8.3.14 Integer#ceil */
1580
/*
1581
 *  call-seq:
1582
 *     int.ceil          ->  int
1583
 *     int.ceil(ndigits) ->  int
1584
 *
1585
 *  Returns self.
1586
 *
1587
 *  When the precision (ndigits) is negative, the returned value is an integer
1588
 *  with at least `ndigits.abs` trailing zeros.
1589
 */
1590
static mrb_value
1591
int_ceil(mrb_state *mrb, mrb_value x)
1592
2
{
1593
2
  mrb_value f = prepare_int_rounding(mrb, x);
1594
2
  if (mrb_undef_p(f)) return mrb_fixnum_value(0);
1595
0
  if (mrb_nil_p(f)) return x;
1596
0
#ifdef MRB_USE_BIGINT
1597
0
  if (mrb_bigint_p(x)) {
1598
0
    x = mrb_bint_add_n(mrb, x, f);
1599
0
    return mrb_bint_sub(mrb, x, mrb_bint_mod(mrb, x, f));
1600
0
  }
1601
0
#endif
1602
0
  mrb_int a = mrb_integer(x);
1603
0
  mrb_int b = mrb_integer(f);
1604
0
  mrb_int c = a % b;
1605
0
  int neg = a < 0;
1606
0
  a -= c;
1607
0
  if (!neg) {
1608
0
    if (mrb_int_add_overflow(a, b, &c)) {
1609
0
#ifdef MRB_USE_BIGINT
1610
0
      x = mrb_bint_new_int(mrb, a);
1611
0
      return mrb_bint_add(mrb, x, f);
1612
#else
1613
      mrb_int_overflow(mrb, "ceil");
1614
#endif
1615
0
    }
1616
0
    a = c;
1617
0
  }
1618
0
  return mrb_int_value(mrb, a);
1619
0
}
1620
1621
/* 15.2.8.3.17 Integer#floor */
1622
/*
1623
 *  call-seq:
1624
 *     int.floor          ->  int
1625
 *     int.floor(ndigits) ->  int
1626
 *
1627
 *  Returns self.
1628
 *
1629
 *  When the precision (ndigits) is negative, the returned value is an integer
1630
 *  with at least `ndigits.abs` trailing zeros.
1631
 */
1632
static mrb_value
1633
int_floor(mrb_state *mrb, mrb_value x)
1634
0
{
1635
0
  mrb_value f = prepare_int_rounding(mrb, x);
1636
0
  if (mrb_undef_p(f)) return mrb_fixnum_value(0);
1637
0
  if (mrb_nil_p(f)) return x;
1638
0
#ifdef MRB_USE_BIGINT
1639
0
  if (mrb_bigint_p(x)) {
1640
0
    return mrb_bint_sub(mrb, x, mrb_bint_mod(mrb, x, f));
1641
0
  }
1642
0
#endif
1643
0
  mrb_int a = mrb_integer(x);
1644
0
  mrb_int b = mrb_integer(f);
1645
0
  mrb_int c = a % b;
1646
0
  int neg = a < 0;
1647
0
  a -= c;
1648
0
  if (neg) {
1649
0
    if (mrb_int_sub_overflow(a, b, &c)) {
1650
0
#ifdef MRB_USE_BIGINT
1651
0
      x = mrb_bint_new_int(mrb, a);
1652
0
      return mrb_bint_sub(mrb, x, f);
1653
#else
1654
      mrb_int_overflow(mrb, "floor");
1655
#endif
1656
0
    }
1657
0
    a = c;
1658
0
  }
1659
0
  return mrb_int_value(mrb, a);
1660
0
}
1661
1662
/* 15.2.8.3.20 Integer#round */
1663
/*
1664
 *  call-seq:
1665
 *     int.round          ->  int
1666
 *     int.round(ndigits) ->  int
1667
 *
1668
 *  Returns self.
1669
 *
1670
 *  When the precision (ndigits) is negative, the returned value is an integer
1671
 *  with at least `ndigits.abs` trailing zeros.
1672
 */
1673
static mrb_value
1674
int_round(mrb_state *mrb, mrb_value x)
1675
0
{
1676
0
  mrb_value f = prepare_int_rounding(mrb, x);
1677
0
  if (mrb_undef_p(f)) return mrb_fixnum_value(0);
1678
0
  if (mrb_nil_p(f)) return x;
1679
0
#ifdef MRB_USE_BIGINT
1680
0
  if (mrb_bigint_p(x)) {
1681
0
    mrb_value r = mrb_bint_mod(mrb, x, f);
1682
0
    mrb_value n = mrb_bint_sub(mrb, x, r);
1683
0
    mrb_value h = mrb_bigint_p(f) ? mrb_bint_rshift(mrb, f, 1) : mrb_int_value(mrb, mrb_integer(f)>>1);
1684
0
    mrb_int cmp = mrb_bigint_p(r) ? mrb_bint_cmp(mrb, r, h) : (mrb_bigint_p(h) ? -mrb_bint_cmp(mrb, h, r) : (mrb_integer(r)-mrb_integer(h)));
1685
0
    if ((cmp > 0) || (cmp == 0 && mrb_bint_cmp(mrb, x, mrb_fixnum_value(0)) > 0)) {
1686
0
      n = mrb_as_bint(mrb, n);
1687
0
      n = mrb_bint_add(mrb, n, f);
1688
0
    }
1689
0
    return n;
1690
0
  }
1691
0
#endif
1692
0
  mrb_int a = mrb_integer(x);
1693
0
  mrb_int b = mrb_integer(f);
1694
0
  mrb_int c = a % b;
1695
0
  a -= c;
1696
0
  if (c < 0) {
1697
0
    c = -c;
1698
0
    if (b/2 < c) {
1699
0
      if (mrb_int_sub_overflow(a, b, &c)) {
1700
0
#ifdef MRB_USE_BIGINT
1701
0
        x = mrb_bint_new_int(mrb, a);
1702
0
        return mrb_bint_sub(mrb, x, f);
1703
#else
1704
        mrb_int_overflow(mrb, "round");
1705
#endif
1706
0
      }
1707
0
    }
1708
0
    a = c;
1709
0
  }
1710
0
  else {
1711
0
    if (b/2 < c) {
1712
0
      if (mrb_int_add_overflow(a, b, &c)) {
1713
0
#ifdef MRB_USE_BIGINT
1714
0
        x = mrb_bint_new_int(mrb, a);
1715
0
        return mrb_bint_add(mrb, x, f);
1716
#else
1717
        mrb_int_overflow(mrb, "round");
1718
#endif
1719
0
      }
1720
0
    }
1721
0
    a = c;
1722
0
  }
1723
0
  return mrb_int_value(mrb, a);
1724
0
}
1725
1726
/* 15.2.8.3.26 Integer#truncate */
1727
/*
1728
 *  call-seq:
1729
 *     int.truncate          ->  int
1730
 *     int.truncate(ndigits) ->  int
1731
 *
1732
 *  Returns self.
1733
 *
1734
 *  When the precision (ndigits) is negative, the returned value is an integer
1735
 *  with at least `ndigits.abs` trailing zeros.
1736
 */
1737
static mrb_value
1738
int_truncate(mrb_state *mrb, mrb_value x)
1739
0
{
1740
0
  mrb_value f = prepare_int_rounding(mrb, x);
1741
0
  if (mrb_undef_p(f)) return mrb_fixnum_value(0);
1742
0
  if (mrb_nil_p(f)) return x;
1743
0
#ifdef MRB_USE_BIGINT
1744
0
  if (mrb_bigint_p(x)) {
1745
0
    mrb_value m = mrb_bint_mod(mrb, x, f);
1746
0
    x = mrb_bint_sub_n(mrb, x, m);
1747
0
    if (mrb_bint_cmp(mrb, x, mrb_fixnum_value(0)) < 0) {
1748
0
      return mrb_bint_add(mrb, x, f);
1749
0
    }
1750
0
    return x;
1751
0
  }
1752
0
#endif
1753
0
  mrb_int a = mrb_integer(x);
1754
0
  mrb_int b = mrb_integer(f);
1755
0
  return mrb_int_value(mrb, a - (a % b));
1756
0
}
1757
1758
/* 15.2.8.3.23 */
1759
/*
1760
 *  call-seq:
1761
 *     int.to_f  ->  float
1762
 *
1763
 *  Converts *int* to a `Float`.
1764
 *
1765
 */
1766
1767
#ifndef MRB_NO_FLOAT
1768
static mrb_value
1769
int_to_f(mrb_state *mrb, mrb_value num)
1770
0
{
1771
0
#ifdef MRB_USE_BIGINT
1772
0
  if (mrb_bigint_p(num)) {
1773
0
    return mrb_float_value(mrb, mrb_bint_as_float(mrb, num));
1774
0
  }
1775
0
#endif
1776
0
  return mrb_float_value(mrb, (mrb_float)mrb_integer(num));
1777
0
}
1778
1779
/**
1780
 * Converts an mrb_value float to an mrb_value integer.
1781
 *
1782
 * @param mrb The mruby state.
1783
 * @param x The float mrb_value to convert.
1784
 * @return An mrb_value integer if the conversion is successful.
1785
 * @raise E_TYPE_ERROR if the input is not a float.
1786
 * @raise E_RANGE_ERROR if the float is Infinity or NaN.
1787
 */
1788
MRB_API mrb_value
1789
mrb_float_to_integer(mrb_state *mrb, mrb_value x)
1790
235
{
1791
235
  if (!mrb_float_p(x)) {
1792
0
    mrb_raise(mrb, E_TYPE_ERROR, "non float value");
1793
0
  }
1794
235
  mrb_float f = mrb_float(x);
1795
235
  if (isinf(f) || isnan(f)) {
1796
0
    mrb_raisef(mrb, E_RANGE_ERROR, "float %f out of range", f);
1797
0
  }
1798
235
  return flo_to_i(mrb, x);
1799
235
}
1800
#endif
1801
1802
/**
1803
 * Adds two mrb_values, x and y, where x is expected to be an integer.
1804
 * y can be an integer, BigInt, Rational, Complex, or Float. The function
1805
 * handles type promotion and dispatches to appropriate handlers.
1806
 *
1807
 * @param mrb The mruby state.
1808
 * @param x The first operand (integer).
1809
 * @param y The second operand (can be various numeric types).
1810
 * @return An mrb_value representing the sum. The type of the result depends
1811
 *         on the types of the inputs and the magnitude of the result.
1812
 * Handles potential integer overflows by promoting to BigInt if MRB_USE_BIGINT
1813
 * is defined, or raising RangeError otherwise.
1814
 * If y is not a recognized numeric type and MRB_NO_FLOAT is defined, it
1815
 * raises E_TYPE_ERROR. If MRB_NO_FLOAT is not defined, it attempts to
1816
 * convert y to a float.
1817
 */
1818
mrb_value
1819
mrb_int_add(mrb_state *mrb, mrb_value x, mrb_value y)
1820
18.6k
{
1821
18.6k
  mrb_int a;
1822
1823
18.6k
  a = mrb_integer(x);
1824
18.6k
  if (mrb_integer_p(y)) {
1825
1.09k
    mrb_int b, c;
1826
1827
1.09k
    if (a == 0) return y;
1828
0
    b = mrb_integer(y);
1829
0
    if (b == 0) return x;
1830
0
    if (mrb_int_add_overflow(a, b, &c)) {
1831
0
#ifdef MRB_USE_BIGINT
1832
0
      x = mrb_bint_new_int(mrb, a);
1833
0
      return mrb_bint_add(mrb, x, y);
1834
#else
1835
      mrb_int_overflow(mrb, "addition");
1836
#endif
1837
0
    }
1838
0
    return mrb_int_value(mrb, c);
1839
0
  }
1840
17.5k
  switch (mrb_type(y)) {
1841
0
#ifdef MRB_USE_BIGINT
1842
1.72k
  case MRB_TT_BIGINT:
1843
1.72k
    return mrb_bint_add(mrb, y, x);
1844
0
#endif
1845
0
#ifdef MRB_USE_RATIONAL
1846
6
  case MRB_TT_RATIONAL:
1847
6
    return mrb_rational_add(mrb, y, x);
1848
0
#endif
1849
0
#ifdef MRB_USE_COMPLEX
1850
15.7k
  case MRB_TT_COMPLEX:
1851
15.7k
    return mrb_complex_add(mrb, y, x);
1852
0
#endif
1853
7
  default:
1854
#ifdef MRB_NO_FLOAT
1855
    mrb_raise(mrb, E_TYPE_ERROR, "non integer addition");
1856
#else
1857
7
    return mrb_float_value(mrb, (mrb_float)a + mrb_as_float(mrb, y));
1858
17.5k
#endif
1859
17.5k
  }
1860
17.5k
}
1861
1862
/* 15.2.8.3.3 */
1863
/*
1864
 * call-seq:
1865
 *   int + numeric  ->  numeric_result
1866
 *
1867
 * Performs addition: the class of the resulting object depends on
1868
 * the class of `numeric` and on the magnitude of the
1869
 * result.
1870
 */
1871
static mrb_value
1872
int_add(mrb_state *mrb, mrb_value self)
1873
21.3k
{
1874
21.3k
  mrb_value other = mrb_get_arg1(mrb);
1875
1876
21.3k
#ifdef MRB_USE_BIGINT
1877
21.3k
  if (mrb_bigint_p(self)) {
1878
2.77k
    return mrb_bint_add(mrb, self, other);
1879
2.77k
  }
1880
18.6k
#endif
1881
18.6k
  return mrb_int_add(mrb, self, other);
1882
21.3k
}
1883
1884
/**
1885
 * Subtracts mrb_value y from mrb_value x, where x is expected to be an
1886
 * integer. y can be an integer, BigInt, Rational, Complex, or Float.
1887
 * The function handles type promotion and dispatches to appropriate handlers.
1888
 *
1889
 * @param mrb The mruby state.
1890
 * @param x The minuend (integer).
1891
 * @param y The subtrahend (can be various numeric types).
1892
 * @return An mrb_value representing the difference. The type of the result
1893
 *         depends on the types of the inputs and the magnitude of the result.
1894
 * Handles potential integer overflows by promoting to BigInt if MRB_USE_BIGINT
1895
 * is defined, or raising RangeError otherwise.
1896
 * If y is not a recognized numeric type and MRB_NO_FLOAT is defined, it
1897
 * raises E_TYPE_ERROR. If MRB_NO_FLOAT is not defined, it attempts to
1898
 * convert y to a float.
1899
 */
1900
mrb_value
1901
mrb_int_sub(mrb_state *mrb, mrb_value x, mrb_value y)
1902
2.42k
{
1903
2.42k
  mrb_int a;
1904
1905
2.42k
  a = mrb_integer(x);
1906
2.42k
  if (mrb_integer_p(y)) {
1907
0
    mrb_int b, c;
1908
1909
0
    b = mrb_integer(y);
1910
0
    if (mrb_int_sub_overflow(a, b, &c)) {
1911
0
#ifdef MRB_USE_BIGINT
1912
0
      x = mrb_bint_new_int(mrb, a);
1913
0
      return mrb_bint_sub(mrb, x, y);
1914
#else
1915
      mrb_int_overflow(mrb, "subtraction");
1916
#endif
1917
0
    }
1918
0
    return mrb_int_value(mrb, c);
1919
0
  }
1920
2.42k
  switch (mrb_type(y)) {
1921
0
#ifdef MRB_USE_BIGINT
1922
2.41k
  case MRB_TT_BIGINT:
1923
2.41k
    return mrb_bint_sub(mrb, mrb_bint_new_int(mrb, a), y);
1924
0
#endif
1925
0
#ifdef MRB_USE_RATIONAL
1926
6
  case MRB_TT_RATIONAL:
1927
6
    return mrb_rational_sub(mrb, mrb_rational_new(mrb, a, 1), y);
1928
0
#endif
1929
0
#ifdef MRB_USE_COMPLEX
1930
0
  case MRB_TT_COMPLEX:
1931
0
    return mrb_complex_sub(mrb, mrb_complex_new(mrb, (mrb_float)a, 0), y);
1932
0
#endif
1933
5
  default:
1934
#ifdef MRB_NO_FLOAT
1935
    mrb_raise(mrb, E_TYPE_ERROR, "non integer subtraction");
1936
#else
1937
5
    return mrb_float_value(mrb, (mrb_float)a - mrb_as_float(mrb, y));
1938
2.42k
#endif
1939
2.42k
  }
1940
2.42k
}
1941
1942
/* 15.2.8.3.4 */
1943
/*
1944
 * call-seq:
1945
 *   int - numeric  ->  numeric
1946
 *
1947
 * Performs subtraction: the class of the resulting object depends on
1948
 * the class of `numeric` and on the magnitude of the
1949
 * result.
1950
 */
1951
static mrb_value
1952
int_sub(mrb_state *mrb, mrb_value self)
1953
9.81k
{
1954
9.81k
  mrb_value other = mrb_get_arg1(mrb);
1955
1956
9.81k
#ifdef MRB_USE_BIGINT
1957
9.81k
  if (mrb_bigint_p(self)) {
1958
7.39k
    return mrb_bint_sub(mrb, self, other);
1959
7.39k
  }
1960
2.42k
#endif
1961
2.42k
  return mrb_int_sub(mrb, self, other);
1962
9.81k
}
1963
1964
/**
1965
 * Converts an mrb_int to a C-style string.
1966
 *
1967
 * @param buf The buffer to write the string to.
1968
 * @param len The size of the buffer.
1969
 * @param n The integer to convert.
1970
 * @param base The radix for conversion (2-36).
1971
 * @return A pointer to the beginning of the string in the buffer,
1972
 *         or NULL if an error occurs (e.g., invalid base, buffer too small).
1973
 */
1974
MRB_API char*
1975
mrb_int_to_cstr(char *buf, size_t len, mrb_int n, mrb_int base)
1976
60.8k
{
1977
60.8k
  char *bufend = buf + len;
1978
60.8k
  char *b = bufend-1;
1979
1980
60.8k
  if (base < 2 || 36 < base) return NULL;
1981
60.8k
  if (len < 2) return NULL;
1982
1983
60.8k
  if (n == 0) {
1984
677
    buf[0] = '0';
1985
677
    buf[1] = '\0';
1986
677
    return buf;
1987
677
  }
1988
1989
60.2k
  *b = '\0';
1990
60.2k
  if (n < 0) {
1991
34
    do {
1992
34
      if (b-- == buf) return NULL;
1993
34
      *b = mrb_digitmap[-(n % base)];
1994
34
    } while (n /= base);
1995
14
    if (b-- == buf) return NULL;
1996
14
    *b = '-';
1997
14
  }
1998
60.2k
  else {
1999
141k
    do {
2000
141k
      if (b-- == buf) return NULL;
2001
141k
      *b = mrb_digitmap[(int)(n % base)];
2002
141k
    } while (n /= base);
2003
60.2k
  }
2004
60.2k
  return b;
2005
60.2k
}
2006
2007
/**
2008
 * Converts an mrb_value representing an integer to a new mrb_value string.
2009
 *
2010
 * @param mrb The mruby state.
2011
 * @param x The integer mrb_value to convert.
2012
 * @param base The radix for conversion (2-36).
2013
 * @return A new mrb_value string representing the integer,
2014
 *         or raises an E_ARGUMENT_ERROR if the base is invalid.
2015
 */
2016
MRB_API mrb_value
2017
mrb_integer_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
2018
60.8k
{
2019
60.8k
  char buf[MRB_INT_BIT+1];
2020
2021
60.8k
  if (base < 2 || 36 < base) {
2022
0
    mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base);
2023
0
  }
2024
60.8k
#ifdef MRB_USE_BIGINT
2025
60.8k
  if (mrb_bigint_p(x)) {
2026
2
    return mrb_bint_to_s(mrb, x, base);
2027
2
  }
2028
60.8k
#endif
2029
60.8k
  mrb_int val = mrb_integer(x);
2030
60.8k
  const char *p = mrb_int_to_cstr(buf, sizeof(buf), val, base);
2031
60.8k
  mrb_assert(p != NULL);
2032
60.8k
  mrb_value str = mrb_str_new_cstr(mrb, p);
2033
60.8k
  RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
2034
60.8k
  return str;
2035
60.8k
}
2036
2037
/* 15.2.8.3.25 */
2038
/*
2039
 *  call-seq:
2040
 *     int.to_s(base=10)  ->  string
2041
 *
2042
 *  Returns a string containing the representation of *int* radix
2043
 *  *base* (between 2 and 36).
2044
 *
2045
 *     12345.to_s       #=> "12345"
2046
 *     12345.to_s(2)    #=> "11000000111001"
2047
 *     12345.to_s(8)    #=> "30071"
2048
 *     12345.to_s(10)   #=> "12345"
2049
 *     12345.to_s(16)   #=> "3039"
2050
 *     12345.to_s(36)   #=> "9ix"
2051
 *
2052
 */
2053
static mrb_value
2054
int_to_s(mrb_state *mrb, mrb_value self)
2055
42.6k
{
2056
42.6k
  mrb_int base;
2057
2058
42.6k
  if (mrb_get_argc(mrb) > 0) {
2059
0
    base = mrb_integer(mrb_get_arg1(mrb));
2060
0
  }
2061
42.6k
  else {
2062
42.6k
    base = 10;
2063
42.6k
  }
2064
42.6k
  return mrb_integer_to_str(mrb, self, base);
2065
42.6k
}
2066
2067
/* compare two numbers: (1:0:-1; -2 for error) */
2068
static mrb_int
2069
cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2)
2070
8.61k
{
2071
#ifdef MRB_NO_FLOAT             /* integer version */
2072
2073
  if (!mrb_fixnum_p(v2)) {
2074
    if (!mrb_obj_is_kind_of(mrb, v2, mrb_class_get_id(mrb, MRB_SYM(Numeric)))) {
2075
      return -2;
2076
    }
2077
    v1 = mrb_funcall_argv(mrb, v2, MRB_OPSYM(cmp), 1, &v1);
2078
    if (mrb_integer_p(v1)) {
2079
      return -mrb_integer(v1);
2080
    }
2081
    return -2;
2082
  }
2083
  mrb_int x = mrb_as_int(mrb, v1);
2084
  mrb_int y = mrb_integer(v2);
2085
2086
#else                           /* float version */
2087
2088
8.61k
  mrb_float x, y;
2089
2090
8.61k
  if (mrb_fixnum_p(v1)) {
2091
6.87k
    if (mrb_fixnum_p(v2)) {
2092
4.21k
      mrb_int x = mrb_integer(v1);
2093
4.21k
      mrb_int y = mrb_integer(v2);
2094
2095
4.21k
      if (x > y) return 1;
2096
4.20k
      else if (x < y) return -1;
2097
2.10k
      return 0;
2098
4.21k
    }
2099
2.65k
    x = (mrb_float)mrb_integer(v1);
2100
2.65k
  }
2101
1.73k
  else {
2102
1.73k
    x = mrb_as_float(mrb, v1);
2103
1.73k
  }
2104
2105
4.39k
  switch (mrb_type(v2)) {
2106
0
#ifdef MRB_USE_RATIONAL
2107
396
  case MRB_TT_RATIONAL:
2108
396
#endif
2109
396
#ifdef MRB_USE_BIGINT
2110
1.33k
  case MRB_TT_BIGINT:
2111
1.33k
#endif
2112
1.89k
  case MRB_TT_INTEGER:
2113
1.89k
    if (mrb_fixnum_p(v2)) {
2114
559
      y = (mrb_float)mrb_integer(v2);
2115
559
      break;
2116
559
    }
2117
    /* fall through */
2118
1.61k
  case MRB_TT_FLOAT:
2119
1.61k
    y = mrb_as_float(mrb, v2);
2120
1.61k
    break;
2121
2.22k
  default:
2122
2.22k
    if (!mrb_obj_is_kind_of(mrb, v2, mrb_class_get_id(mrb, MRB_SYM(Numeric)))) {
2123
2.22k
      return -2;
2124
2.22k
    }
2125
    /* fall through */
2126
0
#ifdef MRB_USE_COMPLEX
2127
0
  case MRB_TT_COMPLEX:
2128
0
#endif
2129
0
    v1 = mrb_funcall_argv(mrb, v2, MRB_OPSYM(cmp), 1, &v1);
2130
0
    if (mrb_fixnum_p(v1)) {
2131
0
      return -mrb_integer(v1);
2132
0
    }
2133
0
    return -2;
2134
4.39k
  }
2135
2.17k
#endif
2136
2.17k
  if (x > y)
2137
395
    return 1;
2138
1.78k
  else if (x < y)
2139
909
    return -1;
2140
871
  return 0;
2141
2.17k
}
2142
2143
static mrb_value
2144
int_hash(mrb_state *mrb, mrb_value self)
2145
4.83k
{
2146
4.83k
#ifdef MRB_USE_BIGINT
2147
4.83k
  if (mrb_bigint_p(self)) {
2148
0
    return mrb_bint_hash(mrb, self);
2149
0
  }
2150
4.83k
#endif
2151
4.83k
  mrb_int n = mrb_integer(self);
2152
4.83k
  return mrb_int_value(mrb, mrb_byte_hash((uint8_t*)&n, sizeof(n)));
2153
4.83k
}
2154
2155
/* 15.2.8.3.1 */
2156
/* 15.2.9.3.1 */
2157
/*
2158
 * call-seq:
2159
 *     self.f <=> other.f    => -1, 0, +1, or nil
2160
 *             <  => -1
2161
 *             =  =>  0
2162
 *             >  => +1
2163
 *  Comparison---Returns -1, 0, or +1 depending on whether *int* is
2164
 *  less than, equal to, or greater than *numeric*. This is the
2165
 *  basis for the tests in `Comparable`. When the operands are
2166
 *  not comparable, it returns nil instead of raising an exception.
2167
 */
2168
static mrb_value
2169
num_cmp(mrb_state *mrb, mrb_value self)
2170
2.23k
{
2171
2.23k
  mrb_value other = mrb_get_arg1(mrb);
2172
2.23k
  mrb_int n;
2173
2174
2.23k
  n = cmpnum(mrb, self, other);
2175
2.23k
  if (n == -2) return mrb_nil_value();
2176
15
  return mrb_fixnum_value(n);
2177
2.23k
}
2178
2179
static mrb_noreturn void
2180
cmperr(mrb_state *mrb, mrb_value v1, mrb_value v2)
2181
6
{
2182
6
  mrb_raisef(mrb, E_ARGUMENT_ERROR, "comparison of %t with %t failed", v1, v2);
2183
6
}
2184
2185
static mrb_value
2186
num_lt(mrb_state *mrb, mrb_value self)
2187
416
{
2188
416
  mrb_value other = mrb_get_arg1(mrb);
2189
416
  mrb_int n;
2190
2191
416
  n = cmpnum(mrb, self, other);
2192
416
  if (n == -2) cmperr(mrb, self, other);
2193
416
  if (n < 0) return mrb_true_value();
2194
18
  return mrb_false_value();
2195
416
}
2196
2197
static mrb_value
2198
num_le(mrb_state *mrb, mrb_value self)
2199
874
{
2200
874
  mrb_value other = mrb_get_arg1(mrb);
2201
874
  mrb_int n;
2202
2203
874
  n = cmpnum(mrb, self, other);
2204
874
  if (n == -2) cmperr(mrb, self, other);
2205
868
  if (n <= 0) return mrb_true_value();
2206
85
  return mrb_false_value();
2207
868
}
2208
2209
static mrb_value
2210
num_gt(mrb_state *mrb, mrb_value self)
2211
16
{
2212
16
  mrb_value other = mrb_get_arg1(mrb);
2213
16
  mrb_int n;
2214
2215
16
  n = cmpnum(mrb, self, other);
2216
16
  if (n == -2) cmperr(mrb, self, other);
2217
16
  if (n > 0) return mrb_true_value();
2218
7
  return mrb_false_value();
2219
16
}
2220
2221
static mrb_value
2222
num_ge(mrb_state *mrb, mrb_value self)
2223
875
{
2224
875
  mrb_value other = mrb_get_arg1(mrb);
2225
875
  mrb_int n;
2226
2227
875
  n = cmpnum(mrb, self, other);
2228
875
  if (n == -2) cmperr(mrb, self, other);
2229
875
  if (n >= 0) return mrb_true_value();
2230
462
  return mrb_false_value();
2231
875
}
2232
2233
/**
2234
 * Compares two mrb_value objects (obj1 and obj2).
2235
 *
2236
 * @param mrb The mruby state.
2237
 * @param obj1 The first object.
2238
 * @param obj2 The second object.
2239
 * @return An mrb_int indicating the comparison result:
2240
 *         - 0 if obj1 is equal to obj2.
2241
 *         - 1 if obj1 is greater than obj2.
2242
 *         - -1 if obj1 is less than obj2.
2243
 *         - -2 if the objects are not comparable (error).
2244
 * It handles comparisons for integers, floats, bigints, and strings directly.
2245
 * For other types, it attempts to call the <=> (spaceship) operator on obj1
2246
 * with obj2 as an argument.
2247
 */
2248
MRB_API mrb_int
2249
mrb_cmp(mrb_state *mrb, mrb_value obj1, mrb_value obj2)
2250
5.88M
{
2251
5.88M
  mrb_value v;
2252
2253
5.88M
  if (mrb_fixnum_p(obj1) || mrb_float_p(obj1)) {
2254
4.20k
    return cmpnum(mrb, obj1, obj2);
2255
4.20k
  }
2256
5.87M
  switch (mrb_type(obj1)) {
2257
0
  case MRB_TT_INTEGER:
2258
0
  case MRB_TT_FLOAT:
2259
0
  case MRB_TT_BIGINT:
2260
0
    return cmpnum(mrb, obj1, obj2);
2261
0
  case MRB_TT_STRING:
2262
0
    if (!mrb_string_p(obj2))
2263
0
      return -2;
2264
0
    return mrb_str_cmp(mrb, obj1, obj2);
2265
5.87M
  default:
2266
5.87M
    v = mrb_funcall_argv(mrb, obj1, MRB_OPSYM(cmp), 1, &obj2);
2267
5.87M
    if (mrb_nil_p(v) || !mrb_integer_p(v))
2268
192
      return -2;
2269
5.87M
    return mrb_integer(v);
2270
5.87M
  }
2271
5.87M
}
2272
2273
static mrb_value
2274
num_finite_p(mrb_state *mrb, mrb_value self)
2275
0
{
2276
0
  return mrb_true_value();
2277
0
}
2278
2279
static mrb_value
2280
num_infinite_p(mrb_state *mrb, mrb_value self)
2281
0
{
2282
0
  return mrb_false_value();
2283
0
}
2284
2285
#ifndef MRB_NO_FLOAT
2286
static mrb_value
2287
flo_hash(mrb_state *mrb, mrb_value flo)
2288
0
{
2289
0
  mrb_float f = mrb_float(flo);
2290
  /* normalize -0.0 to 0.0 */
2291
0
  if (f == 0) f = 0.0;
2292
0
  return mrb_int_value(mrb, (mrb_int)mrb_byte_hash((uint8_t*)&f, sizeof(f)));
2293
0
}
2294
#endif
2295
2296
/* ------------------------------------------------------------------------*/
2297
void
2298
mrb_init_numeric(mrb_state *mrb)
2299
784
{
2300
784
  struct RClass *numeric, *integer;
2301
784
#ifndef MRB_NO_FLOAT
2302
784
  struct RClass *fl;
2303
784
#endif
2304
2305
  /* Numeric Class */
2306
784
  numeric = mrb_define_class_id(mrb, MRB_SYM(Numeric), mrb->object_class);                  /* 15.2.7 */
2307
784
  mrb_define_method_id(mrb, numeric, MRB_SYM_Q(finite),  num_finite_p,    MRB_ARGS_NONE());
2308
784
  mrb_define_method_id(mrb, numeric, MRB_SYM_Q(infinite),num_infinite_p,  MRB_ARGS_NONE());
2309
784
  mrb_define_method_id(mrb, numeric, MRB_SYM_Q(eql),     num_eql,         MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
2310
784
#ifndef MRB_NO_FLOAT
2311
784
  mrb_define_method_id(mrb, numeric, MRB_SYM(fdiv),      num_fdiv,        MRB_ARGS_REQ(1));
2312
784
#endif
2313
2314
  /* Integer Class */
2315
784
  mrb->integer_class = integer = mrb_define_class_id(mrb, MRB_SYM(Integer),  numeric);     /* 15.2.8 */
2316
784
  MRB_SET_INSTANCE_TT(integer, MRB_TT_INTEGER);
2317
784
  MRB_UNDEF_ALLOCATOR(integer);
2318
784
  mrb_undef_class_method_id(mrb, integer, MRB_SYM(new));
2319
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(pow),    int_pow,         MRB_ARGS_REQ(1));
2320
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(cmp),    num_cmp,         MRB_ARGS_REQ(1)); /* 15.2.8.3.1  */
2321
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(lt),     num_lt,          MRB_ARGS_REQ(1));
2322
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(le),     num_le,          MRB_ARGS_REQ(1));
2323
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(gt),     num_gt,          MRB_ARGS_REQ(1));
2324
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(ge),     num_ge,          MRB_ARGS_REQ(1));
2325
2326
784
  mrb_define_method_id(mrb, integer, MRB_SYM(to_i),     mrb_obj_itself,  MRB_ARGS_NONE()); /* 15.2.8.3.24 */
2327
784
  mrb_define_method_id(mrb, integer, MRB_SYM(to_int),   mrb_obj_itself,  MRB_ARGS_NONE());
2328
2329
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(add),    int_add,         MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
2330
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(sub),    int_sub,         MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */
2331
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(mul),    int_mul,         MRB_ARGS_REQ(1)); /* 15.2.8.3.3 */
2332
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(mod),    int_mod,         MRB_ARGS_REQ(1)); /* 15.2.8.3.5 */
2333
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(div),    int_div,         MRB_ARGS_REQ(1)); /* 15.2.8.3.6 */
2334
784
  mrb_define_method_id(mrb, integer, MRB_SYM(quo),      int_quo,         MRB_ARGS_REQ(1)); /* 15.2.7.4.5(x) */
2335
784
  mrb_define_method_id(mrb, integer, MRB_SYM(div),      int_idiv,        MRB_ARGS_REQ(1));
2336
784
#ifndef MRB_NO_FLOAT
2337
784
  mrb_define_method_id(mrb, integer, MRB_SYM(fdiv),     int_fdiv,        MRB_ARGS_REQ(1));
2338
784
#endif
2339
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(eq),     int_equal,       MRB_ARGS_REQ(1)); /* 15.2.8.3.7 */
2340
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(neg),    int_rev,         MRB_ARGS_NONE()); /* 15.2.8.3.8 */
2341
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(and),    int_and,         MRB_ARGS_REQ(1)); /* 15.2.8.3.9 */
2342
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(or),     int_or,          MRB_ARGS_REQ(1)); /* 15.2.8.3.10 */
2343
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(xor),    int_xor,         MRB_ARGS_REQ(1)); /* 15.2.8.3.11 */
2344
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(lshift), int_lshift,      MRB_ARGS_REQ(1)); /* 15.2.8.3.12 */
2345
784
  mrb_define_method_id(mrb, integer, MRB_OPSYM(rshift), int_rshift,      MRB_ARGS_REQ(1)); /* 15.2.8.3.13 */
2346
784
  mrb_define_method_id(mrb, integer, MRB_SYM(ceil),     int_ceil,        MRB_ARGS_OPT(1)); /* 15.2.8.3.14 */
2347
784
  mrb_define_method_id(mrb, integer, MRB_SYM(floor),    int_floor,       MRB_ARGS_OPT(1)); /* 15.2.8.3.17 */
2348
784
  mrb_define_method_id(mrb, integer, MRB_SYM(round),    int_round,       MRB_ARGS_OPT(1)); /* 15.2.8.3.20 */
2349
784
  mrb_define_method_id(mrb, integer, MRB_SYM(truncate), int_truncate,    MRB_ARGS_OPT(1)); /* 15.2.8.3.26 */
2350
784
  mrb_define_method_id(mrb, integer, MRB_SYM(hash),     int_hash,        MRB_ARGS_NONE()); /* 15.2.8.3.18 */
2351
784
#ifndef MRB_NO_FLOAT
2352
784
  mrb_define_method_id(mrb, integer, MRB_SYM(to_f),     int_to_f,        MRB_ARGS_NONE()); /* 15.2.8.3.23 */
2353
784
#endif
2354
784
  mrb_define_method_id(mrb, integer, MRB_SYM(to_s),     int_to_s,        MRB_ARGS_OPT(1)); /* 15.2.8.3.25 */
2355
784
  mrb_define_method_id(mrb, integer, MRB_SYM(inspect),  int_to_s,        MRB_ARGS_OPT(1));
2356
784
  mrb_define_method_id(mrb, integer, MRB_SYM(divmod),   int_divmod,      MRB_ARGS_REQ(1)); /* 15.2.8.3.30(x) */
2357
784
  mrb_define_method_id(mrb, integer, MRB_SYM(__coerce_step_counter), coerce_step_counter, MRB_ARGS_REQ(1));
2358
2359
  /* Fixnum Class for compatibility */
2360
784
  mrb_define_const_id(mrb, mrb->object_class, MRB_SYM(Fixnum), mrb_obj_value(integer));
2361
2362
784
#ifndef MRB_NO_FLOAT
2363
  /* Float Class */
2364
784
  mrb->float_class = fl = mrb_define_class_id(mrb, MRB_SYM(Float), numeric);               /* 15.2.9 */
2365
784
  MRB_SET_INSTANCE_TT(fl, MRB_TT_FLOAT);
2366
784
  MRB_UNDEF_ALLOCATOR(fl);
2367
784
  mrb_undef_class_method(mrb,  fl, "new");
2368
784
  mrb_define_method_id(mrb, fl,      MRB_OPSYM(pow),     flo_pow,        MRB_ARGS_REQ(1));
2369
784
  mrb_define_method_id(mrb, fl,      MRB_OPSYM(div),     flo_div,        MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */
2370
784
  mrb_define_method_id(mrb, fl,      MRB_SYM(quo),       flo_div,        MRB_ARGS_REQ(1)); /* 15.2.7.4.5(x) */
2371
784
  mrb_define_method_id(mrb, fl,      MRB_SYM(fdiv),      flo_div,        MRB_ARGS_REQ(1));
2372
784
  mrb_define_method_id(mrb, fl,      MRB_SYM(div),       flo_idiv,       MRB_ARGS_REQ(1));
2373
784
  mrb_define_method_id(mrb, fl,      MRB_OPSYM(add),     flo_add,        MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */
2374
784
  mrb_define_method_id(mrb, fl,      MRB_OPSYM(sub),     flo_sub,        MRB_ARGS_REQ(1)); /* 15.2.9.3.4 */
2375
784
  mrb_define_method_id(mrb, fl,      MRB_OPSYM(mul),     flo_mul,        MRB_ARGS_REQ(1)); /* 15.2.9.3.5 */
2376
784
  mrb_define_method_id(mrb, fl,      MRB_OPSYM(mod),     flo_mod,        MRB_ARGS_REQ(1)); /* 15.2.9.3.7 */
2377
784
  mrb_define_method_id(mrb, fl,      MRB_OPSYM(cmp),     num_cmp,        MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */
2378
784
  mrb_define_method_id(mrb, fl,      MRB_OPSYM(lt),      num_lt,         MRB_ARGS_REQ(1));
2379
784
  mrb_define_method_id(mrb, fl,      MRB_OPSYM(le),      num_le,         MRB_ARGS_REQ(1));
2380
784
  mrb_define_method_id(mrb, fl,      MRB_OPSYM(gt),      num_gt,         MRB_ARGS_REQ(1));
2381
784
  mrb_define_method_id(mrb, fl,      MRB_OPSYM(ge),      num_ge,         MRB_ARGS_REQ(1));
2382
784
  mrb_define_method_id(mrb, fl,      MRB_OPSYM(eq),      flo_eq,         MRB_ARGS_REQ(1)); /* 15.2.9.3.2  */
2383
784
  mrb_define_method_id(mrb, fl,      MRB_SYM(ceil),      flo_ceil,       MRB_ARGS_OPT(1)); /* 15.2.9.3.8  */
2384
784
  mrb_define_method_id(mrb, fl,      MRB_SYM_Q(finite),  flo_finite_p,   MRB_ARGS_NONE()); /* 15.2.9.3.9  */
2385
784
  mrb_define_method_id(mrb, fl,      MRB_SYM(floor),     flo_floor,      MRB_ARGS_OPT(1)); /* 15.2.9.3.10 */
2386
784
  mrb_define_method_id(mrb, fl,      MRB_SYM_Q(infinite),flo_infinite_p, MRB_ARGS_NONE()); /* 15.2.9.3.11 */
2387
784
  mrb_define_method_id(mrb, fl,      MRB_SYM(round),     flo_round,      MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */
2388
784
  mrb_define_method_id(mrb, fl,      MRB_SYM(to_f),      mrb_obj_itself, MRB_ARGS_NONE()); /* 15.2.9.3.13 */
2389
784
  mrb_define_method_id(mrb, fl,      MRB_SYM(to_i),      flo_to_i,       MRB_ARGS_NONE()); /* 15.2.9.3.14 */
2390
784
  mrb_define_method_id(mrb, fl,      MRB_SYM(truncate),  flo_truncate,   MRB_ARGS_OPT(1)); /* 15.2.9.3.15 */
2391
784
  mrb_define_method_id(mrb, fl,      MRB_SYM(divmod),    flo_divmod,     MRB_ARGS_REQ(1));
2392
2393
784
  mrb_define_method_id(mrb, fl,      MRB_SYM(to_s),      flo_to_s,       MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */
2394
784
  mrb_define_method_id(mrb, fl,      MRB_SYM(inspect),   flo_to_s,       MRB_ARGS_NONE());
2395
784
  mrb_define_method_id(mrb, fl,      MRB_SYM_Q(nan),     flo_nan_p,      MRB_ARGS_NONE());
2396
784
  mrb_define_method_id(mrb, fl,      MRB_SYM(abs),       flo_abs,        MRB_ARGS_NONE()); /* 15.2.7.4.3 */
2397
784
  mrb_define_method_id(mrb, fl,      MRB_SYM(hash),      flo_hash,       MRB_ARGS_NONE());
2398
2399
784
#ifdef INFINITY
2400
784
  mrb_define_const_id(mrb, fl, MRB_SYM(INFINITY), mrb_float_value(mrb, INFINITY));
2401
784
#endif
2402
784
#ifdef NAN
2403
784
  mrb_define_const_id(mrb, fl, MRB_SYM(NAN), mrb_float_value(mrb, NAN));
2404
784
#endif
2405
784
#endif
2406
784
}