"dashu-int",
"num-modular",
"num-order",
+ "rand",
"rustversion",
"static_assertions",
]
"dashu-base",
"num-modular",
"num-order",
+ "rand",
"rustversion",
"static_assertions",
]
"dashu-int",
"num-modular",
"num-order",
+ "rand",
"rustversion",
]
chrono = "0.4.38"
cpu-time = "1.0.0"
crrl = "0.9.0"
-dashu = "0.4.2"
+dashu = { version = "0.4.2", features = ["rand"] }
derive_more = "0.99.18"
dirs-next = "2.0.0"
divrem = "1.0.0"
GetUnknown,
#[strum_discriminants(strum(props(Arity = "1", Name = "$install_new_block")))]
InstallNewBlock,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$random_integer")))]
+ RandomInteger,
#[strum_discriminants(strum(props(Arity = "0", Name = "$maybe")))]
Maybe,
#[strum_discriminants(strum(props(Arity = "1", Name = "$current_time")))]
&Instruction::CallGetDoubleQuotes |
&Instruction::CallGetUnknown |
&Instruction::CallInstallNewBlock |
+ &Instruction::CallRandomInteger |
&Instruction::CallMaybe |
&Instruction::CallCpuNow |
&Instruction::CallDeterministicLengthRundown |
&Instruction::ExecuteGetDoubleQuotes |
&Instruction::ExecuteGetUnknown |
&Instruction::ExecuteInstallNewBlock |
+ &Instruction::ExecuteRandomInteger |
&Instruction::ExecuteMaybe |
&Instruction::ExecuteCpuNow |
&Instruction::ExecuteDeterministicLengthRundown |
% Succeeds with probability 0.5.
maybe :- '$maybe'.
-% The higher the precision, the slower it gets.
-random_number_precision(64).
-
%% random(-R).
%
% Generates a random floating number between 0 (inclusive) and 1 (exclusive).
random(R) :-
var(R),
- random_number_precision(N),
- rnd(N, R).
+ N is 2^50,
+ '$random_integer'(0, N, K),
+ R is K/N.
%% random_integer(+Lower, +Upper, -R).
%
type_error(integer, Lower, random_integer/3)
; \+ integer(Upper) ->
type_error(integer, Upper, random_integer/3)
- ; Upper > Lower,
- random(R0),
- R is floor((Upper - Lower) * R0 + Lower)
+ ; Lower < Upper,
+ '$random_integer'(Lower, Upper, R)
).
-rnd(N, R) :-
- rnd_(N, 0, R).
-
-rnd_(0, R, R) :- !.
-rnd_(N, R0, R) :-
- maybe,
- !,
- N1 is N - 1,
- rnd_(N1, R0, R).
-rnd_(N, R0, R) :-
- N1 is N - 1,
- R1 is R0 + 1.0 / 2.0 ^ N,
- rnd_(N1, R1, R).
-
%% set_random(+Seed).
%
% Sets a seed that will be used for subsequent random generations in this library.
.install_new_block(self.machine_st.registers[1]);
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
+ &Instruction::CallRandomInteger => {
+ self.random_integer();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteRandomInteger => {
+ self.random_integer();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
&Instruction::CallMaybe => {
self.maybe();
step_or_fail!(self, self.machine_st.p += 1);
}
}
+ #[inline(always)]
+ pub(crate) fn random_integer(&mut self) {
+ let a1 = self.deref_register(1);
+ let a2 = self.deref_register(2);
+ let value = match (Number::try_from(a1), Number::try_from(a2)) {
+ (Ok(Number::Fixnum(lower)), Ok(Number::Fixnum(upper))) => {
+ let (lower, upper) = (lower.get_num(), upper.get_num());
+ if lower >= upper {
+ self.machine_st.fail = true;
+ return;
+ }
+ let value = self.rng.gen_range(lower..upper);
+ Number::Fixnum(Fixnum::build_with(value))
+ }
+ (Ok(Number::Fixnum(lower)), Ok(Number::Integer(upper))) => {
+ let lower = Integer::from(lower);
+ if &lower >= &*upper {
+ self.machine_st.fail = true;
+ return;
+ }
+ let value = self.rng.gen_range(lower..(&*upper).clone());
+ Number::arena_from(value, &mut self.machine_st.arena)
+ }
+ (Ok(Number::Integer(lower)), Ok(Number::Fixnum(upper))) => {
+ let upper = Integer::from(upper);
+ if &*lower >= &upper {
+ self.machine_st.fail = true;
+ return;
+ }
+ let value = self.rng.gen_range((&*lower).clone()..upper);
+ Number::arena_from(value, &mut self.machine_st.arena)
+ }
+ (Ok(Number::Integer(lower)), Ok(Number::Integer(upper))) => {
+ if &*lower >= &*upper {
+ self.machine_st.fail = true;
+ return;
+ }
+ let value = self.rng.gen_range((&*lower).clone()..(&*upper).clone());
+ Number::arena_from(value, &mut self.machine_st.arena)
+ }
+ _ => {
+ self.machine_st.fail = true;
+ return;
+ }
+ };
+ let a3 = self.deref_register(3);
+ match value {
+ Number::Fixnum(n) => {
+ self.machine_st.unify_fixnum(n, a3);
+ }
+ Number::Integer(n) => {
+ self.machine_st.unify_big_int(n, a3);
+ }
+ _ => unreachable!(),
+ }
+ }
+
#[inline(always)]
pub(crate) fn maybe(&mut self) {
self.machine_st.fail = self.rng.gen();