Browse Source

big: Add `rand`.

Jeroen van Rijn 4 years ago
parent
commit
9c150381bf
4 changed files with 53 additions and 21 deletions
  1. 9 17
      core/math/big/example.odin
  2. 1 1
      core/math/big/exp_log.odin
  3. 42 2
      core/math/big/helpers.odin
  4. 1 1
      core/math/rand/rand.odin

+ 9 - 17
core/math/big/example.odin

@@ -59,23 +59,15 @@ demo :: proc() {
 	destination, source, quotient, remainder, numerator, denominator := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
 	destination, source, quotient, remainder, numerator, denominator := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
 	defer destroy(destination, source, quotient, remainder, numerator, denominator);
 	defer destroy(destination, source, quotient, remainder, numerator, denominator);
 
 
-	// string_buffer := make([]u8, 1024);
-	// defer delete(string_buffer);
-
-	err = set (numerator,   1024);
-	err = sqrt(destination, numerator);
-	fmt.printf("int_sqrt returned: %v\n", err);
-
-	print("num      ", numerator);
-	print("sqrt(num)", destination);
-
-	fmt.println("\n\n");
-
-	err = root_n(destination, numerator, 2);
-	fmt.printf("root_n(2) returned: %v\n", err);
-
-	print("num        ", numerator);
-	print("root_n(num)", destination);
+	for i in 1..=10 {
+		err = rand(destination, 1200); // 1200 random bits
+		if err != .None {
+			fmt.printf("rand error: %v\n", err);
+		} else {
+			fmt.printf("#%3d: ", i);
+			print("", destination);
+		}
+	}
 }
 }
 
 
 main :: proc() {
 main :: proc() {

+ 1 - 1
core/math/big/exp_log.odin

@@ -406,7 +406,7 @@ _int_log :: proc(a: ^Int, base: DIGIT) -> (res: int, err: Error) {
 	}
 	}
 
 
 	if err = set(bi_base, base);          err != .None { return -1, err; }
 	if err = set(bi_base, base);          err != .None { return -1, err; }
-	if err = _init_multi(bracket_mid, t); err != .None { return -1, err; }
+	if err = init_multi(bracket_mid, t);  err != .None { return -1, err; }
 	if err = one(bracket_low);            err != .None { return -1, err; }
 	if err = one(bracket_low);            err != .None { return -1, err; }
 	if err = set(bracket_high, base);     err != .None { return -1, err; }
 	if err = set(bracket_high, base);     err != .None { return -1, err; }
 
 

+ 42 - 2
core/math/big/helpers.odin

@@ -11,6 +11,7 @@ package big
 
 
 import "core:mem"
 import "core:mem"
 import "core:intrinsics"
 import "core:intrinsics"
+import "core:math/rand"
 
 
 /*
 /*
 	Deallocates the backing memory of one or more `Int`s.
 	Deallocates the backing memory of one or more `Int`s.
@@ -506,6 +507,43 @@ count_lsb :: proc(a: ^Int) -> (count: int, err: Error) {
 	return count, .None;
 	return count, .None;
 }
 }
 
 
+int_random_digit :: proc(r: ^rand.Rand = nil) -> (res: DIGIT) {
+	when _DIGIT_BITS == 60 { // DIGIT = u64
+		return DIGIT(rand.uint64(r)) & _MASK;
+	} else when _DIGIT_BITS == 28 { // DIGIT = u32
+		return DIGIT(rand.uint32(r)) & _MASK;
+	} else {
+		panic("Unsupported DIGIT size.");
+	}
+
+	return 0; // We shouldn't get here.
+}
+
+int_rand :: proc(dest: ^Int, bits: int, r: ^rand.Rand = nil) -> (err: Error) {
+	bits := bits;
+
+	if bits <= 0 { return .Invalid_Argument; }
+
+	digits := bits / _DIGIT_BITS;
+	bits   %= _DIGIT_BITS;
+
+	if bits > 0 {
+		digits += 1;
+	}
+
+	if err = grow(dest, digits); err != .None { return err; }
+
+	for i := 0; i < digits; i += 1 {
+		dest.digit[i] = int_random_digit(r) & _MASK;
+	}
+	if bits > 0 {
+		dest.digit[digits - 1] &= ((1 << uint(bits)) - 1);
+	}
+	dest.used = digits;
+	return .None;
+}
+rand :: proc { int_rand, };
+
 /*
 /*
 	Internal helpers.
 	Internal helpers.
 */
 */
@@ -532,10 +570,12 @@ clear_if_uninitialized :: proc(dest: ^Int, minimize := false) -> (err: Error) {
 	return .None;
 	return .None;
 }
 }
 
 
+
+
 /*
 /*
 	Allocates several `Int`s at once.
 	Allocates several `Int`s at once.
 */
 */
-_int_init_multi :: proc(integers: ..^Int) -> (err: Error) {
+int_init_multi :: proc(integers: ..^Int) -> (err: Error) {
 	integers := integers;
 	integers := integers;
 	for a in &integers {
 	for a in &integers {
 		if err = clear(a); err != .None { return err; }
 		if err = clear(a); err != .None { return err; }
@@ -543,7 +583,7 @@ _int_init_multi :: proc(integers: ..^Int) -> (err: Error) {
 	return .None;
 	return .None;
 }
 }
 
 
-_init_multi :: proc { _int_init_multi, };
+init_multi :: proc { int_init_multi, };
 
 
 _copy_digits :: proc(dest, src: ^Int, digits: int) -> (err: Error) {
 _copy_digits :: proc(dest, src: ^Int, digits: int) -> (err: Error) {
 	digits := digits;
 	digits := digits;

+ 1 - 1
core/math/rand/rand.odin

@@ -95,7 +95,7 @@ int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 {
 
 
 int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 {
 int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 {
 	if n <= 0 {
 	if n <= 0 {
-		panic("Invalid argument to int63_max");
+		panic("Invalid argument to int127_max");
 	}
 	}
 	if n&(n-1) == 0 {
 	if n&(n-1) == 0 {
 		return int127(r) & (n-1);
 		return int127(r) & (n-1);