Browse Source

big: Add `mod` and `addmod`.

Jeroen van Rijn 4 years ago
parent
commit
5f7aeb3045
2 changed files with 54 additions and 8 deletions
  1. 49 3
      core/math/big/basic.odin
  2. 5 5
      core/math/big/example.odin

+ 49 - 3
core/math/big/basic.odin

@@ -662,14 +662,60 @@ int_div :: proc(quotient, remainder, numerator, denominator: ^Int) -> (err: Erro
 	*/
 	if quotient == nil && remainder == nil 		        { return .None; }
 
-
 	if err = clear_if_uninitialized(numerator);			err != .None { return err; }
 	if err = clear_if_uninitialized(denominator);		err != .None { return err; }
 
-	return _int_div_small(quotient, remainder, numerator, denominator);
+	z: bool;
+	if z, err = is_zero(denominator);                   z { return .Division_by_Zero; }
+
+	/*
+		If numerator < denominator then quotient = 0, remainder = numerator.
+	*/
+	c: int;
+	if c, err = cmp_mag(numerator, denominator); c == -1 {
+		if remainder != nil {
+			if err = copy(remainder, numerator); 		err != .None { return err; }
+		}
+		if quotient != nil {
+			zero(quotient);
+		}
+		return .None;
+	}
+
+	if false && (denominator.used > 2 * _MUL_KARATSUBA_CUTOFF) && (denominator.used <= (numerator.used/3) * 2) {
+		// err = _int_div_recursive(quotient, remainder, numerator, denominator);
+	} else if false {
+		// err = _int_div_school(quotient, remainder, numerator, denominator);
+	} else {
+		err = _int_div_small(quotient, remainder, numerator, denominator);
+	}
+
+	return err;
 }
 div :: proc{ int_div, };
 
+/*
+	remainder = numerator % denominator.
+	0 <= remainder < denominator if denominator > 0
+	denominator < remainder <= 0 if denominator < 0
+*/
+int_mod :: proc(remainder, numerator, denominator: ^Int) -> (err: Error) {
+	if err = div(nil, remainder, numerator, denominator); err != .None { return err; }
+
+	z: bool;
+	if z, err = is_zero(remainder); z || denominator.sign == remainder.sign { return .None; }
+	return add(remainder, remainder, numerator);
+}
+mod :: proc { int_mod, };
+
+/*
+	remainder = (number + addend) % modulus.
+*/
+int_addmod :: proc(remainder, number, addend, modulus: ^Int) -> (err: Error) {
+	if err = add(remainder, number, addend); err != .None { return err; }
+	return mod(remainder, remainder, modulus);
+}
+addmod :: proc { int_addmod, };
 
 /*
 	==========================
@@ -974,7 +1020,7 @@ _int_sqr :: proc(dest, src: ^Int) -> (err: Error) {
 }
 
 /*
-	Fivide by three (based on routine from MPI and the GMP manual).
+	Divide by three (based on routine from MPI and the GMP manual).
 */
 _int_div_3 :: proc(quotient, numerator: ^Int) -> (remainder: int, err: Error) {
 	/*

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

@@ -67,16 +67,16 @@ demo :: proc() {
 	destination, source, quotient, remainder, numerator, denominator := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
 	defer destroy(destination, source, quotient, remainder, numerator, denominator);
 
-	err = set (numerator,   2);
-	err = set (denominator, 3);
-	err = zero(quotient);
+	err = set (numerator,   3);
+	err = set (denominator, 2);
+	err = set (quotient,    3);
 	err = zero(remainder);
 
-	err = pow(numerator, numerator, 260);
+	err = addmod(remainder, numerator, denominator, quotient);
 	if err != .None {
 		fmt.printf("Error: %v\n", err);
 	} else {
-		print("numerator  ", numerator,   16);
+		print("numerator  ", numerator,   10);
 		print("denominator", denominator, 10);
 		print("quotient   ", quotient,    10);
 		print("remainder  ", remainder,   10);