Browse Source

big: Timed `factorial`.

Jeroen van Rijn 4 years ago
parent
commit
627872db97
4 changed files with 34 additions and 23 deletions
  1. 12 14
      core/math/big/basic.odin
  2. 3 3
      core/math/big/build.bat
  3. 1 1
      core/math/big/common.odin
  4. 18 5
      core/math/big/example.odin

+ 12 - 14
core/math/big/basic.odin

@@ -580,9 +580,8 @@ int_mul :: proc(dest, src, multiplier: ^Int) -> (err: Error) {
 	/*
 	/*
 		Early out for `multiplier` is zero; Set `dest` to zero.
 		Early out for `multiplier` is zero; Set `dest` to zero.
 	*/
 	*/
-	if z, _ := is_zero(multiplier); z {
-		return zero(dest);
-	}
+	if z, _ := is_zero(multiplier); z { return zero(dest); }
+	if z, _ := is_zero(src);        z { return zero(dest); }
 
 
 	if src == multiplier {
 	if src == multiplier {
 		/*
 		/*
@@ -748,6 +747,10 @@ int_sqrmod :: proc(remainder, number, modulus: ^Int) -> (err: Error) {
 sqrmod :: proc { int_sqrmod, };
 sqrmod :: proc { int_sqrmod, };
 
 
 
 
+/*
+	TODO: Use Sterling's Approximation to estimate log2(N!) to size the result.
+	This way we'll have to reallocate less, possibly not at all.
+*/
 int_factorial :: proc(res: ^Int, n: DIGIT) -> (err: Error) {
 int_factorial :: proc(res: ^Int, n: DIGIT) -> (err: Error) {
 	if n < 0 || n > _FACTORIAL_MAX_N || res == nil { return .Invalid_Argument; }
 	if n < 0 || n > _FACTORIAL_MAX_N || res == nil { return .Invalid_Argument; }
 
 
@@ -759,12 +762,7 @@ int_factorial :: proc(res: ^Int, n: DIGIT) -> (err: Error) {
 		return int_factorial_binary_split(res, n);
 		return int_factorial_binary_split(res, n);
 	}
 	}
 
 
-	a := &Int{};
-	defer destroy(a);
-
-	if err = set(  a, i - 1); err != .None { return err; }
 	if err = set(res, _factorial_table[i - 1]); err != .None { return err; }
 	if err = set(res, _factorial_table[i - 1]); err != .None { return err; }
-
 	for {
 	for {
 		if err = mul(res, res, DIGIT(i)); err != .None || i == n { return err; }
 		if err = mul(res, res, DIGIT(i)); err != .None || i == n { return err; }
 		i += 1;
 		i += 1;
@@ -1168,12 +1166,12 @@ _int_mul_comba :: proc(dest, a, b: ^Int, digits: int) -> (err: Error) {
 	old_used := dest.used;
 	old_used := dest.used;
 	dest.used = pa;
 	dest.used = pa;
 
 
-	for ix = 0; ix < pa; ix += 1 {
-		/*
-			Now extract the previous digit [below the carry].
-		*/
-		dest.digit[ix] = W[ix];
-	}
+	/*
+		Now extract the previous digit [below the carry].
+	*/
+	// for ix = 0; ix < pa; ix += 1 { dest.digit[ix] = W[ix]; }
+
+	copy_slice(dest.digit[0:], W[:pa]);	
 
 
 	/*
 	/*
 		Clear unused digits [that existed in the old copy of dest].
 		Clear unused digits [that existed in the old copy of dest].

+ 3 - 3
core/math/big/build.bat

@@ -1,10 +1,10 @@
 @echo off
 @echo off
-:odin run . -vet
+odin run . -vet
 : -o:size -no-bounds-check
 : -o:size -no-bounds-check
 :odin build . -build-mode:shared -show-timings -o:minimal -use-separate-modules
 :odin build . -build-mode:shared -show-timings -o:minimal -use-separate-modules
 :odin build . -build-mode:shared -show-timings -o:size -use-separate-modules -no-bounds-check
 :odin build . -build-mode:shared -show-timings -o:size -use-separate-modules -no-bounds-check
 :odin build . -build-mode:shared -show-timings -o:size -use-separate-modules
 :odin build . -build-mode:shared -show-timings -o:size -use-separate-modules
-odin build . -build-mode:shared -show-timings -o:speed -use-separate-modules -no-bounds-check
+:odin build . -build-mode:shared -show-timings -o:speed -use-separate-modules -no-bounds-check
 :odin build . -build-mode:shared -show-timings -o:speed -use-separate-modules
 :odin build . -build-mode:shared -show-timings -o:speed -use-separate-modules
 
 
-python test.py
+:python test.py

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

@@ -45,7 +45,7 @@ _MAX_ITERATIONS_ROOT_N        :: 500;
 /*
 /*
 	Largest `N` for which we'll compute `N!`
 	Largest `N` for which we'll compute `N!`
 */
 */
-_FACTORIAL_MAX_N              :: 100_000;
+_FACTORIAL_MAX_N              :: 1_000_000;
 
 
 /*
 /*
 	Cutoff to switch to int_factorial_binary_split, and its max recursion level.
 	Cutoff to switch to int_factorial_binary_split, and its max recursion level.

+ 18 - 5
core/math/big/example.odin

@@ -111,17 +111,30 @@ print :: proc(name: string, a: ^Int, base := i8(10), print_name := false, newlin
 }
 }
 
 
 demo :: proc() {
 demo :: proc() {
-
 	err: Error;
 	err: Error;
+	as: string;
+	defer delete(as);
+
 	a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
 	a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
 	defer destroy(a, b, c, d, e, f);
 	defer destroy(a, b, c, d, e, f);
 
 
+	N :: 5_000;
+
 	s := time.tick_now();
 	s := time.tick_now();
-	err = choose(a, 65535, 255);
-	Timings[.choose].t += time.tick_since(s); Timings[.choose].c += 1;
+	err = factorial(a, N);
+	Timings[.factorial].t += time.tick_since(s); Timings[.factorial].c += 1;
+	if err != .None {
+		fmt.printf("factorial(%v) returned %v\n", N, err);
+	}
+
+	s = time.tick_now();
+	as, err = itoa(a, 16);
+	Timings[.itoa].t += time.tick_since(s); Timings[.itoa].c += 1;
+	if err != .None {
+		fmt.printf("itoa(factorial(%v), 16) returned %v\n", N, err);
+	}
 
 
-	print("65535 choose 255", a, 10, true, true, true);
-	fmt.printf("Error: %v\n", err);
+	fmt.printf("factorial(%v): %v (first 10 hex digits)\n", N, as[:10]);
 }
 }
 
 
 main :: proc() {
 main :: proc() {