aboutsummaryrefslogtreecommitdiff
path: root/core/math/big
diff options
context:
space:
mode:
authorJeroen van Rijn <Kelimion@users.noreply.github.com>2021-08-03 19:52:14 +0200
committerJeroen van Rijn <Kelimion@users.noreply.github.com>2021-08-11 20:59:52 +0200
commitfc0a92f8ace0e8a6f42d7666b8d4cb92cfb0df3e (patch)
treebe538620846e073e70fca1d4accf320603ac94d1 /core/math/big
parent97d80d03f9902872bcd12e460822dce70e6d3fd1 (diff)
big: Add constants.
Diffstat (limited to 'core/math/big')
-rw-r--r--core/math/big/common.odin60
-rw-r--r--core/math/big/example.odin39
-rw-r--r--core/math/big/helpers.odin93
3 files changed, 133 insertions, 59 deletions
diff --git a/core/math/big/common.odin b/core/math/big/common.odin
index cad6524e5..7943c0e4b 100644
--- a/core/math/big/common.odin
+++ b/core/math/big/common.odin
@@ -26,10 +26,15 @@ when _LOW_MEMORY {
_DEFAULT_DIGIT_COUNT :: 32;
}
-_MUL_KARATSUBA_CUTOFF :: #config(MUL_KARATSUBA_CUTOFF, _DEFAULT_MUL_KARATSUBA_CUTOFF);
-_SQR_KARATSUBA_CUTOFF :: #config(SQR_KARATSUBA_CUTOFF, _DEFAULT_SQR_KARATSUBA_CUTOFF);
-_MUL_TOOM_CUTOFF :: #config(MUL_TOOM_CUTOFF, _DEFAULT_MUL_TOOM_CUTOFF);
-_SQR_TOOM_CUTOFF :: #config(SQR_TOOM_CUTOFF, _DEFAULT_SQR_TOOM_CUTOFF);
+/*
+ `initialize_constants` returns `#config(MUL_KARATSUBA_CUTOFF, _DEFAULT_MUL_KARATSUBA_CUTOFF)`
+ and we initialize this cutoff that way so that the procedure is used and called,
+ because it handles initializing the constants ONE, ZERO, MINUS_ONE, NAN and INF.
+*/
+_MUL_KARATSUBA_CUTOFF := initialize_constants();
+_SQR_KARATSUBA_CUTOFF := #config(SQR_KARATSUBA_CUTOFF, _DEFAULT_SQR_KARATSUBA_CUTOFF);
+_MUL_TOOM_CUTOFF := #config(MUL_TOOM_CUTOFF, _DEFAULT_MUL_TOOM_CUTOFF);
+_SQR_TOOM_CUTOFF := #config(SQR_TOOM_CUTOFF, _DEFAULT_SQR_TOOM_CUTOFF);
/*
These defaults were tuned on an AMD A8-6600K (64-bit) using libTomMath's `make tune`.
@@ -59,9 +64,10 @@ Sign :: enum u8 {
};
Int :: struct {
- used: int,
- digit: [dynamic]DIGIT,
- sign: Sign,
+ used: int,
+ digit: [dynamic]DIGIT,
+ sign: Sign,
+ flags: Flags,
};
Flag :: enum u8 {
@@ -76,35 +82,35 @@ Flags :: bit_set[Flag; u8];
Errors are a strict superset of runtime.Allocation_Error.
*/
Error :: enum int {
- Out_Of_Memory = 1,
- Invalid_Pointer = 2,
- Invalid_Argument = 3,
+ Out_Of_Memory = 1,
+ Invalid_Pointer = 2,
+ Invalid_Argument = 3,
- Unknown_Error = 4,
- Max_Iterations_Reached = 5,
- Buffer_Overflow = 6,
- Integer_Overflow = 7,
+ Assignment_To_Immutable = 4,
+ Max_Iterations_Reached = 5,
+ Buffer_Overflow = 6,
+ Integer_Overflow = 7,
- Division_by_Zero = 8,
- Math_Domain_Error = 9,
+ Division_by_Zero = 8,
+ Math_Domain_Error = 9,
- Unimplemented = 127,
+ Unimplemented = 127,
};
Error_String :: #partial [Error]string{
- .Out_Of_Memory = "Out of memory",
- .Invalid_Pointer = "Invalid pointer",
- .Invalid_Argument = "Invalid argument",
+ .Out_Of_Memory = "Out of memory",
+ .Invalid_Pointer = "Invalid pointer",
+ .Invalid_Argument = "Invalid argument",
- .Unknown_Error = "Unknown error",
- .Max_Iterations_Reached = "Max iterations reached",
- .Buffer_Overflow = "Buffer overflow",
- .Integer_Overflow = "Integer overflow",
+ .Assignment_To_Immutable = "Assignment to immutable",
+ .Max_Iterations_Reached = "Max iterations reached",
+ .Buffer_Overflow = "Buffer overflow",
+ .Integer_Overflow = "Integer overflow",
- .Division_by_Zero = "Division by zero",
- .Math_Domain_Error = "Math domain error",
+ .Division_by_Zero = "Division by zero",
+ .Math_Domain_Error = "Math domain error",
- .Unimplemented = "Unimplemented",
+ .Unimplemented = "Unimplemented",
};
Primality_Flag :: enum u8 {
diff --git a/core/math/big/example.odin b/core/math/big/example.odin
index 7dc6329c6..96d036570 100644
--- a/core/math/big/example.odin
+++ b/core/math/big/example.odin
@@ -39,6 +39,7 @@ _SQR_KARATSUBA_CUTOFF,
_MUL_TOOM_CUTOFF,
_SQR_TOOM_CUTOFF,
);
+
}
print_timings :: proc() {
@@ -95,16 +96,15 @@ print :: proc(name: string, a: ^Int, base := i8(10), print_name := false, newlin
defer delete(as);
cb, _ := count_bits(a);
if print_name {
- fmt.printf("%v ", name);
- }
- if print_extra_info {
- fmt.printf("(base: %v, bits used: %v): %v", base, cb, as);
- } else {
- fmt.printf("%v", as);
+ fmt.printf("%v", name);
}
if err != nil {
fmt.printf("%v (error: %v | %v)", name, err, a);
}
+ fmt.printf("%v", as);
+ if print_extra_info {
+ fmt.printf(" (base: %v, bits used: %v, flags: %v)", base, cb, a.flags);
+ }
if newline {
fmt.println();
}
@@ -118,6 +118,31 @@ demo :: proc() {
a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
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);
+ print(" nan: ", a, 10, true, true, true);
+ fmt.println();
+
+ inf(a);
+ print(" inf: ", a, 10, true, true, true);
+ fmt.println();
+
+ minus_inf(a);
+ print("-inf: ", a, 10, true, true, true);
+ fmt.println();
+
+
factorial(a, 128); // Untimed warmup.
N :: 128;
@@ -145,8 +170,8 @@ main :: proc() {
mem.tracking_allocator_init(&ta, context.allocator);
context.allocator = mem.tracking_allocator(&ta);
- // print_configation();
demo();
+
print_timings();
if len(ta.allocation_map) > 0 {
diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin
index c14690279..d4b5d0220 100644
--- a/core/math/big/helpers.odin
+++ b/core/math/big/helpers.odin
@@ -56,7 +56,8 @@ set :: proc { int_set_from_integer, int_copy };
/*
Copy one `Int` to another.
*/
-int_copy :: proc(dest, src: ^Int, 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
@@ -68,7 +69,7 @@ int_copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error
Grow `dest` to fit `src`.
If `dest` is not yet initialized, it will be using `allocator`.
*/
- if err = grow(dest, src.used, false, allocator); err != nil {
+ if err = grow(dest, src.used, minimize, allocator); err != nil {
return err;
}
@@ -78,8 +79,10 @@ int_copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error
for v, i in src.digit[:src.used] {
dest.digit[i] = v;
}
- dest.used = src.used;
- dest.sign = src.sign;
+ dest.used = src.used;
+ dest.sign = src.sign;
+ dest.flags = src.flags &~ {.Immutable};
+
_zero_unused(dest);
return nil;
}
@@ -120,7 +123,7 @@ int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
/*
Copy `src` to `dest`
*/
- if err = copy(dest, src, allocator); err != nil {
+ if err = copy(dest, src, false, allocator); err != nil {
return err;
}
@@ -163,7 +166,7 @@ neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
/*
Copy `src` to `dest`
*/
- if err = copy(dest, src, allocator); err != nil {
+ if err = copy(dest, src, false, allocator); err != nil {
return err;
}
@@ -337,12 +340,7 @@ zero :: clear;
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) {
- if err = clear(a, minimize, allocator); err != nil { return err; }
-
- a.used = 1;
- a.digit[0] = 1;
- a.sign = .Zero_or_Positive;
- return nil;
+ return copy(a, ONE, minimize, allocator);
}
one :: proc { int_one, };
@@ -350,17 +348,34 @@ one :: proc { int_one, };
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) {
- if err = clear(a, minimize, allocator); err != nil {
- return err;
- }
-
- a.used = 1;
- a.digit[0] = 1;
- a.sign = .Negative;
- return nil;
+ return copy(a, MINUS_ONE, minimize, allocator);
}
minus_one :: proc { int_minus_one, };
+/*
+ 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) {
+ return copy(a, INF, minimize, allocator);
+}
+inf :: proc { int_inf, };
+
+/*
+ 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) {
+ return copy(a, MINUS_INF, minimize, allocator);
+}
+minus_inf :: proc { int_inf, };
+
+/*
+ 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) {
+ return copy(a, NAN, minimize, allocator);
+}
+nan :: proc { int_nan, };
+
power_of_two :: proc(a: ^Int, power: int) -> (err: Error) {
/*
Check that `a` is usable.
@@ -602,9 +617,21 @@ clear_if_uninitialized_multi :: proc(args: ..^Int) -> (err: Error) {
}
return err;
}
-
clear_if_uninitialized :: proc {clear_if_uninitialized_single, clear_if_uninitialized_multi, };
+error_if_immutable_single :: proc(arg: ^Int) -> (err: Error) {
+ if arg != nil && .Immutable in arg.flags { return .Assignment_To_Immutable; }
+ return nil;
+}
+
+error_if_immutable_multi :: proc(args: ..^Int) -> (err: Error) {
+ for i in args {
+ if i != nil && .Immutable in i.flags { return .Assignment_To_Immutable; }
+ }
+ return nil;
+}
+error_if_immutable :: proc {error_if_immutable_single, error_if_immutable_multi, };
+
/*
Allocates several `Int`s at once.
*/
@@ -655,7 +682,23 @@ clamp :: proc(a: ^Int) -> (err: Error) {
}
-_STATIC_ZERO := &Int{
- used = 0,
- sign = .Zero_or_Positive,
-};
+/*
+ Initialize constants.
+*/
+ONE, ZERO, MINUS_ONE, INF, MINUS_INF, NAN := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
+
+initialize_constants :: proc() -> (res: int) {
+ set( ZERO, 0); ZERO.flags = {.Immutable};
+ set( ONE, 1); 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};
+
+ return #config(MUL_KARATSUBA_CUTOFF, _DEFAULT_MUL_KARATSUBA_CUTOFF);
+}
+
+destroy_constants :: proc() {
+ destroy(ONE, ZERO, MINUS_ONE, INF, NAN);
+}
+