Browse Source

big: Add `pow`.

Jeroen van Rijn 4 years ago
parent
commit
d953e40fb3
3 changed files with 54 additions and 7 deletions
  1. 6 1
      core/math/big/basic.odin
  2. 46 4
      core/math/big/log.odin
  3. 2 2
      core/math/big/radix.odin

+ 6 - 1
core/math/big/basic.odin

@@ -516,7 +516,7 @@ int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT) -> (err: Error) {
 	}
 	}
 	if is_power_of_two(int(multiplier)) {
 	if is_power_of_two(int(multiplier)) {
 		ix: int;
 		ix: int;
-		if ix, err = log_n(multiplier, 2); err != .None { return err; }
+		if ix, err = log(multiplier, 2); err != .None { return err; }
 		return shl(dest, src, ix);
 		return shl(dest, src, ix);
 	}
 	}
 
 
@@ -648,6 +648,11 @@ int_mul :: proc(dest, src, multiplier: ^Int) -> (err: Error) {
 
 
 mul :: proc { int_mul, int_mul_digit, };
 mul :: proc { int_mul, int_mul_digit, };
 
 
+sqr :: proc(dest, src: ^Int) -> (err: Error) {
+	return mul(dest, src, src);
+}
+
+
 /*
 /*
 	==========================
 	==========================
 		Low-level routines    
 		Low-level routines    

+ 46 - 4
core/math/big/log.odin

@@ -9,7 +9,7 @@ package big
 	The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
 	The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
 */
 */
 
 
-log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
+int_log :: proc(a: ^Int, base: DIGIT) -> (res: int, err: Error) {
 	if base < 2 || DIGIT(base) > _DIGIT_MAX {
 	if base < 2 || DIGIT(base) > _DIGIT_MAX {
 		return -1, .Invalid_Argument;
 		return -1, .Invalid_Argument;
 	}
 	}
@@ -35,7 +35,7 @@ log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
 		Fast path for `Int`s that fit within a single `DIGIT`.
 		Fast path for `Int`s that fit within a single `DIGIT`.
 	*/
 	*/
 	if a.used == 1 {
 	if a.used == 1 {
-		return log_n_digit(a.digit[0], DIGIT(base));
+		return log(a.digit[0], DIGIT(base));
 	}
 	}
 
 
     // if (MP_HAS(S_MP_LOG)) {
     // if (MP_HAS(S_MP_LOG)) {
@@ -45,7 +45,49 @@ log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
 	return -1, .Unimplemented;
 	return -1, .Unimplemented;
 }
 }
 
 
-log_n :: proc{log_n_int, log_n_digit};
+log :: proc { int_log, int_log_digit, };
+
+/*
+	Calculate c = a**b  using a square-multiply algorithm.
+*/
+int_pow :: proc(dest, base: ^Int, power: int) -> (err: Error) {
+	if err = clear_if_uninitialized(dest); err != .None { return err; }
+	if err = clear_if_uninitialized(base); err != .None { return err; }
+
+// 	if ((err = mp_init_copy(&g, a)) != MP_OKAY) {
+// 		return err;
+// 	}
+
+// 	/* set initial result */
+// 	mp_set(c, 1uL);
+
+// 	while (b > 0) {
+// 		/* if the bit is set multiply */
+// 		if ((b & 1) != 0) {
+// 			if ((err = mp_mul(c, &g, c)) != MP_OKAY) {
+// 				goto LBL_ERR;
+// 			}
+// 		}
+
+// 		/* square */
+// 		if (b > 1) {
+// 			if ((err = mp_sqr(&g, &g)) != MP_OKAY) {
+// 				goto LBL_ERR;
+// 			}
+// 		}
+
+// 		/* shift to next bit */
+// 		b >>= 1;
+// 	}
+
+// LBL_ERR:
+// 	mp_clear(&g);
+// 	return err;
+	return err;
+}
+
+
+pow :: proc { int_pow, };
 
 
 /*
 /*
 	Returns the log2 of an `Int`, provided `base` is a power of two.
 	Returns the log2 of an `Int`, provided `base` is a power of two.
@@ -79,7 +121,7 @@ small_pow :: proc(base: _WORD, exponent: _WORD) -> (result: _WORD) {
    	return result;
    	return result;
 }
 }
 
 
-log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error) {
+int_log_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error) {
 	/*
 	/*
 		If the number is smaller than the base, it fits within a fraction.
 		If the number is smaller than the base, it fits within a fraction.
 		Therefore, we return 0.
 		Therefore, we return 0.

+ 2 - 2
core/math/big/radix.odin

@@ -207,7 +207,7 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
 
 
 		shift, count: int;
 		shift, count: int;
 		// mask  := _WORD(radix - 1);
 		// mask  := _WORD(radix - 1);
-		shift, err = log_n(DIGIT(radix), 2);
+		shift, err = log(DIGIT(radix), 2);
 		count, err = count_bits(a);
 		count, err = count_bits(a);
 		digit: _WORD;
 		digit: _WORD;
 
 
@@ -263,7 +263,7 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false) -> (size: int, e
 		digit     = a.digit,
 		digit     = a.digit,
 	};
 	};
 
 
-	if size, err = log_n(t, DIGIT(radix)); err != .None {
+	if size, err = log(t, DIGIT(radix)); err != .None {
 		return 0, err;
 		return 0, err;
 	}
 	}