Browse Source

big: Some more work on constants.

Jeroen van Rijn 4 years ago
parent
commit
85a2a8815e

+ 18 - 13
core/math/big/basic.odin

@@ -683,7 +683,11 @@ int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int) -> (err: E
 		// err = _int_div_recursive(quotient, remainder, numerator, denominator);
 		// err = _int_div_recursive(quotient, remainder, numerator, denominator);
 	} else {
 	} else {
 		err = _int_div_school(quotient, remainder, numerator, denominator);
 		err = _int_div_school(quotient, remainder, numerator, denominator);
-		// err = _int_div_small(quotient, remainder, numerator, denominator);
+		/*
+			NOTE(Jeroen): We no longer need or use `_int_div_small`.
+			We'll keep it around for a bit.
+			err = _int_div_small(quotient, remainder, numerator, denominator);
+		*/
 	}
 	}
 
 
 	return err;
 	return err;
@@ -792,7 +796,7 @@ _int_recursive_product :: proc(res: ^Int, start, stop: DIGIT, level := int(0)) -
 
 
 	if num_factors == 1 { return set(res, start); }
 	if num_factors == 1 { return set(res, start); }
 
 
-	return one(res);
+	return set(res, 1);
 }
 }
 
 
 /*
 /*
@@ -804,8 +808,8 @@ int_factorial_binary_split :: proc(res: ^Int, n: DIGIT) -> (err: Error) {
 	inner, outer, start, stop, temp := &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
 	inner, outer, start, stop, temp := &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
 	defer destroy(inner, outer, start, stop, temp);
 	defer destroy(inner, outer, start, stop, temp);
 
 
-	if err = one(inner); err != nil { return err; }
-	if err = one(outer); err != nil { return err; }
+	if err = set(inner, 1); err != nil { return err; }
+	if err = set(outer, 1); err != nil { return err; }
 
 
 	bits_used := int(_DIGIT_TYPE_BITS - intrinsics.count_leading_zeros(n));
 	bits_used := int(_DIGIT_TYPE_BITS - intrinsics.count_leading_zeros(n));
 
 
@@ -896,7 +900,7 @@ _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
 	/* Zero the carry */
 	/* Zero the carry */
 	carry := DIGIT(0);
 	carry := DIGIT(0);
 
 
-	for i = 0; i < min_used; i += 1 {
+	#no_bounds_check for i = 0; i < min_used; i += 1 {
 		/*
 		/*
 			Compute the sum one _DIGIT at a time.
 			Compute the sum one _DIGIT at a time.
 			dest[i] = a[i] + b[i] + carry;
 			dest[i] = a[i] + b[i] + carry;
@@ -918,7 +922,7 @@ _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
 			Now copy higher words, if any, in A+B.
 			Now copy higher words, if any, in A+B.
 			If A or B has more digits, add those in.
 			If A or B has more digits, add those in.
 		*/
 		*/
-		for ; i < max_used; i += 1 {
+		#no_bounds_check for ; i < max_used; i += 1 {
 			dest.digit[i] = x.digit[i] + carry;
 			dest.digit[i] = x.digit[i] + carry;
 			/*
 			/*
 				Compute carry
 				Compute carry
@@ -975,7 +979,7 @@ _int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
 
 
 	borrow := DIGIT(0);
 	borrow := DIGIT(0);
 
 
-	for i = 0; i < min_used; i += 1 {
+	#no_bounds_check for i = 0; i < min_used; i += 1 {
 		dest.digit[i] = (x.digit[i] - y.digit[i] - borrow);
 		dest.digit[i] = (x.digit[i] - y.digit[i] - borrow);
 		/*
 		/*
 			borrow = carry bit of dest[i]
 			borrow = carry bit of dest[i]
@@ -993,7 +997,7 @@ _int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
 	/*
 	/*
 		Now copy higher words if any, e.g. if A has more digits than B
 		Now copy higher words if any, e.g. if A has more digits than B
 	*/
 	*/
-	for ; i < max_used; i += 1 {
+	#no_bounds_check for ; i < max_used; i += 1 {
 		dest.digit[i] = x.digit[i] - borrow;
 		dest.digit[i] = x.digit[i] - borrow;
 		/*
 		/*
 			borrow = carry bit of dest[i]
 			borrow = carry bit of dest[i]
@@ -1058,7 +1062,7 @@ _int_mul :: proc(dest, a, b: ^Int, digits: int) -> (err: Error) {
 		/*
 		/*
 			Compute the column of the output and propagate the carry.
 			Compute the column of the output and propagate the carry.
 		*/
 		*/
-		for iy = 0; iy < pb; iy += 1 {
+		#no_bounds_check for iy = 0; iy < pb; iy += 1 {
 			/*
 			/*
 				Compute the column as a _WORD.
 				Compute the column as a _WORD.
 			*/
 			*/
@@ -1144,7 +1148,7 @@ _int_mul_comba :: proc(dest, a, b: ^Int, digits: int) -> (err: Error) {
 		/*
 		/*
 			Execute loop.
 			Execute loop.
 		*/
 		*/
-		for iz = 0; iz < iy; iz += 1 {
+		#no_bounds_check for iz = 0; iz < iy; iz += 1 {
 			_W += _WORD(a.digit[tx + iz]) * _WORD(b.digit[ty - iz]);
 			_W += _WORD(a.digit[tx + iz]) * _WORD(b.digit[ty - iz]);
 		}
 		}
 
 
@@ -1202,7 +1206,7 @@ _int_sqr :: proc(dest, src: ^Int) -> (err: Error) {
 	if err = grow(t, max((2 * pa) + 1, _DEFAULT_DIGIT_COUNT)); err != nil { return err; }
 	if err = grow(t, max((2 * pa) + 1, _DEFAULT_DIGIT_COUNT)); err != nil { return err; }
 	t.used = (2 * pa) + 1;
 	t.used = (2 * pa) + 1;
 
 
-	for ix = 0; ix < pa; ix += 1 {
+	#no_bounds_check for ix = 0; ix < pa; ix += 1 {
 		carry := DIGIT(0);
 		carry := DIGIT(0);
 		/*
 		/*
 			First calculate the digit at 2*ix; calculate double precision result.
 			First calculate the digit at 2*ix; calculate double precision result.
@@ -1218,7 +1222,7 @@ _int_sqr :: proc(dest, src: ^Int) -> (err: Error) {
 		*/
 		*/
 		carry = DIGIT(r >> _DIGIT_BITS);
 		carry = DIGIT(r >> _DIGIT_BITS);
 
 
-		for iy = ix + 1; iy < pa; iy += 1 {
+		#no_bounds_check for iy = ix + 1; iy < pa; iy += 1 {
 			/*
 			/*
 				First calculate the product.
 				First calculate the product.
 			*/
 			*/
@@ -1242,7 +1246,7 @@ _int_sqr :: proc(dest, src: ^Int) -> (err: Error) {
 		/*
 		/*
 			Propagate upwards.
 			Propagate upwards.
 		*/
 		*/
-		for carry != 0 {
+		#no_bounds_check for carry != 0 {
 			r     = _WORD(t.digit[ix+iy]) + _WORD(carry);
 			r     = _WORD(t.digit[ix+iy]) + _WORD(carry);
 			t.digit[ix+iy] = DIGIT(r & _WORD(_MASK));
 			t.digit[ix+iy] = DIGIT(r & _WORD(_MASK));
 			carry = DIGIT(r >> _WORD(_DIGIT_BITS));
 			carry = DIGIT(r >> _WORD(_DIGIT_BITS));
@@ -1483,6 +1487,7 @@ _int_div_school :: proc(quotient, remainder, numerator, denominator: ^Int) -> (e
 /*
 /*
 	Slower bit-bang division... also smaller.
 	Slower bit-bang division... also smaller.
 */
 */
+@(deprecated="Use `_int_div_school`, it's 3.5x faster.")
 _int_div_small :: proc(quotient, remainder, numerator, denominator: ^Int) -> (err: Error) {
 _int_div_small :: proc(quotient, remainder, numerator, denominator: ^Int) -> (err: Error) {
 
 
 	ta, tb, tq, q := &Int{}, &Int{}, &Int{}, &Int{};
 	ta, tb, tq, q := &Int{}, &Int{}, &Int{}, &Int{};

+ 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

+ 4 - 16
core/math/big/example.odin

@@ -88,7 +88,7 @@ Event :: struct {
 }
 }
 Timings := [Category]Event{};
 Timings := [Category]Event{};
 
 
-print :: proc(name: string, a: ^Int, base := i8(10), print_name := false, newline := true, print_extra_info := false) {
+print :: proc(name: string, a: ^Int, base := i8(10), print_name := true, newline := true, print_extra_info := false) {
 	s := time.tick_now();
 	s := time.tick_now();
 	as, err := itoa(a, base);
 	as, err := itoa(a, base);
 	Timings[.itoa].t += time.tick_since(s); Timings[.itoa].c += 1;
 	Timings[.itoa].t += time.tick_since(s); Timings[.itoa].c += 1;
@@ -118,28 +118,16 @@ demo :: proc() {
 	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);
 
 
-	fmt.println();
-	print(" ONE: ",       ONE, 10, true, true, true);
-	fmt.println();
-
-	one(a);
-	print(" one: ",         a, 10, true, true, true);
-	fmt.println();
-
-	minus_one(a);
-	print("-one: ",         a, 10, true, true, true);
-	fmt.println();
-
 	nan(a);
 	nan(a);
-	print(" nan: ",         a, 10, true, true, true);
+	print(" nan: ", a, 10, true, true, true);
 	fmt.println();
 	fmt.println();
 
 
 	inf(a);
 	inf(a);
-	print(" inf: ",         a, 10, true, true, true);
+	print(" inf: ", a, 10, true, true, true);
 	fmt.println();
 	fmt.println();
 
 
 	minus_inf(a);
 	minus_inf(a);
-	print("-inf: ",         a, 10, true, true, true);
+	print("-inf: ", a, 10, true, true, true);
 	fmt.println();
 	fmt.println();
 
 
 
 

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

@@ -51,7 +51,7 @@ int_pow :: proc(dest, base: ^Int, power: int) -> (err: Error) {
 			if err = zero(dest); err != nil { return err; }
 			if err = zero(dest); err != nil { return err; }
 			return .Math_Domain_Error;
 			return .Math_Domain_Error;
 		}
 		}
-		if power == 0 { return  one(dest); }
+		if power == 0 { return  set(dest, 1); }
 		if power  > 0 { return zero(dest); }
 		if power  > 0 { return zero(dest); }
 
 
 	}
 	}
@@ -429,7 +429,7 @@ _int_log :: proc(a: ^Int, base: DIGIT) -> (res: int, err: Error) {
 
 
 	if err = set(bi_base, base);          err != nil { return -1, err; }
 	if err = set(bi_base, base);          err != nil { return -1, err; }
 	if err = init_multi(bracket_mid, t);  err != nil { return -1, err; }
 	if err = init_multi(bracket_mid, t);  err != nil { return -1, err; }
-	if err = one(bracket_low);            err != nil { return -1, err; }
+	if err = set(bracket_low, 1);         err != nil { return -1, err; }
 	if err = set(bracket_high, base);     err != nil { return -1, err; }
 	if err = set(bracket_high, base);     err != nil { return -1, err; }
 
 
 	low  := 0; high := 1;
 	low  := 0; high := 1;

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

@@ -13,6 +13,10 @@ import "core:mem"
 import "core:intrinsics"
 import "core:intrinsics"
 import rnd "core:math/rand"
 import rnd "core:math/rand"
 
 
+/*
+	TODO: Int.flags and Constants like ONE, NAN, etc, are not yet properly handled everywhere.
+*/
+
 /*
 /*
 	Deallocates the backing memory of one or more `Int`s.
 	Deallocates the backing memory of one or more `Int`s.
 */
 */
@@ -35,10 +39,13 @@ int_destroy :: proc(integers: ..^Int) {
 int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator := context.allocator) -> (err: Error)
 int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator := context.allocator) -> (err: Error)
 	where intrinsics.type_is_integer(T) {
 	where intrinsics.type_is_integer(T) {
 	src := src;
 	src := src;
-	if err = clear_if_uninitialized(dest); err != nil {
-		return err;
-	}
-	dest.used = 0;
+
+	if err = error_if_immutable(dest); err != nil { return err; }
+	if err = clear_if_uninitialized(dest); err != nil { return err; }
+
+	dest.flags = {}; // We're not -Inf, Inf, NaN or Immutable.
+
+	dest.used  = 0;
 	dest.sign = .Zero_or_Positive if src >= 0 else .Negative;
 	dest.sign = .Zero_or_Positive if src >= 0 else .Negative;
 	src = abs(src);
 	src = abs(src);
 
 
@@ -57,19 +64,21 @@ set :: proc { int_set_from_integer, int_copy };
 	Copy one `Int` to another.
 	Copy one `Int` to another.
 */
 */
 int_copy :: proc(dest, src: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
 int_copy :: proc(dest, src: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
-	if err = error_if_immutable(dest);    err != nil { return err; }
-	if err = clear_if_uninitialized(src); err != nil { return err; }
 	/*
 	/*
 		If dest == src, do nothing
 		If dest == src, do nothing
 	*/
 	*/
-	if (dest == src) {
-		return nil;
-	}
+	if (dest == src) { return nil; }
+
+	if err = error_if_immutable(dest);    err != nil { return err; }
+	if err = clear_if_uninitialized(src); err != nil { return err; }
+
 	/*
 	/*
 		Grow `dest` to fit `src`.
 		Grow `dest` to fit `src`.
 		If `dest` is not yet initialized, it will be using `allocator`.
 		If `dest` is not yet initialized, it will be using `allocator`.
 	*/
 	*/
-	if err = grow(dest, src.used, minimize, allocator); err != nil {
+	needed := src.used if minimize else max(src.used, _DEFAULT_DIGIT_COUNT);
+
+	if err = grow(dest, needed, minimize, allocator); err != nil {
 		return err;
 		return err;
 	}
 	}
 
 
@@ -340,7 +349,7 @@ zero  :: clear;
 	Set the `Int` to 1 and optionally shrink it to the minimum backing size.
 	Set the `Int` to 1 and optionally shrink it to the minimum backing size.
 */
 */
 int_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
 int_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
-	return set(a, 1);
+	return set(a, 1, minimize, allocator);
 }
 }
 one :: proc { int_one, };
 one :: proc { int_one, };
 
 
@@ -348,7 +357,7 @@ one :: proc { int_one, };
 	Set the `Int` to -1 and optionally shrink it to the minimum backing size.
 	Set the `Int` to -1 and optionally shrink it to the minimum backing size.
 */
 */
 int_minus_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
 int_minus_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
-	return set(a, -1);
+	return set(a, -1, minimize, allocator);
 }
 }
 minus_one :: proc { int_minus_one, };
 minus_one :: proc { int_minus_one, };
 
 
@@ -356,7 +365,9 @@ minus_one :: proc { int_minus_one, };
 	Set the `Int` to Inf and optionally shrink it to the minimum backing size.
 	Set the `Int` to Inf and optionally shrink it to the minimum backing size.
 */
 */
 int_inf :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
 int_inf :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
-	return copy(a, INF, minimize, allocator);
+	err = set(a, 1, minimize, allocator);
+	a.flags |= { .Inf, };
+	return err;
 }
 }
 inf :: proc { int_inf, };
 inf :: proc { int_inf, };
 
 
@@ -364,7 +375,9 @@ inf :: proc { int_inf, };
 	Set the `Int` to -Inf and optionally shrink it to the minimum backing size.
 	Set the `Int` to -Inf and optionally shrink it to the minimum backing size.
 */
 */
 int_minus_inf :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
 int_minus_inf :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
-	return copy(a, MINUS_INF, minimize, allocator);
+	err = set(a, -1, minimize, allocator);
+	a.flags |= { .Inf, };
+	return err;
 }
 }
 minus_inf :: proc { int_inf, };
 minus_inf :: proc { int_inf, };
 
 
@@ -372,7 +385,9 @@ minus_inf :: proc { int_inf, };
 	Set the `Int` to NaN and optionally shrink it to the minimum backing size.
 	Set the `Int` to NaN and optionally shrink it to the minimum backing size.
 */
 */
 int_nan :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
 int_nan :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
-	return copy(a, NAN, minimize, allocator);
+	err = set(a, 1, minimize, allocator);
+	a.flags |= { .NaN, };
+	return err;
 }
 }
 nan :: proc { int_nan, };
 nan :: proc { int_nan, };
 
 
@@ -691,9 +706,14 @@ initialize_constants :: proc() -> (res: int) {
 	set(     ZERO,  0);      ZERO.flags = {.Immutable};
 	set(     ZERO,  0);      ZERO.flags = {.Immutable};
 	set(      ONE,  1);       ONE.flags = {.Immutable};
 	set(      ONE,  1);       ONE.flags = {.Immutable};
 	set(MINUS_ONE, -1); MINUS_ONE.flags = {.Immutable};
 	set(MINUS_ONE, -1); MINUS_ONE.flags = {.Immutable};
-	set(      INF,  0);       INF.flags = {.Immutable, .Inf};
-	set(      INF,  0); MINUS_INF.flags = {.Immutable, .Inf}; MINUS_INF.sign = .Negative;
-	set(      NAN,  0);       NAN.flags = {.Immutable, .NaN};
+
+	/*
+		We set these special values to -1 or 1 so they don't get mistake for zero accidentally.
+		This allows for shortcut tests of is_zero as .used == 0.
+	*/
+	set(      INF,  1);       INF.flags = {.Immutable, .Inf};
+	set(      INF, -1); MINUS_INF.flags = {.Immutable, .Inf};
+	set(      NAN,  1);       NAN.flags = {.Immutable, .NaN};
 
 
 	return #config(MUL_KARATSUBA_CUTOFF, _DEFAULT_MUL_KARATSUBA_CUTOFF);
 	return #config(MUL_KARATSUBA_CUTOFF, _DEFAULT_MUL_KARATSUBA_CUTOFF);
 }
 }