mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-random: support bigint in rand method
To achieve this, the following changes were made: - Exported `mrb_bint_size`, `mrb_bint_from_bytes`, and `mrb_bint_sign` functions from `mruby-bigint` to be used in other mrbgems. - Modified `mruby-random` to use these new functions to handle Bigint arguments in the `rand` method. Co-authored-by: Gemini <gemini@google.com>
This commit is contained in:
@@ -258,6 +258,9 @@ void mrb_bint_copy(mrb_state *mrb, mrb_value x, mrb_value y);
|
||||
size_t mrb_bint_memsize(mrb_value x);
|
||||
mrb_value mrb_bint_hash(mrb_state *mrb, mrb_value x);
|
||||
mrb_value mrb_bint_sqrt(mrb_state *mrb, mrb_value x);
|
||||
mrb_int mrb_bint_size(mrb_state *mrb, mrb_value bint);
|
||||
mrb_value mrb_bint_from_bytes(mrb_state *mrb, const uint8_t *bytes, mrb_int len);
|
||||
mrb_int mrb_bint_sign(mrb_state *mrb, mrb_value bint);
|
||||
#endif
|
||||
|
||||
#endif /* MRUBY_INTERNAL_H */
|
||||
|
||||
@@ -2756,6 +2756,34 @@ mrb_bint_sqrt(mrb_state *mrb, mrb_value x)
|
||||
return bint_norm(mrb, bint_new(mrb, &z));
|
||||
}
|
||||
|
||||
mrb_int
|
||||
mrb_bint_sign(mrb_state *mrb, mrb_value bint)
|
||||
{
|
||||
return RBIGINT_SIGN(RBIGINT(bint));
|
||||
}
|
||||
|
||||
mrb_int
|
||||
mrb_bint_size(mrb_state *mrb, mrb_value bint)
|
||||
{
|
||||
mpz_t z;
|
||||
bint_as_mpz(RBIGINT(bint), &z);
|
||||
return z.sz * sizeof(mp_limb);
|
||||
}
|
||||
|
||||
mrb_value
|
||||
mrb_bint_from_bytes(mrb_state *mrb, const uint8_t *bytes, mrb_int len)
|
||||
{
|
||||
mpz_t z;
|
||||
mpz_init(mrb, &z);
|
||||
size_t limb_len = (len + sizeof(mp_limb) - 1) / sizeof(mp_limb);
|
||||
mpz_realloc(mrb, &z, limb_len);
|
||||
memcpy(z.p, bytes, len);
|
||||
z.sn = (len > 0) ? 1 : 0;
|
||||
z.sz = limb_len;
|
||||
trim(&z);
|
||||
return bint_norm(mrb, bint_new(mrb, &z));
|
||||
}
|
||||
|
||||
mrb_value
|
||||
mrb_bint_hash(mrb_state *mrb, mrb_value x)
|
||||
{
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <mruby/presym.h>
|
||||
#include <mruby/range.h>
|
||||
#include <mruby/string.h>
|
||||
#include <mruby/internal.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
@@ -210,6 +211,22 @@ random_rand_impl(mrb_state *mrb, rand_state *t, mrb_value self)
|
||||
return random_range(mrb, t, arg);
|
||||
}
|
||||
|
||||
#ifdef MRB_USE_BIGINT
|
||||
if (mrb_bigint_p(arg)) {
|
||||
if (mrb_bint_sign(mrb, arg) < 0) {
|
||||
mrb_raise(mrb, E_ARGUMENT_ERROR, "negative value as random limit");
|
||||
}
|
||||
mrb_int size = mrb_bint_size(mrb, arg);
|
||||
mrb_value bytes = mrb_str_new(mrb, NULL, size);
|
||||
uint8_t *p = (uint8_t*)RSTRING_PTR(bytes);
|
||||
for (mrb_int i = 0; i < size; i++) {
|
||||
p[i] = (uint8_t)rand_uint32(t);
|
||||
}
|
||||
mrb_value rand_bint = mrb_bint_from_bytes(mrb, p, size);
|
||||
return mrb_bint_mod(mrb, rand_bint, arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
range_error(mrb, arg);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user