]> Repositorios git - scryer-prolog.git/commitdiff
Add '$random_integer'/3
authornotoria <[email protected]>
Sun, 8 Dec 2024 19:00:00 +0000 (20:00 +0100)
committernotoria <[email protected]>
Sun, 8 Dec 2024 19:00:00 +0000 (20:00 +0100)
Cargo.lock
Cargo.toml
build/instructions_template.rs
src/lib/random.pl
src/machine/dispatch.rs
src/machine/system_calls.rs

index 0fc692cdd834b295715b7548de9af7b55c2cb11d..623d5cf782d8548a08262e11189c770b6522587e 100644 (file)
@@ -631,6 +631,7 @@ dependencies = [
  "dashu-int",
  "num-modular",
  "num-order",
+ "rand",
  "rustversion",
  "static_assertions",
 ]
@@ -645,6 +646,7 @@ dependencies = [
  "dashu-base",
  "num-modular",
  "num-order",
+ "rand",
  "rustversion",
  "static_assertions",
 ]
@@ -676,6 +678,7 @@ dependencies = [
  "dashu-int",
  "num-modular",
  "num-order",
+ "rand",
  "rustversion",
 ]
 
index ddb6f239e2364996d8127a65e9285975f0b54974..a299e6900ff46c21b09cac4d5e5881d561dcb395 100644 (file)
@@ -46,7 +46,7 @@ bytes = "1"
 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"
index 5e64f3d796af26e6be4fd5db26cbb4015fbd6e51..f6f9351e711c21c6a55e15faab9701a81a5d7b7a 100644 (file)
@@ -419,6 +419,8 @@ enum SystemClauseType {
     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")))]
@@ -1805,6 +1807,7 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::CallGetDoubleQuotes |
                     &Instruction::CallGetUnknown |
                     &Instruction::CallInstallNewBlock |
+                    &Instruction::CallRandomInteger |
                     &Instruction::CallMaybe |
                     &Instruction::CallCpuNow |
                     &Instruction::CallDeterministicLengthRundown |
@@ -2042,6 +2045,7 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::ExecuteGetDoubleQuotes |
                     &Instruction::ExecuteGetUnknown |
                     &Instruction::ExecuteInstallNewBlock |
+                    &Instruction::ExecuteRandomInteger |
                     &Instruction::ExecuteMaybe |
                     &Instruction::ExecuteCpuNow |
                     &Instruction::ExecuteDeterministicLengthRundown |
index a32967976d22b2f58f1430db893152f824e1b222..6498157446fb6f33e06ce321c6b0ec1149b134ee 100644 (file)
@@ -15,16 +15,14 @@ the random seed. This makes everything completely reproducible.
 % 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).
 %
@@ -41,25 +39,10 @@ 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.
index a3ace102ff46b068699e25a6d8484542097f02a1..f77f7f0f184c0030f56864b191062b307af2cff3 100644 (file)
@@ -4061,6 +4061,14 @@ impl Machine {
                             .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);
index 371b97e14ac4e0bc91889d84f49726840fe58765..3ab0831b2ea7555fcc01aac29494c415e62cc76f 100644 (file)
@@ -4157,6 +4157,63 @@ impl Machine {
         }
     }
 
+    #[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();