Selaa lähdekoodia

big: Add `swap`.

Jeroen van Rijn 4 vuotta sitten
vanhempi
commit
0254057f1b
3 muutettua tiedostoa jossa 88 lisäystä ja 29 poistoa
  1. 61 0
      core/math/big/basic.odin
  2. 9 28
      core/math/big/example.odin
  3. 18 1
      core/math/big/helpers.odin

+ 61 - 0
core/math/big/basic.odin

@@ -669,4 +669,65 @@ _int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
 		Adjust dest.used based on leading zeroes.
 	*/
 	return clamp(dest);
+}
+
+
+/*
+	Multiplies |a| * |b| and only computes upto digs digits of result.
+	HAC pp. 595, Algorithm 14.12  Modified so you can control how
+	many digits of output are created.
+*/
+_int_mul :: proc(dest, a, b: ^Int, digits: int) -> (err: Error) {
+
+	/*
+		Can we use the fast multiplier?
+	*/
+	when false { // Have Comba?
+		if digits < _WARRAY && min(a.used, b.used) < _MAX_COMBA {
+			return _int_mul_comba(dest, a, b, digits);
+		}
+	}
+
+	if err = grow(dest, digits); err != .None { return err; }
+	dest.used = digits;
+
+	/*
+
+	/* compute the digits of the product directly */
+	pa = a->used;
+	for (ix = 0; ix < pa; ix++) {
+		int iy, pb;
+		mp_digit u = 0;
+
+		/* limit ourselves to making digs digits of output */
+		pb = MP_MIN(b->used, digs - ix);
+
+		/* compute the columns of the output and propagate the carry */
+		for (iy = 0; iy < pb; iy++) {
+			/* compute the column as a mp_word */
+			mp_word r = (mp_word)t.dp[ix + iy] +
+							((mp_word)a->dp[ix] * (mp_word)b->dp[iy]) +
+							(mp_word)u;
+
+			/* the new column is the lower part of the result */
+			t.dp[ix + iy] = (mp_digit)(r & (mp_word)MP_MASK);
+
+			/* get the carry word from the result */
+			u       = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
+		}
+		/* set carry if it is placed below digs */
+		if ((ix + iy) < digs) {
+			t.dp[ix + pb] = u;
+		}
+	}
+
+	mp_clamp(&t);
+	mp_exch(&t, c);
+
+	mp_clear(&t);
+	return MP_OKAY;
+}
+
+*/
+	return .None;
 }

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

@@ -19,7 +19,7 @@ print_configation :: proc() {
 	DIGIT_BITS           %v
 	MIN_DIGIT_COUNT      %v
 	MAX_DIGIT_COUNT      %v
-	EFAULT_DIGIT_COUNT   %v
+	DEFAULT_DIGIT_COUNT  %v
 	MAX_COMBA            %v
 	WARRAY               %v
 	MUL_KARATSUBA_CUTOFF %v
@@ -57,37 +57,18 @@ demo :: proc() {
 	a, b, c := &Int{}, &Int{}, &Int{};
 	defer destroy(a, b, c);
 
-	err = set(a, 1);
-	err = set(b, 1);
-	err = set(c, -4);
+	err = set(a, -512);
+	err = set(b, 1024);
 
 	print("a", a, 16);
-	print("b", b, 10);
-	print("c", c, 10);
+	print("b", b, 16);
 
-	fmt.println("=== a = a & b ===");
-	err = and(a, a, b);
-	fmt.printf("a &= b error: %v\n", err);
+	fmt.println("--- swap ---");
+	foo(a, b);
 
-	print("a", a, 2);
-	print("b", b, 10);
-
-	fmt.println("\n\n=== b = abs(c) ===");
-	c.sign = .Negative;
-	abs(b, c); // copy c to b.
-
-	print("b", b);
-	print("c", c);
-
-	fmt.println("\n\n=== Set a to (1 << 120) - 1 ===");
-	if err = power_of_two(a, 120); err != .None {
-		fmt.printf("Error %v while setting a to 1 << 120.\n", err);
-	}
-	if err = sub(a, a, 1); err != .None {
-		fmt.printf("Error %v while subtracting 1 from a\n", err);	
-	}
 	print("a", a, 16);
-	fmt.println("Expected a to be:        FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+	print("b", b, 16);
+
 }
 
 main :: proc() {
@@ -95,7 +76,7 @@ main :: proc() {
 	mem.tracking_allocator_init(&ta, context.allocator);
 	context.allocator = mem.tracking_allocator(&ta);
 
-	// print_configation();
+	print_configation();
 	demo();
 
 	if len(ta.allocation_map) > 0 {

+ 18 - 1
core/math/big/helpers.odin

@@ -20,7 +20,10 @@ int_destroy :: proc(integers: ..^Int) {
 
 	for a in &integers {
 		mem.zero_slice(a.digit[:]);
-		free(&a.digit[0]);
+		raw := transmute(mem.Raw_Dynamic_Array)a.digit;
+		if raw.cap > 0 {
+			free(&a.digit[0]);
+		}
 		a = &Int{};
 	}
 }
@@ -84,6 +87,20 @@ int_copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error
 }
 copy :: proc { int_copy, };
 
+/*
+	In normal code, you can also write `a, b = b, a`.
+	However, that only swaps within the current scope.
+	This helper swaps completely.
+*/
+int_swap :: proc(a, b: ^Int) {
+	a := a; b := b;
+
+	a.used,  b.used  = b.used,  a.used;
+	a.sign,  b.sign  = b.sign,  a.sign;
+	a.digit, b.digit = b.digit, a.digit;
+}
+swap :: proc { int_swap, };
+
 /*
 	Set `dest` to |`src`|.
 */