mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-01 04:10:07 +00:00
big: Add constants.
This commit is contained in:
+33
-27
@@ -26,10 +26,15 @@ when _LOW_MEMORY {
|
|||||||
_DEFAULT_DIGIT_COUNT :: 32;
|
_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);
|
`initialize_constants` returns `#config(MUL_KARATSUBA_CUTOFF, _DEFAULT_MUL_KARATSUBA_CUTOFF)`
|
||||||
_MUL_TOOM_CUTOFF :: #config(MUL_TOOM_CUTOFF, _DEFAULT_MUL_TOOM_CUTOFF);
|
and we initialize this cutoff that way so that the procedure is used and called,
|
||||||
_SQR_TOOM_CUTOFF :: #config(SQR_TOOM_CUTOFF, _DEFAULT_SQR_TOOM_CUTOFF);
|
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`.
|
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 {
|
Int :: struct {
|
||||||
used: int,
|
used: int,
|
||||||
digit: [dynamic]DIGIT,
|
digit: [dynamic]DIGIT,
|
||||||
sign: Sign,
|
sign: Sign,
|
||||||
|
flags: Flags,
|
||||||
};
|
};
|
||||||
|
|
||||||
Flag :: enum u8 {
|
Flag :: enum u8 {
|
||||||
@@ -76,35 +82,35 @@ Flags :: bit_set[Flag; u8];
|
|||||||
Errors are a strict superset of runtime.Allocation_Error.
|
Errors are a strict superset of runtime.Allocation_Error.
|
||||||
*/
|
*/
|
||||||
Error :: enum int {
|
Error :: enum int {
|
||||||
Out_Of_Memory = 1,
|
Out_Of_Memory = 1,
|
||||||
Invalid_Pointer = 2,
|
Invalid_Pointer = 2,
|
||||||
Invalid_Argument = 3,
|
Invalid_Argument = 3,
|
||||||
|
|
||||||
Unknown_Error = 4,
|
Assignment_To_Immutable = 4,
|
||||||
Max_Iterations_Reached = 5,
|
Max_Iterations_Reached = 5,
|
||||||
Buffer_Overflow = 6,
|
Buffer_Overflow = 6,
|
||||||
Integer_Overflow = 7,
|
Integer_Overflow = 7,
|
||||||
|
|
||||||
Division_by_Zero = 8,
|
Division_by_Zero = 8,
|
||||||
Math_Domain_Error = 9,
|
Math_Domain_Error = 9,
|
||||||
|
|
||||||
Unimplemented = 127,
|
Unimplemented = 127,
|
||||||
};
|
};
|
||||||
|
|
||||||
Error_String :: #partial [Error]string{
|
Error_String :: #partial [Error]string{
|
||||||
.Out_Of_Memory = "Out of memory",
|
.Out_Of_Memory = "Out of memory",
|
||||||
.Invalid_Pointer = "Invalid pointer",
|
.Invalid_Pointer = "Invalid pointer",
|
||||||
.Invalid_Argument = "Invalid argument",
|
.Invalid_Argument = "Invalid argument",
|
||||||
|
|
||||||
.Unknown_Error = "Unknown error",
|
.Assignment_To_Immutable = "Assignment to immutable",
|
||||||
.Max_Iterations_Reached = "Max iterations reached",
|
.Max_Iterations_Reached = "Max iterations reached",
|
||||||
.Buffer_Overflow = "Buffer overflow",
|
.Buffer_Overflow = "Buffer overflow",
|
||||||
.Integer_Overflow = "Integer overflow",
|
.Integer_Overflow = "Integer overflow",
|
||||||
|
|
||||||
.Division_by_Zero = "Division by zero",
|
.Division_by_Zero = "Division by zero",
|
||||||
.Math_Domain_Error = "Math domain error",
|
.Math_Domain_Error = "Math domain error",
|
||||||
|
|
||||||
.Unimplemented = "Unimplemented",
|
.Unimplemented = "Unimplemented",
|
||||||
};
|
};
|
||||||
|
|
||||||
Primality_Flag :: enum u8 {
|
Primality_Flag :: enum u8 {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ _SQR_KARATSUBA_CUTOFF,
|
|||||||
_MUL_TOOM_CUTOFF,
|
_MUL_TOOM_CUTOFF,
|
||||||
_SQR_TOOM_CUTOFF,
|
_SQR_TOOM_CUTOFF,
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
print_timings :: proc() {
|
print_timings :: proc() {
|
||||||
@@ -95,16 +96,15 @@ print :: proc(name: string, a: ^Int, base := i8(10), print_name := false, newlin
|
|||||||
defer delete(as);
|
defer delete(as);
|
||||||
cb, _ := count_bits(a);
|
cb, _ := count_bits(a);
|
||||||
if print_name {
|
if print_name {
|
||||||
fmt.printf("%v ", 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);
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.printf("%v (error: %v | %v)", name, err, a);
|
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 {
|
if newline {
|
||||||
fmt.println();
|
fmt.println();
|
||||||
}
|
}
|
||||||
@@ -118,6 +118,31 @@ 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);
|
||||||
|
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.
|
factorial(a, 128); // Untimed warmup.
|
||||||
|
|
||||||
N :: 128;
|
N :: 128;
|
||||||
@@ -145,8 +170,8 @@ main :: proc() {
|
|||||||
mem.tracking_allocator_init(&ta, context.allocator);
|
mem.tracking_allocator_init(&ta, context.allocator);
|
||||||
context.allocator = mem.tracking_allocator(&ta);
|
context.allocator = mem.tracking_allocator(&ta);
|
||||||
|
|
||||||
// print_configation();
|
|
||||||
demo();
|
demo();
|
||||||
|
|
||||||
print_timings();
|
print_timings();
|
||||||
|
|
||||||
if len(ta.allocation_map) > 0 {
|
if len(ta.allocation_map) > 0 {
|
||||||
|
|||||||
+68
-25
@@ -56,7 +56,8 @@ set :: proc { int_set_from_integer, int_copy };
|
|||||||
/*
|
/*
|
||||||
Copy one `Int` to another.
|
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 err = clear_if_uninitialized(src); err != nil { return err; }
|
||||||
/*
|
/*
|
||||||
If dest == src, do nothing
|
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`.
|
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, false, allocator); err != nil {
|
if err = grow(dest, src.used, minimize, allocator); err != nil {
|
||||||
return err;
|
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] {
|
for v, i in src.digit[:src.used] {
|
||||||
dest.digit[i] = v;
|
dest.digit[i] = v;
|
||||||
}
|
}
|
||||||
dest.used = src.used;
|
dest.used = src.used;
|
||||||
dest.sign = src.sign;
|
dest.sign = src.sign;
|
||||||
|
dest.flags = src.flags &~ {.Immutable};
|
||||||
|
|
||||||
_zero_unused(dest);
|
_zero_unused(dest);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
@@ -120,7 +123,7 @@ int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
|
|||||||
/*
|
/*
|
||||||
Copy `src` to `dest`
|
Copy `src` to `dest`
|
||||||
*/
|
*/
|
||||||
if err = copy(dest, src, allocator); err != nil {
|
if err = copy(dest, src, false, allocator); err != nil {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +166,7 @@ neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
Copy `src` to `dest`
|
Copy `src` to `dest`
|
||||||
*/
|
*/
|
||||||
if err = copy(dest, src, allocator); err != nil {
|
if err = copy(dest, src, false, allocator); err != nil {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,12 +340,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) {
|
||||||
if err = clear(a, minimize, allocator); err != nil { return err; }
|
return copy(a, ONE, minimize, allocator);
|
||||||
|
|
||||||
a.used = 1;
|
|
||||||
a.digit[0] = 1;
|
|
||||||
a.sign = .Zero_or_Positive;
|
|
||||||
return nil;
|
|
||||||
}
|
}
|
||||||
one :: proc { int_one, };
|
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.
|
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) {
|
||||||
if err = clear(a, minimize, allocator); err != nil {
|
return copy(a, MINUS_ONE, minimize, allocator);
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.used = 1;
|
|
||||||
a.digit[0] = 1;
|
|
||||||
a.sign = .Negative;
|
|
||||||
return nil;
|
|
||||||
}
|
}
|
||||||
minus_one :: proc { int_minus_one, };
|
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) {
|
power_of_two :: proc(a: ^Int, power: int) -> (err: Error) {
|
||||||
/*
|
/*
|
||||||
Check that `a` is usable.
|
Check that `a` is usable.
|
||||||
@@ -602,9 +617,21 @@ clear_if_uninitialized_multi :: proc(args: ..^Int) -> (err: Error) {
|
|||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_if_uninitialized :: proc {clear_if_uninitialized_single, clear_if_uninitialized_multi, };
|
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.
|
Allocates several `Int`s at once.
|
||||||
*/
|
*/
|
||||||
@@ -655,7 +682,23 @@ clamp :: proc(a: ^Int) -> (err: Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_STATIC_ZERO := &Int{
|
/*
|
||||||
used = 0,
|
Initialize constants.
|
||||||
sign = .Zero_or_Positive,
|
*/
|
||||||
};
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user