src/bigint.c: implement multi-precision integer.

To enable multi-precision integer support, you need to link
`mruby-bigint` mrbgem. The gem itself is empty but it turns on
the "bigint" support.
This commit is contained in:
Yukihiro "Matz" Matsumoto
2022-04-07 16:45:21 +09:00
parent e3c20b7319
commit dcaf4083d5
17 changed files with 2065 additions and 41 deletions
+117
View File
@@ -0,0 +1,117 @@
/**
** @file mruby/bigint.h - Multi-precision, Integer
**
** See Copyright Notice in mruby.h
*/
#ifdef MRB_USE_BIGINT
#ifndef MRUBY_BIGINT_H
#define MRUBY_BIGINT_H
/*
* FREE GMP - a public domain implementation of a subset of the
* gmp library
*
* I hearby place the file in the public domain.
*
* Do whatever you want with this code. Change it. Sell it. Claim you
* wrote it.
* Bugs, complaints, flames, rants: please send email to
* Mark Henderson <markh@wimsey.bc.ca>
* I'm already aware that fgmp is considerably slower than gmp
*
* CREDITS:
* Paul Rouse <par@r-cube.demon.co.uk> - generic bug fixes, mpz_sqrt and
* mpz_sqrtrem, and modifications to get fgmp to compile on a system
* with int and long of different sizes (specifically MS-DOS,286 compiler)
* Also see the file "notes" included with the fgmp distribution, for
* more credits.
*
* VERSION 1.0 - beta 5
*/
#include <sys/types.h>
#ifdef MRB_32BIT
/*
* The values below are for 32 bit machines (i.e. machines with a
* 32 bit long type)
* You'll need to change them, if you're using something else
* If DIGITBITS is odd, see the comment at the top of mpz_sqrtrem
*/
typedef int32_t mp_limb;
#define LMAX 0x3fffffffL
#define LC 0xc0000000L
#define OVMASK 0x2
#define CMASK (LMAX+1)
#define HLMAX 0x7fffL
#define HCMASK (HLMAX + 1)
#define HIGH(x) (((x) & 0x3fff8000L) >> 15)
#define LOW(x) ((x) & 0x7fffL)
#else
/* 64 bit long type */
typedef int64_t mp_limb;
#define LMAX 0x3fffffffffffffffL
#define LC 0xc000000000000000L
#define OVMASK 0x2
#define CMASK (LMAX+1)
#define HLMAX 0x7fffffffL
#define HCMASK (HLMAX + 1)
#define HIGH(x) (((x) & 0x3fffffff80000000L) >> 31)
#define LOW(x) ((x) & 0x7fffffffL)
#endif
typedef struct _mpz_t {
mp_limb *p;
short sn;
size_t sz;
} mpz_t;
struct RBigint {
MRB_OBJECT_HEADER;
mpz_t mp;
};
#define RBIGINT(v) ((struct RBigint*)mrb_ptr(v))
#define iabs(x) ((x>0) ? (x) : (-x))
#define imax(x,y) ((x>y)?x:y)
#define LONGBITS (sizeof(mp_limb)*8)
#define DIGITBITS (LONGBITS-2)
#define HALFDIGITBITS ((LONGBITS-2)/2)
#define hd(x,i) (((size_t)(i)>=2*((x)->sz))? 0:(((i)%2) ? HIGH((x)->p[(i)/2]) \
: LOW((x)->p[(i)/2])))
#define dg(x,i) (((size_t)(i) < (x)->sz) ? ((x)->p)[i] : 0)
#define RBIGINT(v) ((struct RBigint*)mrb_ptr(v))
mrb_value mrb_bint_new_int(mrb_state *mrb, mrb_int x);
mrb_value mrb_bint_add(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_sub(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_mul(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_div(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_divmod(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_add_ii(mrb_state *mrb, mrb_int x, mrb_int y);
mrb_value mrb_bint_sub_ii(mrb_state *mrb, mrb_int x, mrb_int y);
mrb_value mrb_bint_mul_ii(mrb_state *mrb, mrb_int x, mrb_int y);
mrb_value mrb_bint_div_ii(mrb_state *mrb, mrb_int x, mrb_int y);
mrb_value mrb_bint_mod(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_rem(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_pow(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_powm(mrb_state *mrb, mrb_value x, mrb_int y, mrb_value z);
mrb_value mrb_bint_and(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_or(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_xor(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_rev(mrb_state *mrb, mrb_value x);
mrb_value mrb_bint_lshift(mrb_state *mrb, mrb_value x, mrb_int width);
mrb_value mrb_bint_rshift(mrb_state *mrb, mrb_value x, mrb_int width);
mrb_value mrb_bint_to_s(mrb_state *mrb, mrb_value x, mrb_int base);
#ifndef MRB_NO_FLOAT
mrb_float mrb_bint_as_float(mrb_state *mrb, mrb_value x);
#endif
mrb_int mrb_bint_as_int(mrb_state *mrb, mrb_value x);
mrb_int mrb_bint_cmp(mrb_state *mrb, mrb_value x, mrb_value y);
void mrb_gc_free_bint(mrb_state *mrb, struct RBasic *x);
#endif
#endif /* MRB_USE_BIGINT */
+34
View File
@@ -83,6 +83,8 @@ mrb_int mrb_div_int(mrb_state *mrb, mrb_int x, mrb_int y);
mrb_value mrb_int_add(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_int_sub(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_int_mul(mrb_state *mrb, mrb_value x, mrb_value y);
void mrb_int_zerodiv(mrb_state *mrb);
void mrb_int_overflow(mrb_state *mrb, const char *reason);
#ifdef MRB_USE_COMPLEX
mrb_value mrb_complex_new(mrb_state *mrb, mrb_float x, mrb_float y);
@@ -154,4 +156,36 @@ void mrb_gc_free_iv(mrb_state*, struct RObject*);
/* VM */
mrb_int mrb_ci_bidx(mrb_callinfo *ci);
#ifdef MRB_USE_BIGINT
mrb_value mrb_bint_new_int(mrb_state *mrb, mrb_int x);
mrb_value mrb_bint_new_str(mrb_state *mrb, const char *x, mrb_int len, mrb_int base);
mrb_value mrb_as_bint(mrb_state *mrb, mrb_value x);
mrb_value mrb_bint_add(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_sub(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_mul(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_div(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_divmod(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_add_ii(mrb_state *mrb, mrb_int x, mrb_int y);
mrb_value mrb_bint_sub_ii(mrb_state *mrb, mrb_int x, mrb_int y);
mrb_value mrb_bint_mul_ii(mrb_state *mrb, mrb_int x, mrb_int y);
mrb_value mrb_bint_div_ii(mrb_state *mrb, mrb_int x, mrb_int y);
mrb_value mrb_bint_mod(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_rem(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_pow(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_powm(mrb_state *mrb, mrb_value x, mrb_int y, mrb_value z);
mrb_value mrb_bint_and(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_or(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_xor(mrb_state *mrb, mrb_value x, mrb_value y);
mrb_value mrb_bint_rev(mrb_state *mrb, mrb_value x);
mrb_value mrb_bint_lshift(mrb_state *mrb, mrb_value x, mrb_int width);
mrb_value mrb_bint_rshift(mrb_state *mrb, mrb_value x, mrb_int width);
mrb_value mrb_bint_to_s(mrb_state *mrb, mrb_value x, mrb_int base);
#ifndef MRB_NO_FLOAT
mrb_float mrb_bint_as_float(mrb_state *mrb, mrb_value x);
#endif
mrb_int mrb_bint_as_int(mrb_state *mrb, mrb_value x);
mrb_int mrb_bint_cmp(mrb_state *mrb, mrb_value x, mrb_value y);
void mrb_gc_free_bint(mrb_state *mrb, struct RBasic *x);
#endif
#endif /* MRUBY_INTERNAL_H */
+5 -1
View File
@@ -154,7 +154,8 @@ static const unsigned int IEEE754_INFINITY_BITS_SINGLE = 0x7F800000;
f(MRB_TT_ISTRUCT, struct RIStruct, "istruct") \
f(MRB_TT_BREAK, struct RBreak, "break") \
f(MRB_TT_COMPLEX, struct RComplex, "Complex") \
f(MRB_TT_RATIONAL, struct RRational, "Rational")
f(MRB_TT_RATIONAL, struct RRational, "Rational") \
f(MRB_TT_BIGINT, struct RBigint, "Integer")
enum mrb_vtype {
#define MRB_VTYPE_DEFINE(tt, type, name) tt,
@@ -300,6 +301,9 @@ struct RCptr {
#define mrb_bool(o) (mrb_type(o) != MRB_TT_FALSE)
#endif
#define mrb_test(o) mrb_bool(o)
#ifndef mrb_bigint_p
#define mrb_bigint_p(o) (mrb_type(o) == MRB_TT_BIGINT)
#endif
/**
* Returns a float in Ruby.
+154
View File
@@ -0,0 +1,154 @@
# fgmp
FGMP is a public domain implementation of a subset of the GNU gmp library with the same API.
WELCOME TO FGMP.
FGMP is a public domain implementation of a subset of the GNU gmp library
with the same API.
For instance, you can link the following trivial program with either
this code, or libgmp.a and get the same results.
``` C
#include <stdio.h>
#include "gmp.h"
main()
{
MP_INT a; MP_INT b; MP_INT c;
mpz_init_set_ui(&a,1); mpz_init_set_ui(&b,2); mpz_init(&c);
mpz_add(&c,&a,&b);
printf("\n%s\n", mpz_get_str(NULL,10,&c));
}
```
FGMP is really in the public domain. You can do whatever you want with
it.
I wrote FGMP so that we would all have access to a (truly free)
implementation of this subset of the API of GNU libgmp. I encourage
everyone to distribute this as widely as possible.
If you need more documentation, I suggest you look at the file
gmp.texi which is included with the GNU gmp library.
You can send me bug reports, implementations of missing functions, flames
and rants by Email.
Any submissions of new code to be integrated into fgmp must also be
placed in the public domain (For the particularly dense, you can
release a new fgmp yourself under different licensing terms. This
is a condition for including a submission in a release of FGMP that
I personally prepare).
Mark Henderson <markh@wimsey.bc.ca>
# This is the fifth BETA release. 1.0b5
I hearby place this file and all of FGMP in the public domain.
Thanks to Paul Rouse <par@r-cube.demon.co.uk> for changes to get fgmp
to work on a 286 MS-DOS compiler, the functions mpz_sqrt and
mpz_sqrtrem, plus other general bug fixes.
Thanks also to Erick Gallesio <eg@kaolin.unice.fr> for a fix
to mpz_init_set_str
Define B64 if your "long" type is 64 bits. Otherwise we assume 32
bit longs. (The 64 bit version hasn't been tested enough)
```
Platforms:
Linux 0.99 (gcc)
IBM RS6000/AIX 3.2 (IBM xlc compiler and gcc 2.3)
Sun OS 4.1, Sun 3/4
DEC Alpha OSF/1 (only lightly tested, 64 bit longs do make a difference,
thanks to DEC for providing access via axposf.pa.dec.com). Define B64
for this platform
MS-DOS 286 C compiler (see credits above)
```
# Some differences between gmp and fgmp
1. fgmp is considerably slower than gmp
2. fgmp does not implement the following:
all mpq_*
internal mpn_* functions
mpz_perfect_square_p
mpz_inp_raw, mpz_out_raw
mp_set_memory_functions, mpz_out_str, mpz_inp_str
3. fgmp implements the following in addition to the routines in GNU gmp.
`int mpz_jacobi(MP_INT *a, MP_INT *b)`
- finds the jacobi symbol (a/b)
4. mpz_sizeinbase often overestimates the exact value
5. To convert your gmp based program to fgmp (subject to the
above)
- recompile your source. Make sure to include the gmp.h file included
with fgmp rather than that included with gmp. (The point is to recompile
all files which include gmp.h)
- link with gmp.o instead of libgmp.a
Here's a complete sorted list of function implemented in fgmp:
```
_mpz_realloc
mpz_abs
mpz_add
mpz_add_ui
mpz_and
mpz_clear
mpz_cmp
mpz_cmp_si
mpz_cmp_ui
mpz_div
mpz_div_2exp
mpz_div_ui
mpz_divmod
mpz_divmod_ui
mpz_fac_ui
mpz_gcd
mpz_gcdext
mpz_get_si
mpz_get_str
mpz_get_ui
mpz_init
mpz_init_set
mpz_init_set_si
mpz_init_set_str
mpz_init_set_ui
mpz_jacobi
mpz_mdiv
mpz_mdiv_ui
mpz_mdivmod
mpz_mdivmod_ui
mpz_mmod
mpz_mmod_ui
mpz_mod
mpz_mod_2exp
mpz_mod_ui
mpz_mul
mpz_mul_2exp
mpz_mul_ui
mpz_neg
mpz_or
mpz_pow_ui
mpz_powm
mpz_powm_ui
mpz_probab_prime_p
mpz_random
mpz_random2
mpz_set
mpz_set_si
mpz_set_str
mpz_set_ui
mpz_size
mpz_sizeinbase
mpz_sqrt
mpz_sqrtrem
mpz_sub
mpz_sub_ui
mpz_xor
```
+9
View File
@@ -0,0 +1,9 @@
# Multi-precision Integer extension for mruby
This extension uses fgmp, which is a public domain implementation of a subset of the GNU gmp library by Mark Henderson <markh@wimsey.bc.ca>
But it's heavily modified to fit with mruby. You can get the original source code from <https://github.com/deischi/fgmp.git>
You can read the original README for fgmp in <README-fgmp.md>
## Implementation
This mrbgem is only to turn on `MRB_USE_BIGINT` flag. The implementation resides in `include/mruby/bigint.h` and `src/bigint.c`.
+6
View File
@@ -0,0 +1,6 @@
MRuby::Gem::Specification.new('mruby-bigint') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'Integer class extension to multiple-precision'
spec.build.defines << "MRB_USE_BIGINT"
end
+69 -10
View File
@@ -1,9 +1,40 @@
#include <mruby.h>
#include <mruby/numeric.h>
#include <mruby/internal.h>
#include <mruby/presym.h>
void mrb_int_zerodiv(mrb_state *mrb);
void mrb_int_overflow(mrb_state *mrb, const char *reason);
#ifdef MRB_USE_BIGINT
#include <mruby/bigint.h>
static mrb_value
bint_allbits(mrb_state *mrb, mrb_value x, mrb_value y)
{
y = mrb_as_bint(mrb, y);
x = mrb_bint_and(mrb, x, y);
if (mrb_bint_cmp(mrb, x, y) == 0) return mrb_true_value();
return mrb_false_value();
}
static mrb_value
bint_anybits(mrb_state *mrb, mrb_value x, mrb_value y)
{
y = mrb_as_bint(mrb, y);
x = mrb_bint_and(mrb, x, y);
if (mrb_bint_cmp(mrb, x, mrb_fixnum_value(0)) != 0)
return mrb_true_value();
return mrb_false_value();
}
static mrb_value
bint_nobits(mrb_state *mrb, mrb_value x, mrb_value y)
{
y = mrb_as_bint(mrb, y);
x = mrb_bint_and(mrb, x, y);
if (mrb_bint_cmp(mrb, x, mrb_fixnum_value(0)) == 0)
return mrb_true_value();
return mrb_false_value();
}
#endif
/*
* call-seq:
@@ -14,6 +45,9 @@ void mrb_int_overflow(mrb_state *mrb, const char *reason);
static mrb_value
int_allbits(mrb_state *mrb, mrb_value self)
{
#ifdef MRB_USE_BIGINT
return bint_allbits(mrb, self, mrb_get_arg1(mrb));
#endif
mrb_int n, m;
mrb_get_args(mrb, "i", &m);
@@ -30,6 +64,9 @@ int_allbits(mrb_state *mrb, mrb_value self)
static mrb_value
int_anybits(mrb_state *mrb, mrb_value self)
{
#ifdef MRB_USE_BIGINT
return bint_anybits(mrb, self, mrb_get_arg1(mrb));
#endif
mrb_int n, m;
mrb_get_args(mrb, "i", &m);
@@ -46,6 +83,9 @@ int_anybits(mrb_state *mrb, mrb_value self)
static mrb_value
int_nobits(mrb_state *mrb, mrb_value self)
{
#ifdef MRB_USE_BIGINT
return bint_nobits(mrb, self, mrb_get_arg1(mrb));
#endif
mrb_int n, m;
mrb_get_args(mrb, "i", &m);
@@ -53,6 +93,10 @@ int_nobits(mrb_state *mrb, mrb_value self)
return mrb_bool_value((n & m) == 0);
}
#ifndef MRB_NO_FLOAT
static mrb_value flo_remainder(mrb_state *mrb, mrb_value self);
#endif
/*
* call-seq:
* num.remainder(numeric) -> real
@@ -67,6 +111,14 @@ int_remainder(mrb_state *mrb, mrb_value x)
mrb_value y = mrb_get_arg1(mrb);
mrb_int a, b;
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
if (mrb_integer_p(y) || mrb_bigint_p(y)) {
return mrb_bint_rem(mrb, x, y);
}
return flo_remainder(mrb, mrb_float_value(mrb, mrb_as_float(mrb, x)));
}
#endif
a = mrb_integer(x);
if (mrb_integer_p(y)) {
b = mrb_integer(y);
@@ -77,11 +129,7 @@ int_remainder(mrb_state *mrb, mrb_value x)
#ifdef MRB_NO_FLOAT
mrb_raise(mrb, E_TYPE_ERROR, "non integer remainder");
#else
mrb_float n = (mrb_float)a;
mrb_float m = mrb_as_float(mrb, y);
if (isinf(m)) return mrb_float_value(mrb, n);
return mrb_float_value(mrb, n-m*trunc(n/m));
return flo_remainder(mrb, mrb_float_value(mrb, mrb_as_float(mrb, x)));
#endif
}
@@ -100,14 +148,25 @@ mrb_value mrb_int_pow(mrb_state *mrb, mrb_value x);
static mrb_value
int_powm(mrb_state *mrb, mrb_value x)
{
mrb_value m;
mrb_int base, exp, mod, result = 1;
if (mrb_get_argc(mrb) == 1) {
return mrb_int_pow(mrb, x);
}
mrb_get_args(mrb, "ii", &exp, &mod);
if (exp < 0) mrb_raise(mrb, E_TYPE_ERROR, "int.pow(n,m): n must be positive");
if (mod < 0) mrb_raise(mrb, E_TYPE_ERROR, "int.pow(n,m): m must be positive");
mrb_get_args(mrb, "io", &exp, &m);
if (exp < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "int.pow(n,m): n must be positive");
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
return mrb_bint_powm(mrb, x, exp, m);
}
if (mrb_bigint_p(m)) {
return mrb_bint_powm(mrb, mrb_bint_new_int(mrb, mrb_integer(x)), exp, m);
}
#endif
if (!mrb_integer_p(m)) mrb_raise(mrb, E_TYPE_ERROR, "int.pow(n,m): m must be integer");
mod = mrb_integer(m);
if (mod < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "int.pow(n,m): m must be positive");
if (mod == 0) mrb_int_zerodiv(mrb);
if (mod == 1) return mrb_fixnum_value(0);
base = mrb_integer(x);
+9 -8
View File
@@ -128,23 +128,24 @@ os_memsize_of_object(mrb_state* mrb, mrb_value obj)
case MRB_TT_INTEGER:
if (mrb_immediate_p(obj))
break;
case MRB_TT_RATIONAL:
case MRB_TT_RATIONAL:
#if defined(MRB_USE_RATIONAL)
#if defined(MRB_INT64) && defined(MRB_32BIT)
size += sizeof(mrb_int)*2;
size += sizeof(mrb_int)*2;
#endif
size += mrb_objspace_page_slot_size();
size += mrb_objspace_page_slot_size();
#endif
break;
break;
case MRB_TT_COMPLEX:
case MRB_TT_COMPLEX:
#if defined(MRB_USE_COMPLEX)
#if defined(MRB_32BIT) && !defined(MRB_USE_FLOAT32)
size += sizeof(mrb_float)*2;
size += sizeof(mrb_float)*2;
#endif
size += mrb_objspace_page_slot_size();
size += mrb_objspace_page_slot_size();
#endif
break;
break;
case MRB_TT_BIGINT:
case MRB_TT_DATA:
case MRB_TT_ISTRUCT:
size += mrb_objspace_page_slot_size();
+1 -1
View File
@@ -847,7 +847,7 @@ ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len)
return mrb_ary_new_from_values(mrb, len, ARY_PTR(a)+beg);
}
ary_make_shared(mrb, a);
b = MRB_OBJ_ALLOC(mrb, MRB_TT_ARRAY, mrb->array_class);
b = MRB_OBJ_ALLOC(mrb, MRB_TT_ARRAY, mrb->array_class);
b->as.heap.ptr = a->as.heap.ptr + beg;
b->as.heap.len = len;
b->as.heap.aux.shared = a->as.heap.aux.shared;
+1410
View File
File diff suppressed because it is too large Load Diff
+7
View File
@@ -555,6 +555,7 @@ mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls)
ttype != MRB_TT_SCLASS &&
ttype != MRB_TT_ICLASS &&
ttype != MRB_TT_ENV &&
ttype != MRB_TT_BIGINT &&
ttype != tt) {
mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %C", cls);
}
@@ -909,6 +910,12 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end)
break;
#endif
#ifdef MRB_USE_BIGINT
case MRB_TT_BIGINT:
mrb_gc_free_bint(mrb, obj);
break;
#endif
default:
break;
}
+1 -1
View File
@@ -166,7 +166,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, const uint8_t *end, size_
pool_data_len = bin_to_uint8(src); /* pool data length */
src += sizeof(uint8_t);
if (src + pool_data_len > end) return FALSE;
{
{
char *p;
pool[i].tt = IREP_TT_BIGINT;
p = (char*)mrb_malloc(mrb, pool_data_len+2);
+171 -8
View File
@@ -45,6 +45,18 @@ mrb_int_zerodiv(mrb_state *mrb)
mrb_value
mrb_int_pow(mrb_state *mrb, mrb_value x)
{
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
mrb_value y = mrb_get_arg1(mrb);
#ifndef MRB_NO_FLOAT
if (mrb_float_p(y)) {
return mrb_float_value(mrb, pow(mrb_bint_as_float(mrb, x), mrb_float(y)));
}
#endif
return mrb_bint_pow(mrb, x, y);
}
#endif
mrb_int base = mrb_integer(x);
mrb_int result = 1;
mrb_int exp;
@@ -79,7 +91,11 @@ mrb_int_pow(mrb_state *mrb, mrb_value x)
exp >>= 1;
if (exp == 0) break;
if (mrb_int_mul_overflow(base, base, &base)) {
#ifdef MRB_USE_BIGINT
return mrb_bint_pow(mrb, mrb_bint_new_int(mrb, mrb_integer(x)), y);
#else
mrb_int_overflow(mrb, "power");
#endif
}
}
return mrb_int_value(mrb, result);
@@ -121,13 +137,28 @@ static mrb_value
int_div(mrb_state *mrb, mrb_value x)
{
mrb_value y = mrb_get_arg1(mrb);
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
return mrb_bint_div(mrb, x, y);
}
#endif
mrb_int a = mrb_integer(x);
if (mrb_integer_p(y)) {
mrb_int div = mrb_div_int(mrb, a, mrb_integer(y));
mrb_int b = mrb_integer(y);
#ifdef MRB_USE_BIGINT
if(a == MRB_INT_MIN && b == -1) {
return mrb_bint_mul_ii(mrb, a, b);
}
#endif
mrb_int div = mrb_div_int(mrb, a, b);
return mrb_int_value(mrb, div);
}
switch (mrb_type(y)) {
#ifdef MRB_USE_BIGINT
case MRB_TT_BIGINT:
return mrb_bint_div(mrb, mrb_bint_new_int(mrb, a), y);
#endif
#ifdef MRB_USE_RATIONAL
case MRB_TT_RATIONAL:
return mrb_rational_div(mrb, mrb_rational_new(mrb, a, 1), y);
@@ -163,6 +194,11 @@ int_div(mrb_state *mrb, mrb_value x)
static mrb_value
int_idiv(mrb_state *mrb, mrb_value x)
{
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
return mrb_bint_div(mrb, x, mrb_get_arg1(mrb));
}
#endif
mrb_int y;
mrb_get_args(mrb, "i", &y);
@@ -182,6 +218,11 @@ int_quo(mrb_state *mrb, mrb_value x)
if (y == 0) {
mrb_int_zerodiv(mrb);
}
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
return mrb_float_value(mrb, mrb_bint_as_float(mrb, x) / y);
}
#endif
return mrb_float_value(mrb, mrb_integer(x) / y);
#endif
#else
@@ -502,6 +543,11 @@ int_eql(mrb_state *mrb, mrb_value x)
{
mrb_value y = mrb_get_arg1(mrb);
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
return mrb_bool_value(mrb_bint_cmp(mrb, x, y) == 0);
}
#endif
if (!mrb_integer_p(y)) return mrb_false_value();
return mrb_bool_value(mrb_integer(x) == mrb_integer(y));
}
@@ -1038,16 +1084,25 @@ mrb_int_mul(mrb_state *mrb, mrb_value x, mrb_value y)
if (a == 0) return x;
b = mrb_integer(y);
if (mrb_int_mul_overflow(a, b, &c)) {
#ifdef MRB_USE_BIGINT
x = mrb_bint_new_int(mrb, a);
return mrb_bint_mul(mrb, x, y);
#else
mrb_int_overflow(mrb, "multiplication");
#endif
}
return mrb_int_value(mrb, c);
}
switch (mrb_type(y)) {
#if defined(MRB_USE_RATIONAL)
#ifdef MRB_USE_BIGINT
case MRB_TT_BIGINT:
return mrb_bint_mul(mrb, y, x);
#endif
#ifdef MRB_USE_RATIONAL
case MRB_TT_RATIONAL:
return mrb_rational_mul(mrb, y, x);
#endif
#if defined(MRB_USE_COMPLEX)
#ifdef MRB_USE_COMPLEX
case MRB_TT_COMPLEX:
return mrb_complex_mul(mrb, y, x);
#endif
@@ -1075,6 +1130,11 @@ int_mul(mrb_state *mrb, mrb_value x)
{
mrb_value y = mrb_get_arg1(mrb);
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
return mrb_bint_mul(mrb, x, y);
}
#endif
return mrb_int_mul(mrb, x, y);
}
@@ -1115,6 +1175,11 @@ int_mod(mrb_state *mrb, mrb_value x)
mrb_value y = mrb_get_arg1(mrb);
mrb_int a, b;
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
return mrb_bint_mod(mrb, x, y);
}
#endif
a = mrb_integer(x);
if (mrb_integer_p(y)) {
b = mrb_integer(y);
@@ -1151,6 +1216,17 @@ int_divmod(mrb_state *mrb, mrb_value x)
{
mrb_value y = mrb_get_arg1(mrb);
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
#ifndef MRB_NO_FLOAT
if (mrb_float_p(y)) {
mrb_float f = mrb_bint_as_float(mrb, x);
return flo_divmod(mrb, mrb_float_value(mrb, f));
}
#endif
return mrb_bint_divmod(mrb, x, y);
}
#endif
if (mrb_integer_p(y)) {
mrb_int div, mod;
@@ -1206,6 +1282,10 @@ int_equal(mrb_state *mrb, mrb_value x)
case MRB_TT_FLOAT:
return mrb_bool_value((mrb_float)mrb_integer(x) == mrb_float(y));
#endif
#ifdef MRB_USE_BIGINT
case MRB_TT_BIGINT:
return mrb_bool_value(mrb_bint_cmp(mrb, y, x) == 0);
#endif
#ifdef MRB_USE_RATIONAL
case MRB_TT_RATIONAL:
return mrb_bool_value(mrb_equal(mrb, y, x));
@@ -1235,6 +1315,11 @@ int_rev(mrb_state *mrb, mrb_value num)
{
mrb_int val = mrb_integer(num);
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(num)) {
mrb_bint_rev(mrb, num);
}
#endif
return mrb_int_value(mrb, ~val);
}
@@ -1265,6 +1350,11 @@ int_and(mrb_state *mrb, mrb_value x)
{
mrb_value y = mrb_get_arg1(mrb);
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
return mrb_bint_and(mrb, x, y);
}
#endif
bit_op(x, y, and, &);
}
@@ -1281,6 +1371,11 @@ int_or(mrb_state *mrb, mrb_value x)
{
mrb_value y = mrb_get_arg1(mrb);
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
return mrb_bint_or(mrb, x, y);
}
#endif
bit_op(x, y, or, |);
}
@@ -1297,6 +1392,11 @@ int_xor(mrb_state *mrb, mrb_value x)
{
mrb_value y = mrb_get_arg1(mrb);
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
return mrb_bint_xor(mrb, x, y);
}
#endif
bit_op(x, y, or, ^);
}
@@ -1355,10 +1455,20 @@ int_lshift(mrb_state *mrb, mrb_value x)
if (width == 0) {
return x;
}
if (width == MRB_INT_MIN) mrb_int_overflow(mrb, "bit shift");
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
return mrb_bint_lshift(mrb, x, width);
}
#endif
val = mrb_integer(x);
if (val == 0) return x;
if (!mrb_num_shift(mrb, val, width, &val)) {
#ifdef MRB_USE_BIGINT
return mrb_bint_lshift(mrb, mrb_bint_new_int(mrb, val), width);
#else
mrb_int_overflow(mrb, "bit shift");
#endif
}
return mrb_int_value(mrb, val);
}
@@ -1380,11 +1490,20 @@ int_rshift(mrb_state *mrb, mrb_value x)
if (width == 0) {
return x;
}
if (width == MRB_INT_MIN) mrb_int_overflow(mrb, "bit shift");
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
return mrb_bint_rshift(mrb, x, width);
}
#endif
val = mrb_integer(x);
if (val == 0) return x;
if (width == MRB_INT_MIN) mrb_int_overflow(mrb, "bit shift");
if (!mrb_num_shift(mrb, val, -width, &val)) {
#ifdef MRB_USE_BIGINT
return mrb_bint_rshift(mrb, mrb_bint_new_int(mrb, val), width);
#else
mrb_int_overflow(mrb, "bit shift");
#endif
}
return mrb_int_value(mrb, val);
}
@@ -1402,6 +1521,11 @@ int_rshift(mrb_state *mrb, mrb_value x)
static mrb_value
int_to_f(mrb_state *mrb, mrb_value num)
{
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(num)) {
return mrb_float_value(mrb, mrb_bint_as_float(mrb, num));
}
#endif
return mrb_float_value(mrb, (mrb_float)mrb_integer(num));
}
@@ -1454,16 +1578,25 @@ mrb_int_add(mrb_state *mrb, mrb_value x, mrb_value y)
if (a == 0) return y;
b = mrb_integer(y);
if (mrb_int_add_overflow(a, b, &c)) {
#ifdef MRB_USE_BIGINT
x = mrb_bint_new_int(mrb, a);
return mrb_bint_add(mrb, x, y);
#else
mrb_int_overflow(mrb, "addition");
#endif
}
return mrb_int_value(mrb, c);
}
switch (mrb_type(y)) {
#if defined(MRB_USE_RATIONAL)
#ifdef MRB_USE_BIGINT
case MRB_TT_BIGINT:
return mrb_bint_add(mrb, y, x);
#endif
#ifdef MRB_USE_RATIONAL
case MRB_TT_RATIONAL:
return mrb_rational_add(mrb, y, x);
#endif
#if defined(MRB_USE_COMPLEX)
#ifdef MRB_USE_COMPLEX
case MRB_TT_COMPLEX:
return mrb_complex_add(mrb, y, x);
#endif
@@ -1490,6 +1623,11 @@ int_add(mrb_state *mrb, mrb_value self)
{
mrb_value other = mrb_get_arg1(mrb);
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(self)) {
return mrb_bint_add(mrb, self, other);
}
#endif
return mrb_int_add(mrb, self, other);
}
@@ -1504,16 +1642,25 @@ mrb_int_sub(mrb_state *mrb, mrb_value x, mrb_value y)
b = mrb_integer(y);
if (mrb_int_sub_overflow(a, b, &c)) {
#ifdef MRB_USE_BIGINT
x = mrb_bint_new_int(mrb, a);
return mrb_bint_sub(mrb, x, y);
#else
mrb_int_overflow(mrb, "subtraction");
#endif
}
return mrb_int_value(mrb, c);
}
switch (mrb_type(y)) {
#if defined(MRB_USE_RATIONAL)
#ifdef MRB_USE_BIGINT
case MRB_TT_BIGINT:
return mrb_bint_sub(mrb, mrb_bint_new_int(mrb, a), y);
#endif
#ifdef MRB_USE_RATIONAL
case MRB_TT_RATIONAL:
return mrb_rational_sub(mrb, mrb_rational_new(mrb, a, 1), y);
#endif
#if defined(MRB_USE_COMPLEX)
#ifdef MRB_USE_COMPLEX
case MRB_TT_COMPLEX:
return mrb_complex_sub(mrb, mrb_complex_new(mrb, (mrb_float)a, 0), y);
#endif
@@ -1541,6 +1688,11 @@ int_sub(mrb_state *mrb, mrb_value self)
{
mrb_value other = mrb_get_arg1(mrb);
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(self)) {
return mrb_bint_sub(mrb, self, other);
}
#endif
return mrb_int_sub(mrb, self, other);
}
@@ -1615,6 +1767,11 @@ int_to_s(mrb_state *mrb, mrb_value self)
mrb_int base = 10;
mrb_get_args(mrb, "|i", &base);
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(self)) {
return mrb_bint_to_s(mrb, self, base);
}
#endif
return mrb_integer_to_str(mrb, self, base);
}
@@ -1622,6 +1779,12 @@ int_to_s(mrb_state *mrb, mrb_value self)
static mrb_int
cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2)
{
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(v2)) {
return mrb_bint_cmp(mrb, v1, v2);
}
#endif
#ifdef MRB_NO_FLOAT
mrb_int x, y;
#else
+15
View File
@@ -12,6 +12,11 @@
MRB_API mrb_value
mrb_num_add(mrb_state *mrb, mrb_value x, mrb_value y)
{
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
return mrb_bint_add(mrb, x, y);
}
#endif
if (mrb_integer_p(x)) {
return mrb_int_add(mrb, x, y);
}
@@ -41,6 +46,11 @@ mrb_num_add(mrb_state *mrb, mrb_value x, mrb_value y)
MRB_API mrb_value
mrb_num_sub(mrb_state *mrb, mrb_value x, mrb_value y)
{
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
return mrb_bint_sub(mrb, x, y);
}
#endif
if (mrb_integer_p(x)) {
return mrb_int_sub(mrb, x, y);
}
@@ -70,6 +80,11 @@ mrb_num_sub(mrb_state *mrb, mrb_value x, mrb_value y)
MRB_API mrb_value
mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y)
{
#ifdef MRB_USE_BIGINT
if (mrb_bigint_p(x)) {
return mrb_bint_mul(mrb, x, y);
}
#endif
if (mrb_integer_p(x)) {
return mrb_int_mul(mrb, x, y);
}
+6
View File
@@ -9,6 +9,7 @@
#include <mruby/numeric.h>
#include <mruby/string.h>
#include <mruby/class.h>
#include <mruby/internal.h>
#include <mruby/presym.h>
MRB_API mrb_bool
@@ -547,6 +548,11 @@ mrb_ensure_float_type(mrb_state *mrb, mrb_value val)
return mrb_complex_to_f(mrb, val);
#endif
#ifdef MRB_USE_BIGINT
case MRB_TT_BIGINT:
return mrb_float_value(mrb, mrb_bint_as_float(mrb, val));
#endif
default:
mrb_raisef(mrb, E_TYPE_ERROR, "%Y cannot be converted to Float", val);
/* not reached */
+30 -7
View File
@@ -2150,11 +2150,24 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str)
return result;
}
static mrb_bool
trailingbad(const char *str, const char *p, const char *pend)
{
if (p == str) return TRUE; /* no number */
if (*(p - 1) == '_') return TRUE; /* trailing '_' */
while (p<pend && ISSPACE(*p)) p++;
if (p<pend) return TRUE; /* trailing garbage */
return FALSE;
}
static mrb_value
mrb_str_len_to_integer(mrb_state *mrb, const char *str, size_t len, mrb_int base, int badcheck)
{
const char *p = str;
const char *pend = str + len;
#ifdef MRB_USE_BIGINT
const char *p2 = NULL;
#endif
char sign = 1;
int c;
mrb_int n = 0;
@@ -2265,6 +2278,9 @@ mrb_str_len_to_integer(mrb_state *mrb, const char *str, size_t len, mrb_int base
if (badcheck) goto bad;
return mrb_fixnum_value(0);
}
#ifdef MRB_USE_BIGINT
p2 = p;
#endif
for ( ;p<pend;p++) {
if (*p == '_') {
p++;
@@ -2292,18 +2308,25 @@ mrb_str_len_to_integer(mrb_state *mrb, const char *str, size_t len, mrb_int base
break;
}
overflow:
#ifdef MRB_USE_BIGINT
;
const char *p3 = p2;
while (p3 < pend) {
char c = TOLOWER(*p3);
const char *p4 = strchr(mrb_digitmap, c);
if (p4 == NULL && c != '_') break;
if (p4 - mrb_digitmap >= base) break;
p3++;
}
if (badcheck && trailingbad(str, p, pend)) goto bad;
return mrb_bint_new_str(mrb, p2, (mrb_int)(p3-p2), sign ? base : -base);
#endif
mrb_raisef(mrb, E_RANGE_ERROR, "string (%l) too big for integer", str, pend-str);
}
n += c;
}
val = (mrb_int)n;
if (badcheck) {
if (p == str) goto bad; /* no number */
if (*(p - 1) == '_') goto bad; /* trailing '_' */
while (p<pend && ISSPACE(*p)) p++;
if (p<pend) goto bad; /* trailing garbage */
}
if (badcheck && trailingbad(str, p, pend)) goto bad;
return mrb_int_value(mrb, sign ? val : -val);
bad:
mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for number(%!l)", str, pend-str);
+21 -5
View File
@@ -1267,7 +1267,15 @@ RETRY_TRY_BLOCK:
goto L_INT_OVERFLOW;
#endif
case IREP_TT_BIGINT:
#ifdef MRB_USE_BIGINT
{
const char *s = pool[b].u.str;
regs[a] = mrb_bint_new_str(mrb, s+2, (mrb_int)s[0], (mrb_int)s[1]);
}
break;
#else
goto L_INT_OVERFLOW;
#endif
#ifndef MRB_NO_FLOAT
case IREP_TT_FLOAT:
regs[a] = mrb_float_value(mrb, pool[b].u.f);
@@ -2376,12 +2384,14 @@ RETRY_TRY_BLOCK:
NEXT;
}
#if !defined(MRB_USE_BIGINT) || (defined(MRB_INT32) && MRB_32BIT)
L_INT_OVERFLOW:
{
mrb_value exc = mrb_exc_new_lit(mrb, E_RANGE_ERROR, "integer overflow");
mrb_exc_set(mrb, exc);
}
goto L_RAISE;
#endif
#define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff))
#define OP_MATH(op_name) \
@@ -2401,8 +2411,9 @@ RETRY_TRY_BLOCK:
case TYPES2(MRB_TT_INTEGER, MRB_TT_INTEGER): \
{ \
mrb_int x = mrb_integer(regs[a]), y = mrb_integer(regs[a+1]), z; \
if (mrb_int_##op_name##_overflow(x, y, &z)) \
OP_MATH_OVERFLOW_INT(); \
if (mrb_int_##op_name##_overflow(x, y, &z)) { \
OP_MATH_OVERFLOW_INT(op_name,x,y); \
} \
else \
SET_INT_VALUE(mrb,regs[a], z); \
} \
@@ -2418,7 +2429,11 @@ RETRY_TRY_BLOCK:
} \
break
#endif
#define OP_MATH_OVERFLOW_INT() goto L_INT_OVERFLOW
#ifdef MRB_USE_BIGINT
#define OP_MATH_OVERFLOW_INT(op,x,y) regs[a] = mrb_bint_##op##_ii(mrb,x,y)
#else
#define OP_MATH_OVERFLOW_INT(op,x,y) goto L_INT_OVERFLOW
#endif
#define OP_MATH_CASE_STRING_add() \
case TYPES2(MRB_TT_STRING, MRB_TT_STRING): \
regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); \
@@ -2500,8 +2515,9 @@ RETRY_TRY_BLOCK:
case MRB_TT_INTEGER: \
{ \
mrb_int x = mrb_integer(regs[a]), y = (mrb_int)b, z; \
if (mrb_int_##op_name##_overflow(x, y, &z)) \
OP_MATH_OVERFLOW_INT(); \
if (mrb_int_##op_name##_overflow(x, y, &z)) { \
OP_MATH_OVERFLOW_INT(op_name,x,y); \
} \
else \
SET_INT_VALUE(mrb,regs[a], z); \
} \