Browse Source

big: Split up `int_mod_bits` (res = val % (1 << bits))

Jeroen van Rijn 4 years ago
parent
commit
d4a03acbc3
2 changed files with 47 additions and 37 deletions
  1. 4 32
      core/math/big/basic.odin
  2. 43 5
      core/math/big/internal.odin

+ 4 - 32
core/math/big/basic.odin

@@ -321,39 +321,11 @@ lcm :: proc { int_lcm, };
 	remainder = numerator % (1 << bits)
 */
 int_mod_bits :: proc(remainder, numerator: ^Int, bits: int) -> (err: Error) {
-	if err = clear_if_uninitialized(remainder); err != nil { return err; }
-	if err = clear_if_uninitialized(numerator); err != nil { return err; }
-
+	if remainder == nil || numerator == nil { return .Invalid_Pointer; }
+	if err = clear_if_uninitialized(remainder, numerator); err != nil { return err; }
 	if bits  < 0 { return .Invalid_Argument; }
-	if bits == 0 { return zero(remainder); }
-
-	/*
-		If the modulus is larger than the value, return the value.
-	*/
-	err = copy(remainder, numerator);
-	if bits >= (numerator.used * _DIGIT_BITS) || err != nil {
-		return;
-	}
-
-	/*
-		Zero digits above the last digit of the modulus.
-	*/
-	zero_count := (bits / _DIGIT_BITS);
-	zero_count += 0 if (bits % _DIGIT_BITS == 0) else 1;
-
-	/*
-		Zero remainder. Special case, can't use `zero_unused`.
-	*/
-	if zero_count > 0 {
-		mem.zero_slice(remainder.digit[zero_count:]);
-	}
 
-	/*
-		Clear the digit that is not completely outside/inside the modulus.
-	*/
-	remainder.digit[bits / _DIGIT_BITS] &= DIGIT(1 << DIGIT(bits % _DIGIT_BITS)) - DIGIT(1);
-	return clamp(remainder);
+	return #force_inline internal_int_mod_bits(remainder, numerator, bits);
 }
-mod_bits :: proc { int_mod_bits, };
-
 
+mod_bits :: proc { int_mod_bits, };

+ 43 - 5
core/math/big/internal.odin

@@ -876,6 +876,44 @@ internal_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int) -> (err: Error) {
 	return #force_inline _private_int_gcd_lcm(res_gcd, res_lcm, a, b);
 }
 
+/*
+	remainder = numerator % (1 << bits)
+
+	Assumes `remainder` and `numerator` both not to be `nil` and `bits` to be >= 0.
+*/
+internal_int_mod_bits :: proc(remainder, numerator: ^Int, bits: int) -> (err: Error) {
+	/*
+		Everything is divisible by 1 << 0 == 1, so this returns 0.
+	*/
+	if bits == 0 { return zero(remainder); }
+
+	/*
+		If the modulus is larger than the value, return the value.
+	*/
+	err = copy(remainder, numerator);
+	if bits >= (numerator.used * _DIGIT_BITS) || err != nil {
+		return;
+	}
+
+	/*
+		Zero digits above the last digit of the modulus.
+	*/
+	zero_count := (bits / _DIGIT_BITS);
+	zero_count += 0 if (bits % _DIGIT_BITS == 0) else 1;
+
+	/*
+		Zero remainder. Special case, can't use `zero_unused`.
+	*/
+	if zero_count > 0 {
+		mem.zero_slice(remainder.digit[zero_count:]);
+	}
+
+	/*
+		Clear the digit that is not completely outside/inside the modulus.
+	*/
+	remainder.digit[bits / _DIGIT_BITS] &= DIGIT(1 << DIGIT(bits % _DIGIT_BITS)) - DIGIT(1);
+	return clamp(remainder);
+}
 
 internal_int_zero_unused :: #force_inline proc(dest: ^Int, old_used := -1) {
 	/*
@@ -1590,7 +1628,7 @@ _private_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int) -> (err: Error) {
 		/*
 			Subtract smallest from largest.
 		*/
-		if err = sub(v, v, u); err != nil { return err; }
+		if err = internal_sub(v, v, u); err != nil { return err; }
 
 		/*
 			Divide out all factors of two.
@@ -1622,14 +1660,14 @@ _private_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int) -> (err: Error) {
 		/*
 			Store quotient in `t2` such that `t2 * b` is the LCM.
 		*/
-		if err = div(res_lcm, a, temp_gcd_res); err != nil { return err; }
-		err = mul(res_lcm, res_lcm, b);
+		if err = internal_div(res_lcm, a, temp_gcd_res); err != nil { return err; }
+		err = internal_mul(res_lcm, res_lcm, b);
 	} else {
 		/*
 			Store quotient in `t2` such that `t2 * a` is the LCM.
 		*/
-		if err = div(res_lcm, a, temp_gcd_res); err != nil { return err; }
-		err = mul(res_lcm, res_lcm, b);
+		if err = internal_div(res_lcm, a, temp_gcd_res); err != nil { return err; }
+		err = internal_mul(res_lcm, res_lcm, b);
 	}
 
 	if res_gcd != nil {