mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-02 12:48:14 +00:00
Remove unneeded semicolons from the core library
This commit is contained in:
+16
-16
@@ -31,7 +31,7 @@ add :: proc {
|
||||
int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error)
|
||||
*/
|
||||
int_add_digit,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
err = sub(dest, a, b);
|
||||
@@ -45,7 +45,7 @@ sub :: proc {
|
||||
int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error)
|
||||
*/
|
||||
int_sub_digit,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
=== === === === === === === === === === === === === === === === === === === === === === === ===
|
||||
@@ -59,44 +59,44 @@ is_initialized :: proc {
|
||||
int_is_initialized :: proc(a: ^Int) -> bool
|
||||
*/
|
||||
int_is_initialized,
|
||||
};
|
||||
}
|
||||
|
||||
is_zero :: proc {
|
||||
/*
|
||||
int_is_zero :: proc(a: ^Int) -> bool
|
||||
*/
|
||||
int_is_zero,
|
||||
};
|
||||
}
|
||||
|
||||
is_positive :: proc {
|
||||
/*
|
||||
int_is_positive :: proc(a: ^Int) -> bool
|
||||
*/
|
||||
int_is_positive,
|
||||
};
|
||||
is_pos :: is_positive;
|
||||
}
|
||||
is_pos :: is_positive
|
||||
|
||||
is_negative :: proc {
|
||||
/*
|
||||
int_is_negative :: proc(a: ^Int) -> bool
|
||||
*/
|
||||
int_is_negative,
|
||||
};
|
||||
is_neg :: is_negative;
|
||||
}
|
||||
is_neg :: is_negative
|
||||
|
||||
is_even :: proc {
|
||||
/*
|
||||
int_is_even :: proc(a: ^Int) -> bool
|
||||
*/
|
||||
int_is_even,
|
||||
};
|
||||
}
|
||||
|
||||
is_odd :: proc {
|
||||
/*
|
||||
int_is_odd :: proc(a: ^Int) -> bool
|
||||
*/
|
||||
int_is_odd,
|
||||
};
|
||||
}
|
||||
|
||||
is_power_of_two :: proc {
|
||||
/*
|
||||
@@ -107,7 +107,7 @@ is_power_of_two :: proc {
|
||||
int_is_power_of_two :: proc(a: ^Int) -> (res: bool)
|
||||
*/
|
||||
int_is_power_of_two,
|
||||
};
|
||||
}
|
||||
|
||||
compare :: proc {
|
||||
/*
|
||||
@@ -122,16 +122,16 @@ compare :: proc {
|
||||
int_compare_digit :: proc(a: ^Int, u: DIGIT) -> Comparison_Flag
|
||||
*/
|
||||
int_compare_digit,
|
||||
};
|
||||
cmp :: compare;
|
||||
}
|
||||
cmp :: compare
|
||||
|
||||
compare_magnitude :: proc {
|
||||
/*
|
||||
Compare the magnitude of two `Int`s, unsigned.
|
||||
*/
|
||||
int_compare_magnitude,
|
||||
};
|
||||
cmp_mag :: compare_magnitude;
|
||||
}
|
||||
cmp_mag :: compare_magnitude
|
||||
|
||||
/*
|
||||
=== === === === === === === === === === === === === === === === === === === === === === === ===
|
||||
@@ -147,6 +147,6 @@ destroy :: proc {
|
||||
int_destroy :: proc(integers: ..^Int)
|
||||
*/
|
||||
int_destroy,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
+45
-45
@@ -33,15 +33,15 @@ import "core:intrinsics"
|
||||
To allow tests to run we add `-define:MATH_BIG_EXE=false` to hardcode the cutoffs for now.
|
||||
*/
|
||||
when #config(MATH_BIG_EXE, true) {
|
||||
MUL_KARATSUBA_CUTOFF := initialize_constants();
|
||||
SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF;
|
||||
MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF;
|
||||
SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF;
|
||||
MUL_KARATSUBA_CUTOFF := initialize_constants()
|
||||
SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF
|
||||
MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF
|
||||
SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF
|
||||
} else {
|
||||
MUL_KARATSUBA_CUTOFF := _DEFAULT_MUL_KARATSUBA_CUTOFF;
|
||||
SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF;
|
||||
MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF;
|
||||
SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF;
|
||||
MUL_KARATSUBA_CUTOFF := _DEFAULT_MUL_KARATSUBA_CUTOFF
|
||||
SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF
|
||||
MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF
|
||||
SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -57,24 +57,24 @@ when #config(MATH_BIG_EXE, true) {
|
||||
debugged where necessary.
|
||||
*/
|
||||
|
||||
_DEFAULT_MUL_KARATSUBA_CUTOFF :: #config(MUL_KARATSUBA_CUTOFF, 80);
|
||||
_DEFAULT_SQR_KARATSUBA_CUTOFF :: #config(SQR_KARATSUBA_CUTOFF, 120);
|
||||
_DEFAULT_MUL_TOOM_CUTOFF :: #config(MUL_TOOM_CUTOFF, 350);
|
||||
_DEFAULT_SQR_TOOM_CUTOFF :: #config(SQR_TOOM_CUTOFF, 400);
|
||||
_DEFAULT_MUL_KARATSUBA_CUTOFF :: #config(MUL_KARATSUBA_CUTOFF, 80)
|
||||
_DEFAULT_SQR_KARATSUBA_CUTOFF :: #config(SQR_KARATSUBA_CUTOFF, 120)
|
||||
_DEFAULT_MUL_TOOM_CUTOFF :: #config(MUL_TOOM_CUTOFF, 350)
|
||||
_DEFAULT_SQR_TOOM_CUTOFF :: #config(SQR_TOOM_CUTOFF, 400)
|
||||
|
||||
|
||||
MAX_ITERATIONS_ROOT_N := 500;
|
||||
MAX_ITERATIONS_ROOT_N := 500
|
||||
|
||||
/*
|
||||
Largest `N` for which we'll compute `N!`
|
||||
*/
|
||||
FACTORIAL_MAX_N := 1_000_000;
|
||||
FACTORIAL_MAX_N := 1_000_000
|
||||
|
||||
/*
|
||||
Cutoff to switch to int_factorial_binary_split, and its max recursion level.
|
||||
*/
|
||||
FACTORIAL_BINARY_SPLIT_CUTOFF := 6100;
|
||||
FACTORIAL_BINARY_SPLIT_MAX_RECURSIONS := 100;
|
||||
FACTORIAL_BINARY_SPLIT_CUTOFF := 6100
|
||||
FACTORIAL_BINARY_SPLIT_MAX_RECURSIONS := 100
|
||||
|
||||
|
||||
/*
|
||||
@@ -85,15 +85,15 @@ FACTORIAL_BINARY_SPLIT_MAX_RECURSIONS := 100;
|
||||
|
||||
2) Optimizations thanks to precomputed masks wouldn't work.
|
||||
*/
|
||||
MATH_BIG_FORCE_64_BIT :: #config(MATH_BIG_FORCE_64_BIT, false);
|
||||
MATH_BIG_FORCE_32_BIT :: #config(MATH_BIG_FORCE_32_BIT, false);
|
||||
MATH_BIG_FORCE_64_BIT :: #config(MATH_BIG_FORCE_64_BIT, false)
|
||||
MATH_BIG_FORCE_32_BIT :: #config(MATH_BIG_FORCE_32_BIT, false)
|
||||
when (MATH_BIG_FORCE_32_BIT && MATH_BIG_FORCE_64_BIT) { #panic("Cannot force 32-bit and 64-bit big backend simultaneously."); };
|
||||
|
||||
_LOW_MEMORY :: #config(BIGINT_SMALL_MEMORY, false);
|
||||
_LOW_MEMORY :: #config(BIGINT_SMALL_MEMORY, false)
|
||||
when _LOW_MEMORY {
|
||||
_DEFAULT_DIGIT_COUNT :: 8;
|
||||
_DEFAULT_DIGIT_COUNT :: 8
|
||||
} else {
|
||||
_DEFAULT_DIGIT_COUNT :: 32;
|
||||
_DEFAULT_DIGIT_COUNT :: 32
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -103,22 +103,22 @@ when _LOW_MEMORY {
|
||||
Sign :: enum u8 {
|
||||
Zero_or_Positive = 0,
|
||||
Negative = 1,
|
||||
};
|
||||
}
|
||||
|
||||
Int :: struct {
|
||||
used: int,
|
||||
digit: [dynamic]DIGIT,
|
||||
sign: Sign,
|
||||
flags: Flags,
|
||||
};
|
||||
}
|
||||
|
||||
Flag :: enum u8 {
|
||||
NaN,
|
||||
Inf,
|
||||
Immutable,
|
||||
};
|
||||
}
|
||||
|
||||
Flags :: bit_set[Flag; u8];
|
||||
Flags :: bit_set[Flag; u8]
|
||||
|
||||
/*
|
||||
Errors are a strict superset of runtime.Allocation_Error.
|
||||
@@ -138,7 +138,7 @@ Error :: enum int {
|
||||
Math_Domain_Error = 9,
|
||||
|
||||
Unimplemented = 127,
|
||||
};
|
||||
}
|
||||
|
||||
Error_String :: #partial [Error]string{
|
||||
.Out_Of_Memory = "Out of memory",
|
||||
@@ -154,14 +154,14 @@ Error_String :: #partial [Error]string{
|
||||
.Math_Domain_Error = "Math domain error",
|
||||
|
||||
.Unimplemented = "Unimplemented",
|
||||
};
|
||||
}
|
||||
|
||||
Primality_Flag :: enum u8 {
|
||||
Blum_Blum_Shub = 0, /* BBS style prime */
|
||||
Safe = 1, /* Safe prime (p-1)/2 == prime */
|
||||
Second_MSB_On = 3, /* force 2nd MSB to 1 */
|
||||
};
|
||||
Primality_Flags :: bit_set[Primality_Flag; u8];
|
||||
}
|
||||
Primality_Flags :: bit_set[Primality_Flag; u8]
|
||||
|
||||
/*
|
||||
How do we store the Ints?
|
||||
@@ -171,7 +171,7 @@ Primality_Flags :: bit_set[Primality_Flag; u8];
|
||||
- Must be large enough such that `init_integer` can store `u128` in the `Int` without growing.
|
||||
*/
|
||||
|
||||
_MIN_DIGIT_COUNT :: max(3, ((size_of(u128) + _DIGIT_BITS) - 1) / _DIGIT_BITS);
|
||||
_MIN_DIGIT_COUNT :: max(3, ((size_of(u128) + _DIGIT_BITS) - 1) / _DIGIT_BITS)
|
||||
#assert(_DEFAULT_DIGIT_COUNT >= _MIN_DIGIT_COUNT);
|
||||
|
||||
/*
|
||||
@@ -180,36 +180,36 @@ _MIN_DIGIT_COUNT :: max(3, ((size_of(u128) + _DIGIT_BITS) - 1) / _DIGIT_BITS);
|
||||
- Must be small enough such that `_radix_size` for base 2 does not overflow.
|
||||
`_radix_size` needs two additional bytes for zero termination and sign.
|
||||
*/
|
||||
_MAX_BIT_COUNT :: (max(int) - 2);
|
||||
_MAX_DIGIT_COUNT :: _MAX_BIT_COUNT / _DIGIT_BITS;
|
||||
_MAX_BIT_COUNT :: (max(int) - 2)
|
||||
_MAX_DIGIT_COUNT :: _MAX_BIT_COUNT / _DIGIT_BITS
|
||||
|
||||
when MATH_BIG_FORCE_64_BIT || (!MATH_BIG_FORCE_32_BIT && size_of(rawptr) == 8) {
|
||||
/*
|
||||
We can use u128 as an intermediary.
|
||||
*/
|
||||
DIGIT :: distinct u64;
|
||||
_WORD :: distinct u128;
|
||||
DIGIT :: distinct u64
|
||||
_WORD :: distinct u128
|
||||
} else {
|
||||
DIGIT :: distinct u32;
|
||||
_WORD :: distinct u64;
|
||||
DIGIT :: distinct u32
|
||||
_WORD :: distinct u64
|
||||
}
|
||||
#assert(size_of(_WORD) == 2 * size_of(DIGIT));
|
||||
|
||||
_DIGIT_TYPE_BITS :: 8 * size_of(DIGIT);
|
||||
_WORD_TYPE_BITS :: 8 * size_of(_WORD);
|
||||
_DIGIT_TYPE_BITS :: 8 * size_of(DIGIT)
|
||||
_WORD_TYPE_BITS :: 8 * size_of(_WORD)
|
||||
|
||||
_DIGIT_BITS :: _DIGIT_TYPE_BITS - 4;
|
||||
_WORD_BITS :: 2 * _DIGIT_BITS;
|
||||
_DIGIT_BITS :: _DIGIT_TYPE_BITS - 4
|
||||
_WORD_BITS :: 2 * _DIGIT_BITS
|
||||
|
||||
_MASK :: (DIGIT(1) << DIGIT(_DIGIT_BITS)) - DIGIT(1);
|
||||
_DIGIT_MAX :: _MASK;
|
||||
_MAX_COMBA :: 1 << (_WORD_TYPE_BITS - (2 * _DIGIT_BITS)) ;
|
||||
_WARRAY :: 1 << ((_WORD_TYPE_BITS - (2 * _DIGIT_BITS)) + 1);
|
||||
_MASK :: (DIGIT(1) << DIGIT(_DIGIT_BITS)) - DIGIT(1)
|
||||
_DIGIT_MAX :: _MASK
|
||||
_MAX_COMBA :: 1 << (_WORD_TYPE_BITS - (2 * _DIGIT_BITS))
|
||||
_WARRAY :: 1 << ((_WORD_TYPE_BITS - (2 * _DIGIT_BITS)) + 1)
|
||||
|
||||
Order :: enum i8 {
|
||||
LSB_First = -1,
|
||||
MSB_First = 1,
|
||||
};
|
||||
}
|
||||
|
||||
Endianness :: enum i8 {
|
||||
Little = -1,
|
||||
|
||||
+90
-90
@@ -47,186 +47,186 @@ MAX_ITERATIONS_ROOT_N,
|
||||
FACTORIAL_MAX_N,
|
||||
FACTORIAL_BINARY_SPLIT_CUTOFF,
|
||||
FACTORIAL_BINARY_SPLIT_MAX_RECURSIONS,
|
||||
);
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
print :: proc(name: string, a: ^Int, base := i8(10), print_name := true, newline := true, print_extra_info := false) {
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
|
||||
as, err := itoa(a, base);
|
||||
defer delete(as);
|
||||
as, err := itoa(a, base)
|
||||
defer delete(as)
|
||||
|
||||
cb := internal_count_bits(a);
|
||||
cb := internal_count_bits(a)
|
||||
if print_name {
|
||||
fmt.printf("%v", name);
|
||||
fmt.printf("%v", name)
|
||||
}
|
||||
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);
|
||||
fmt.printf("%v", as)
|
||||
if print_extra_info {
|
||||
fmt.printf(" (base: %v, bits: %v (digits: %v), flags: %v)", base, cb, a.used, a.flags);
|
||||
fmt.printf(" (base: %v, bits: %v (digits: %v), flags: %v)", base, cb, a.used, a.flags)
|
||||
}
|
||||
if newline {
|
||||
fmt.println();
|
||||
fmt.println()
|
||||
}
|
||||
}
|
||||
|
||||
int_to_byte :: proc(v: ^Int) {
|
||||
err: Error;
|
||||
size: int;
|
||||
print("v: ", v);
|
||||
fmt.println();
|
||||
err: Error
|
||||
size: int
|
||||
print("v: ", v)
|
||||
fmt.println()
|
||||
|
||||
t := &Int{};
|
||||
defer destroy(t);
|
||||
t := &Int{}
|
||||
defer destroy(t)
|
||||
|
||||
if size, err = int_to_bytes_size(v); err != nil {
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err);
|
||||
return;
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err)
|
||||
return
|
||||
}
|
||||
b1 := make([]u8, size, context.temp_allocator);
|
||||
err = int_to_bytes_big(v, b1);
|
||||
int_from_bytes_big(t, b1);
|
||||
fmt.printf("big: %v | err: %v\n", b1, err);
|
||||
b1 := make([]u8, size, context.temp_allocator)
|
||||
err = int_to_bytes_big(v, b1)
|
||||
int_from_bytes_big(t, b1)
|
||||
fmt.printf("big: %v | err: %v\n", b1, err)
|
||||
|
||||
int_from_bytes_big(t, b1);
|
||||
int_from_bytes_big(t, b1)
|
||||
if internal_cmp_mag(t, v) != 0 {
|
||||
print("\tError parsing t: ", t);
|
||||
print("\tError parsing t: ", t)
|
||||
}
|
||||
|
||||
if size, err = int_to_bytes_size(v); err != nil {
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err);
|
||||
return;
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err)
|
||||
return
|
||||
}
|
||||
b2 := make([]u8, size, context.temp_allocator);
|
||||
err = int_to_bytes_big_python(v, b2);
|
||||
fmt.printf("big python: %v | err: %v\n", b2, err);
|
||||
b2 := make([]u8, size, context.temp_allocator)
|
||||
err = int_to_bytes_big_python(v, b2)
|
||||
fmt.printf("big python: %v | err: %v\n", b2, err)
|
||||
|
||||
if err == nil {
|
||||
int_from_bytes_big_python(t, b2);
|
||||
int_from_bytes_big_python(t, b2)
|
||||
if internal_cmp_mag(t, v) != 0 {
|
||||
print("\tError parsing t: ", t);
|
||||
print("\tError parsing t: ", t)
|
||||
}
|
||||
}
|
||||
|
||||
if size, err = int_to_bytes_size(v, true); err != nil {
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err);
|
||||
return;
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err)
|
||||
return
|
||||
}
|
||||
b3 := make([]u8, size, context.temp_allocator);
|
||||
err = int_to_bytes_big(v, b3, true);
|
||||
fmt.printf("big signed: %v | err: %v\n", b3, err);
|
||||
b3 := make([]u8, size, context.temp_allocator)
|
||||
err = int_to_bytes_big(v, b3, true)
|
||||
fmt.printf("big signed: %v | err: %v\n", b3, err)
|
||||
|
||||
int_from_bytes_big(t, b3, true);
|
||||
int_from_bytes_big(t, b3, true)
|
||||
if internal_cmp(t, v) != 0 {
|
||||
print("\tError parsing t: ", t);
|
||||
print("\tError parsing t: ", t)
|
||||
}
|
||||
|
||||
if size, err = int_to_bytes_size(v, true); err != nil {
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err);
|
||||
return;
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err)
|
||||
return
|
||||
}
|
||||
b4 := make([]u8, size, context.temp_allocator);
|
||||
err = int_to_bytes_big_python(v, b4, true);
|
||||
fmt.printf("big signed python: %v | err: %v\n", b4, err);
|
||||
b4 := make([]u8, size, context.temp_allocator)
|
||||
err = int_to_bytes_big_python(v, b4, true)
|
||||
fmt.printf("big signed python: %v | err: %v\n", b4, err)
|
||||
|
||||
int_from_bytes_big_python(t, b4, true);
|
||||
int_from_bytes_big_python(t, b4, true)
|
||||
if internal_cmp(t, v) != 0 {
|
||||
print("\tError parsing t: ", t);
|
||||
print("\tError parsing t: ", t)
|
||||
}
|
||||
}
|
||||
|
||||
int_to_byte_little :: proc(v: ^Int) {
|
||||
err: Error;
|
||||
size: int;
|
||||
print("v: ", v);
|
||||
fmt.println();
|
||||
err: Error
|
||||
size: int
|
||||
print("v: ", v)
|
||||
fmt.println()
|
||||
|
||||
t := &Int{};
|
||||
defer destroy(t);
|
||||
t := &Int{}
|
||||
defer destroy(t)
|
||||
|
||||
if size, err = int_to_bytes_size(v); err != nil {
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err);
|
||||
return;
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err)
|
||||
return
|
||||
}
|
||||
b1 := make([]u8, size, context.temp_allocator);
|
||||
err = int_to_bytes_little(v, b1);
|
||||
fmt.printf("little: %v | err: %v\n", b1, err);
|
||||
b1 := make([]u8, size, context.temp_allocator)
|
||||
err = int_to_bytes_little(v, b1)
|
||||
fmt.printf("little: %v | err: %v\n", b1, err)
|
||||
|
||||
int_from_bytes_little(t, b1);
|
||||
int_from_bytes_little(t, b1)
|
||||
if internal_cmp_mag(t, v) != 0 {
|
||||
print("\tError parsing t: ", t);
|
||||
print("\tError parsing t: ", t)
|
||||
}
|
||||
|
||||
if size, err = int_to_bytes_size(v); err != nil {
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err);
|
||||
return;
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err)
|
||||
return
|
||||
}
|
||||
b2 := make([]u8, size, context.temp_allocator);
|
||||
err = int_to_bytes_little_python(v, b2);
|
||||
fmt.printf("little python: %v | err: %v\n", b2, err);
|
||||
b2 := make([]u8, size, context.temp_allocator)
|
||||
err = int_to_bytes_little_python(v, b2)
|
||||
fmt.printf("little python: %v | err: %v\n", b2, err)
|
||||
|
||||
if err == nil {
|
||||
int_from_bytes_little_python(t, b2);
|
||||
int_from_bytes_little_python(t, b2)
|
||||
if internal_cmp_mag(t, v) != 0 {
|
||||
print("\tError parsing t: ", t);
|
||||
print("\tError parsing t: ", t)
|
||||
}
|
||||
}
|
||||
|
||||
if size, err = int_to_bytes_size(v, true); err != nil {
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err);
|
||||
return;
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err)
|
||||
return
|
||||
}
|
||||
b3 := make([]u8, size, context.temp_allocator);
|
||||
err = int_to_bytes_little(v, b3, true);
|
||||
fmt.printf("little signed: %v | err: %v\n", b3, err);
|
||||
b3 := make([]u8, size, context.temp_allocator)
|
||||
err = int_to_bytes_little(v, b3, true)
|
||||
fmt.printf("little signed: %v | err: %v\n", b3, err)
|
||||
|
||||
int_from_bytes_little(t, b3, true);
|
||||
int_from_bytes_little(t, b3, true)
|
||||
if internal_cmp(t, v) != 0 {
|
||||
print("\tError parsing t: ", t);
|
||||
print("\tError parsing t: ", t)
|
||||
}
|
||||
|
||||
if size, err = int_to_bytes_size(v, true); err != nil {
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err);
|
||||
return;
|
||||
fmt.printf("int_to_bytes_size returned: %v\n", err)
|
||||
return
|
||||
}
|
||||
b4 := make([]u8, size, context.temp_allocator);
|
||||
err = int_to_bytes_little_python(v, b4, true);
|
||||
fmt.printf("little signed python: %v | err: %v\n", b4, err);
|
||||
b4 := make([]u8, size, context.temp_allocator)
|
||||
err = int_to_bytes_little_python(v, b4, true)
|
||||
fmt.printf("little signed python: %v | err: %v\n", b4, err)
|
||||
|
||||
int_from_bytes_little_python(t, b4, true);
|
||||
int_from_bytes_little_python(t, b4, true)
|
||||
if internal_cmp(t, v) != 0 {
|
||||
print("\tError parsing t: ", t);
|
||||
print("\tError parsing t: ", t)
|
||||
}
|
||||
}
|
||||
|
||||
demo :: proc() {
|
||||
a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
||||
defer destroy(a, b, c, d, e, f);
|
||||
a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}
|
||||
defer destroy(a, b, c, d, e, f)
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
ta := mem.Tracking_Allocator{};
|
||||
mem.tracking_allocator_init(&ta, context.allocator);
|
||||
context.allocator = mem.tracking_allocator(&ta);
|
||||
ta := mem.Tracking_Allocator{}
|
||||
mem.tracking_allocator_init(&ta, context.allocator)
|
||||
context.allocator = mem.tracking_allocator(&ta)
|
||||
|
||||
demo();
|
||||
demo()
|
||||
|
||||
print_configation();
|
||||
print_configation()
|
||||
|
||||
print_timings();
|
||||
print_timings()
|
||||
|
||||
if len(ta.allocation_map) > 0 {
|
||||
for _, v in ta.allocation_map {
|
||||
fmt.printf("Leaked %v bytes @ %v\n", v.size, v.location);
|
||||
fmt.printf("Leaked %v bytes @ %v\n", v.size, v.location)
|
||||
}
|
||||
}
|
||||
if len(ta.bad_free_array) > 0 {
|
||||
fmt.println("Bad frees:");
|
||||
fmt.println("Bad frees:")
|
||||
for v in ta.bad_free_array {
|
||||
fmt.println(v);
|
||||
fmt.println(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
+251
-251
@@ -22,10 +22,10 @@ import rnd "core:math/rand"
|
||||
Deallocates the backing memory of one or more `Int`s.
|
||||
*/
|
||||
int_destroy :: proc(integers: ..^Int) {
|
||||
integers := integers;
|
||||
integers := integers
|
||||
|
||||
for a in &integers {
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
}
|
||||
#force_inline internal_int_destroy(..integers);
|
||||
}
|
||||
@@ -35,19 +35,19 @@ int_destroy :: proc(integers: ..^Int) {
|
||||
*/
|
||||
int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator := context.allocator) -> (err: Error)
|
||||
where intrinsics.type_is_integer(T) {
|
||||
context.allocator = allocator;
|
||||
src := src;
|
||||
context.allocator = allocator
|
||||
src := src
|
||||
|
||||
/*
|
||||
Check that `src` is usable and `dest` isn't immutable.
|
||||
*/
|
||||
assert_if_nil(dest);
|
||||
assert_if_nil(dest)
|
||||
#force_inline internal_error_if_immutable(dest) or_return;
|
||||
|
||||
return #force_inline internal_int_set_from_integer(dest, src, minimize);
|
||||
return #force_inline internal_int_set_from_integer(dest, src, minimize)
|
||||
}
|
||||
|
||||
set :: proc { int_set_from_integer, int_copy, int_atoi, };
|
||||
set :: proc { int_set_from_integer, int_copy, int_atoi, }
|
||||
|
||||
/*
|
||||
Copy one `Int` to another.
|
||||
@@ -61,15 +61,15 @@ int_copy :: proc(dest, src: ^Int, minimize := false, allocator := context.alloca
|
||||
/*
|
||||
Check that `src` is usable and `dest` isn't immutable.
|
||||
*/
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
#force_inline internal_clear_if_uninitialized(src) or_return;
|
||||
#force_inline internal_error_if_immutable(dest) or_return;
|
||||
|
||||
return #force_inline internal_int_copy(dest, src, minimize);
|
||||
return #force_inline internal_int_copy(dest, src, minimize)
|
||||
}
|
||||
copy :: proc { int_copy, };
|
||||
copy :: proc { int_copy, }
|
||||
|
||||
/*
|
||||
In normal code, you can also write `a, b = b, a`.
|
||||
@@ -77,10 +77,10 @@ copy :: proc { int_copy, };
|
||||
This helper swaps completely.
|
||||
*/
|
||||
int_swap :: proc(a, b: ^Int) {
|
||||
assert_if_nil(a, b);
|
||||
assert_if_nil(a, b)
|
||||
#force_inline internal_swap(a, b);
|
||||
}
|
||||
swap :: proc { int_swap, };
|
||||
swap :: proc { int_swap, }
|
||||
|
||||
/*
|
||||
Set `dest` to |`src`|.
|
||||
@@ -89,19 +89,19 @@ int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
|
||||
/*
|
||||
Check that `src` is usable and `dest` isn't immutable.
|
||||
*/
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
#force_inline internal_clear_if_uninitialized(src) or_return;
|
||||
#force_inline internal_error_if_immutable(dest) or_return;
|
||||
|
||||
return #force_inline internal_int_abs(dest, src);
|
||||
return #force_inline internal_int_abs(dest, src)
|
||||
}
|
||||
|
||||
platform_abs :: proc(n: $T) -> T where intrinsics.type_is_integer(T) {
|
||||
return n if n >= 0 else -n;
|
||||
return n if n >= 0 else -n
|
||||
}
|
||||
abs :: proc{ int_abs, platform_abs, };
|
||||
abs :: proc{ int_abs, platform_abs, }
|
||||
|
||||
/*
|
||||
Set `dest` to `-src`.
|
||||
@@ -110,32 +110,32 @@ int_neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
|
||||
/*
|
||||
Check that `src` is usable and `dest` isn't immutable.
|
||||
*/
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
#force_inline internal_clear_if_uninitialized(src) or_return;
|
||||
#force_inline internal_error_if_immutable(dest) or_return;
|
||||
|
||||
return #force_inline internal_int_neg(dest, src);
|
||||
return #force_inline internal_int_neg(dest, src)
|
||||
}
|
||||
neg :: proc { int_neg, };
|
||||
neg :: proc { int_neg, }
|
||||
|
||||
/*
|
||||
Helpers to extract values from the `Int`.
|
||||
*/
|
||||
int_bitfield_extract_single :: proc(a: ^Int, offset: int, allocator := context.allocator) -> (bit: _WORD, err: Error) {
|
||||
return #force_inline int_bitfield_extract(a, offset, 1, allocator);
|
||||
return #force_inline int_bitfield_extract(a, offset, 1, allocator)
|
||||
}
|
||||
|
||||
int_bitfield_extract :: proc(a: ^Int, offset, count: int, allocator := context.allocator) -> (res: _WORD, err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
#force_inline internal_clear_if_uninitialized(a) or_return;
|
||||
return #force_inline internal_int_bitfield_extract(a, offset, count);
|
||||
return #force_inline internal_int_bitfield_extract(a, offset, count)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -145,21 +145,21 @@ shrink :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
#force_inline internal_clear_if_uninitialized(a) or_return;
|
||||
return #force_inline internal_shrink(a);
|
||||
return #force_inline internal_shrink(a)
|
||||
}
|
||||
|
||||
int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := context.allocator) -> (err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return #force_inline internal_int_grow(a, digits, allow_shrink, allocator);
|
||||
assert_if_nil(a)
|
||||
return #force_inline internal_int_grow(a, digits, allow_shrink, allocator)
|
||||
}
|
||||
grow :: proc { int_grow, };
|
||||
grow :: proc { int_grow, }
|
||||
|
||||
/*
|
||||
Clear `Int` and resize it to the default size.
|
||||
@@ -168,11 +168,11 @@ int_clear :: proc(a: ^Int, minimize := false, allocator := context.allocator) ->
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return #force_inline internal_int_clear(a, minimize, allocator);
|
||||
assert_if_nil(a)
|
||||
return #force_inline internal_int_clear(a, minimize, allocator)
|
||||
}
|
||||
clear :: proc { int_clear, };
|
||||
zero :: clear;
|
||||
clear :: proc { int_clear, }
|
||||
zero :: clear
|
||||
|
||||
/*
|
||||
Set the `Int` to 1 and optionally shrink it to the minimum backing size.
|
||||
@@ -181,10 +181,10 @@ int_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return #force_inline internal_one(a, minimize, allocator);
|
||||
assert_if_nil(a)
|
||||
return #force_inline internal_one(a, minimize, allocator)
|
||||
}
|
||||
one :: proc { int_one, };
|
||||
one :: proc { int_one, }
|
||||
|
||||
/*
|
||||
Set the `Int` to -1 and optionally shrink it to the minimum backing size.
|
||||
@@ -193,10 +193,10 @@ int_minus_one :: proc(a: ^Int, minimize := false, allocator := context.allocator
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return #force_inline internal_minus_one(a, minimize, allocator);
|
||||
assert_if_nil(a)
|
||||
return #force_inline internal_minus_one(a, minimize, allocator)
|
||||
}
|
||||
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.
|
||||
@@ -205,10 +205,10 @@ int_inf :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return #force_inline internal_inf(a, minimize, allocator);
|
||||
assert_if_nil(a)
|
||||
return #force_inline internal_inf(a, minimize, allocator)
|
||||
}
|
||||
inf :: proc { int_inf, };
|
||||
inf :: proc { int_inf, }
|
||||
|
||||
/*
|
||||
Set the `Int` to -Inf and optionally shrink it to the minimum backing size.
|
||||
@@ -217,10 +217,10 @@ int_minus_inf :: proc(a: ^Int, minimize := false, allocator := context.allocator
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return #force_inline internal_minus_inf(a, minimize, allocator);
|
||||
assert_if_nil(a)
|
||||
return #force_inline internal_minus_inf(a, minimize, allocator)
|
||||
}
|
||||
minus_inf :: proc { int_inf, };
|
||||
minus_inf :: proc { int_inf, }
|
||||
|
||||
/*
|
||||
Set the `Int` to NaN and optionally shrink it to the minimum backing size.
|
||||
@@ -229,72 +229,72 @@ int_nan :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return #force_inline internal_nan(a, minimize, allocator);
|
||||
assert_if_nil(a)
|
||||
return #force_inline internal_nan(a, minimize, allocator)
|
||||
}
|
||||
nan :: proc { int_nan, };
|
||||
nan :: proc { int_nan, }
|
||||
|
||||
power_of_two :: proc(a: ^Int, power: int, allocator := context.allocator) -> (err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return #force_inline internal_int_power_of_two(a, power, allocator);
|
||||
assert_if_nil(a)
|
||||
return #force_inline internal_int_power_of_two(a, power, allocator)
|
||||
}
|
||||
|
||||
int_get_u128 :: proc(a: ^Int, allocator := context.allocator) -> (res: u128, err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return int_get(a, u128, allocator);
|
||||
assert_if_nil(a)
|
||||
return int_get(a, u128, allocator)
|
||||
}
|
||||
get_u128 :: proc { int_get_u128, };
|
||||
get_u128 :: proc { int_get_u128, }
|
||||
|
||||
int_get_i128 :: proc(a: ^Int, allocator := context.allocator) -> (res: i128, err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return int_get(a, i128, allocator);
|
||||
assert_if_nil(a)
|
||||
return int_get(a, i128, allocator)
|
||||
}
|
||||
get_i128 :: proc { int_get_i128, };
|
||||
get_i128 :: proc { int_get_i128, }
|
||||
|
||||
int_get_u64 :: proc(a: ^Int, allocator := context.allocator) -> (res: u64, err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return int_get(a, u64, allocator);
|
||||
assert_if_nil(a)
|
||||
return int_get(a, u64, allocator)
|
||||
}
|
||||
get_u64 :: proc { int_get_u64, };
|
||||
get_u64 :: proc { int_get_u64, }
|
||||
|
||||
int_get_i64 :: proc(a: ^Int, allocator := context.allocator) -> (res: i64, err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return int_get(a, i64, allocator);
|
||||
assert_if_nil(a)
|
||||
return int_get(a, i64, allocator)
|
||||
}
|
||||
get_i64 :: proc { int_get_i64, };
|
||||
get_i64 :: proc { int_get_i64, }
|
||||
|
||||
int_get_u32 :: proc(a: ^Int, allocator := context.allocator) -> (res: u32, err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return int_get(a, u32, allocator);
|
||||
assert_if_nil(a)
|
||||
return int_get(a, u32, allocator)
|
||||
}
|
||||
get_u32 :: proc { int_get_u32, };
|
||||
get_u32 :: proc { int_get_u32, }
|
||||
|
||||
int_get_i32 :: proc(a: ^Int, allocator := context.allocator) -> (res: i32, err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
return int_get(a, i32, allocator);
|
||||
assert_if_nil(a)
|
||||
return int_get(a, i32, allocator)
|
||||
}
|
||||
get_i32 :: proc { int_get_i32, };
|
||||
get_i32 :: proc { int_get_i32, }
|
||||
|
||||
/*
|
||||
TODO: Think about using `count_bits` to check if the value could be returned completely,
|
||||
@@ -304,19 +304,19 @@ int_get :: proc(a: ^Int, $T: typeid, allocator := context.allocator) -> (res: T,
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||
return #force_inline internal_int_get(a, T);
|
||||
return #force_inline internal_int_get(a, T)
|
||||
}
|
||||
get :: proc { int_get, };
|
||||
get :: proc { int_get, }
|
||||
|
||||
int_get_float :: proc(a: ^Int, allocator := context.allocator) -> (res: f64, err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||
return #force_inline internal_int_get_float(a);
|
||||
return #force_inline internal_int_get_float(a)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -326,9 +326,9 @@ count_bits :: proc(a: ^Int, allocator := context.allocator) -> (count: int, err:
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||
return #force_inline internal_count_bits(a), nil;
|
||||
return #force_inline internal_count_bits(a), nil
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -339,109 +339,109 @@ int_count_lsb :: proc(a: ^Int, allocator := context.allocator) -> (count: int, e
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||
return #force_inline internal_int_count_lsb(a);
|
||||
return #force_inline internal_int_count_lsb(a)
|
||||
}
|
||||
|
||||
platform_count_lsb :: #force_inline proc(a: $T) -> (count: int)
|
||||
where intrinsics.type_is_integer(T) && intrinsics.type_is_unsigned(T) {
|
||||
return int(intrinsics.count_trailing_zeros(a)) if a > 0 else 0;
|
||||
return int(intrinsics.count_trailing_zeros(a)) if a > 0 else 0
|
||||
}
|
||||
|
||||
count_lsb :: proc { int_count_lsb, platform_count_lsb, };
|
||||
count_lsb :: proc { int_count_lsb, platform_count_lsb, }
|
||||
|
||||
int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) {
|
||||
when _DIGIT_BITS == 60 { // DIGIT = u64
|
||||
return DIGIT(rnd.uint64(r)) & _MASK;
|
||||
return DIGIT(rnd.uint64(r)) & _MASK
|
||||
} else when _DIGIT_BITS == 28 { // DIGIT = u32
|
||||
return DIGIT(rnd.uint32(r)) & _MASK;
|
||||
return DIGIT(rnd.uint32(r)) & _MASK
|
||||
} else {
|
||||
panic("Unsupported DIGIT size.");
|
||||
panic("Unsupported DIGIT size.")
|
||||
}
|
||||
|
||||
return 0; // We shouldn't get here.
|
||||
return 0 // We shouldn't get here.
|
||||
}
|
||||
|
||||
int_rand :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator := context.allocator) -> (err: Error) {
|
||||
/*
|
||||
Check that `a` is usable.
|
||||
*/
|
||||
assert_if_nil(dest);
|
||||
return #force_inline internal_int_rand(dest, bits, r, allocator);
|
||||
assert_if_nil(dest)
|
||||
return #force_inline internal_int_rand(dest, bits, r, allocator)
|
||||
|
||||
}
|
||||
rand :: proc { int_rand, };
|
||||
rand :: proc { int_rand, }
|
||||
|
||||
/*
|
||||
Internal helpers.
|
||||
*/
|
||||
assert_initialized :: proc(a: ^Int, loc := #caller_location) {
|
||||
assert_if_nil(a);
|
||||
assert(is_initialized(a), "`Int` was not properly initialized.", loc);
|
||||
assert_if_nil(a)
|
||||
assert(is_initialized(a), "`Int` was not properly initialized.", loc)
|
||||
}
|
||||
|
||||
zero_unused :: proc(dest: ^Int, old_used := -1) {
|
||||
assert_if_nil(dest);
|
||||
assert_if_nil(dest)
|
||||
if ! #force_inline is_initialized(dest) { return; }
|
||||
|
||||
#force_inline internal_zero_unused(dest, old_used);
|
||||
}
|
||||
|
||||
clear_if_uninitialized_single :: proc(arg: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(arg);
|
||||
return #force_inline internal_clear_if_uninitialized_single(arg, allocator);
|
||||
assert_if_nil(arg)
|
||||
return #force_inline internal_clear_if_uninitialized_single(arg, allocator)
|
||||
}
|
||||
|
||||
clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context.allocator) -> (err: Error) {
|
||||
args := args;
|
||||
assert_if_nil(..args);
|
||||
args := args
|
||||
assert_if_nil(..args)
|
||||
|
||||
for i in &args {
|
||||
#force_inline internal_clear_if_uninitialized_single(i, allocator) or_return;
|
||||
}
|
||||
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;
|
||||
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;
|
||||
return nil
|
||||
}
|
||||
error_if_immutable :: proc {error_if_immutable_single, error_if_immutable_multi, };
|
||||
error_if_immutable :: proc {error_if_immutable_single, error_if_immutable_multi, }
|
||||
|
||||
/*
|
||||
Allocates several `Int`s at once.
|
||||
*/
|
||||
int_init_multi :: proc(integers: ..^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(..integers);
|
||||
assert_if_nil(..integers)
|
||||
|
||||
integers := integers;
|
||||
integers := integers
|
||||
for a in &integers {
|
||||
#force_inline internal_clear(a, true, allocator) or_return;
|
||||
}
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
init_multi :: proc { int_init_multi, };
|
||||
init_multi :: proc { int_init_multi, }
|
||||
|
||||
copy_digits :: proc(dest, src: ^Int, digits: int, offset := int(0), allocator := context.allocator) -> (err: Error) {
|
||||
context.allocator = allocator;
|
||||
context.allocator = allocator
|
||||
|
||||
/*
|
||||
Check that `src` is usable and `dest` isn't immutable.
|
||||
*/
|
||||
assert_if_nil(dest, src);
|
||||
assert_if_nil(dest, src)
|
||||
#force_inline internal_clear_if_uninitialized(src) or_return;
|
||||
|
||||
return #force_inline internal_copy_digits(dest, src, digits, offset);
|
||||
return #force_inline internal_copy_digits(dest, src, digits, offset)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -451,17 +451,17 @@ copy_digits :: proc(dest, src: ^Int, digits: int, offset := int(0), allocator :=
|
||||
Typically very fast. Also fixes the sign if there are no more leading digits.
|
||||
*/
|
||||
clamp :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||
|
||||
for a.used > 0 && a.digit[a.used - 1] == 0 {
|
||||
a.used -= 1;
|
||||
a.used -= 1
|
||||
}
|
||||
|
||||
if z, _ := is_zero(a); z {
|
||||
a.sign = .Zero_or_Positive;
|
||||
a.sign = .Zero_or_Positive
|
||||
}
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -469,15 +469,15 @@ clamp :: proc(a: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
Size binary representation
|
||||
*/
|
||||
int_to_bytes_size :: proc(a: ^Int, signed := false, allocator := context.allocator) -> (size_in_bytes: int, err: Error) {
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
#force_inline internal_clear_if_uninitialized(a, allocator) or_return;
|
||||
|
||||
size_in_bits := internal_count_bits(a);
|
||||
size_in_bits := internal_count_bits(a)
|
||||
|
||||
size_in_bytes = (size_in_bits / 8);
|
||||
size_in_bytes += 0 if size_in_bits % 8 == 0 else 1;
|
||||
size_in_bytes += 1 if signed else 0;
|
||||
return;
|
||||
size_in_bytes = (size_in_bits / 8)
|
||||
size_in_bytes += 0 if size_in_bits % 8 == 0 else 1
|
||||
size_in_bytes += 1 if signed else 0
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -485,22 +485,22 @@ int_to_bytes_size :: proc(a: ^Int, signed := false, allocator := context.allocat
|
||||
If `a` is negative and we ask for the default unsigned representation, we return abs(a).
|
||||
*/
|
||||
int_to_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
|
||||
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return;
|
||||
l := len(buf);
|
||||
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return
|
||||
l := len(buf)
|
||||
if size_in_bytes > l { return .Buffer_Overflow; }
|
||||
|
||||
size_in_bits := internal_count_bits(a);
|
||||
i := 0;
|
||||
size_in_bits := internal_count_bits(a)
|
||||
i := 0
|
||||
if signed {
|
||||
buf[l - 1] = 1 if a.sign == .Negative else 0;
|
||||
buf[l - 1] = 1 if a.sign == .Negative else 0
|
||||
}
|
||||
for offset := 0; offset < size_in_bits; offset += 8 {
|
||||
bits, _ := internal_int_bitfield_extract(a, offset, 8);
|
||||
buf[i] = u8(bits & 255); i += 1;
|
||||
bits, _ := internal_int_bitfield_extract(a, offset, 8)
|
||||
buf[i] = u8(bits & 255); i += 1
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -508,23 +508,23 @@ int_to_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := co
|
||||
If `a` is negative and we ask for the default unsigned representation, we return abs(a).
|
||||
*/
|
||||
int_to_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
|
||||
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return;
|
||||
l := len(buf);
|
||||
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return
|
||||
l := len(buf)
|
||||
if size_in_bytes > l { return .Buffer_Overflow; }
|
||||
|
||||
size_in_bits := internal_count_bits(a);
|
||||
i := l - 1;
|
||||
size_in_bits := internal_count_bits(a)
|
||||
i := l - 1
|
||||
|
||||
if signed {
|
||||
buf[0] = 1 if a.sign == .Negative else 0;
|
||||
buf[0] = 1 if a.sign == .Negative else 0
|
||||
}
|
||||
for offset := 0; offset < size_in_bits; offset += 8 {
|
||||
bits, _ := internal_int_bitfield_extract(a, offset, 8);
|
||||
buf[i] = u8(bits & 255); i -= 1;
|
||||
bits, _ := internal_int_bitfield_extract(a, offset, 8)
|
||||
buf[i] = u8(bits & 255); i -= 1
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -532,35 +532,35 @@ int_to_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := conte
|
||||
If `a` is negative when asking for an unsigned number, we return an error like Python does.
|
||||
*/
|
||||
int_to_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
|
||||
if !signed && a.sign == .Negative { return .Invalid_Argument; }
|
||||
|
||||
l := len(buf);
|
||||
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return;
|
||||
l := len(buf)
|
||||
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return
|
||||
if size_in_bytes > l { return .Buffer_Overflow; }
|
||||
|
||||
if a.sign == .Negative {
|
||||
t := &Int{};
|
||||
defer destroy(t);
|
||||
internal_complement(t, a, allocator) or_return;
|
||||
t := &Int{}
|
||||
defer destroy(t)
|
||||
internal_complement(t, a, allocator) or_return
|
||||
|
||||
size_in_bits := internal_count_bits(t);
|
||||
i := 0;
|
||||
size_in_bits := internal_count_bits(t)
|
||||
i := 0
|
||||
for offset := 0; offset < size_in_bits; offset += 8 {
|
||||
bits, _ := internal_int_bitfield_extract(t, offset, 8);
|
||||
buf[i] = 255 - u8(bits & 255); i += 1;
|
||||
bits, _ := internal_int_bitfield_extract(t, offset, 8)
|
||||
buf[i] = 255 - u8(bits & 255); i += 1
|
||||
}
|
||||
buf[l-1] = 255;
|
||||
buf[l-1] = 255
|
||||
} else {
|
||||
size_in_bits := internal_count_bits(a);
|
||||
i := 0;
|
||||
size_in_bits := internal_count_bits(a)
|
||||
i := 0
|
||||
for offset := 0; offset < size_in_bits; offset += 8 {
|
||||
bits, _ := internal_int_bitfield_extract(a, offset, 8);
|
||||
buf[i] = u8(bits & 255); i += 1;
|
||||
bits, _ := internal_int_bitfield_extract(a, offset, 8)
|
||||
buf[i] = u8(bits & 255); i += 1
|
||||
}
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -568,29 +568,29 @@ int_to_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, allocato
|
||||
If `a` is negative when asking for an unsigned number, we return an error like Python does.
|
||||
*/
|
||||
int_to_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(a);
|
||||
assert_if_nil(a)
|
||||
|
||||
if !signed && a.sign == .Negative { return .Invalid_Argument; }
|
||||
if a.sign == .Zero_or_Positive { return int_to_bytes_big(a, buf, signed, allocator); }
|
||||
|
||||
l := len(buf);
|
||||
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return;
|
||||
l := len(buf)
|
||||
size_in_bytes := int_to_bytes_size(a, signed, allocator) or_return
|
||||
if size_in_bytes > l { return .Buffer_Overflow; }
|
||||
|
||||
t := &Int{};
|
||||
defer destroy(t);
|
||||
t := &Int{}
|
||||
defer destroy(t)
|
||||
|
||||
internal_complement(t, a, allocator) or_return;
|
||||
internal_complement(t, a, allocator) or_return
|
||||
|
||||
size_in_bits := internal_count_bits(t);
|
||||
i := l - 1;
|
||||
size_in_bits := internal_count_bits(t)
|
||||
i := l - 1
|
||||
for offset := 0; offset < size_in_bits; offset += 8 {
|
||||
bits, _ := internal_int_bitfield_extract(t, offset, 8);
|
||||
buf[i] = 255 - u8(bits & 255); i -= 1;
|
||||
bits, _ := internal_int_bitfield_extract(t, offset, 8)
|
||||
buf[i] = 255 - u8(bits & 255); i -= 1
|
||||
}
|
||||
buf[0] = 255;
|
||||
buf[0] = 255
|
||||
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -598,36 +598,36 @@ int_to_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator :
|
||||
Sign is detected from the first byte if `signed` is true.
|
||||
*/
|
||||
int_from_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(a);
|
||||
buf := buf;
|
||||
l := len(buf);
|
||||
assert_if_nil(a)
|
||||
buf := buf
|
||||
l := len(buf)
|
||||
if l == 0 { return .Invalid_Argument; }
|
||||
|
||||
sign: Sign;
|
||||
size_in_bits := l * 8;
|
||||
sign: Sign
|
||||
size_in_bits := l * 8
|
||||
if signed {
|
||||
/*
|
||||
First byte denotes the sign.
|
||||
*/
|
||||
size_in_bits -= 8;
|
||||
size_in_bits -= 8
|
||||
}
|
||||
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
|
||||
size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
|
||||
internal_zero(a, false, allocator) or_return;
|
||||
internal_grow(a, size_in_digits, false, allocator) or_return;
|
||||
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS
|
||||
size_in_digits += 0 if size_in_bits % 8 == 0 else 1
|
||||
internal_zero(a, false, allocator) or_return
|
||||
internal_grow(a, size_in_digits, false, allocator) or_return
|
||||
|
||||
if signed {
|
||||
sign = .Zero_or_Positive if buf[0] == 0 else .Negative;
|
||||
buf = buf[1:];
|
||||
sign = .Zero_or_Positive if buf[0] == 0 else .Negative
|
||||
buf = buf[1:]
|
||||
}
|
||||
|
||||
for v in buf {
|
||||
internal_shl(a, a, 8) or_return;
|
||||
a.digit[0] |= DIGIT(v);
|
||||
internal_shl(a, a, 8) or_return
|
||||
a.digit[0] |= DIGIT(v)
|
||||
}
|
||||
a.sign = sign;
|
||||
a.used = size_in_digits;
|
||||
return internal_clamp(a);
|
||||
a.sign = sign
|
||||
a.used = size_in_digits
|
||||
return internal_clamp(a)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -635,45 +635,45 @@ int_from_bytes_big :: proc(a: ^Int, buf: []u8, signed := false, allocator := con
|
||||
Sign is detected from the first byte if `signed` is true.
|
||||
*/
|
||||
int_from_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(a);
|
||||
buf := buf;
|
||||
l := len(buf);
|
||||
assert_if_nil(a)
|
||||
buf := buf
|
||||
l := len(buf)
|
||||
if l == 0 { return .Invalid_Argument; }
|
||||
|
||||
sign: Sign;
|
||||
size_in_bits := l * 8;
|
||||
sign: Sign
|
||||
size_in_bits := l * 8
|
||||
if signed {
|
||||
/*
|
||||
First byte denotes the sign.
|
||||
*/
|
||||
size_in_bits -= 8;
|
||||
size_in_bits -= 8
|
||||
}
|
||||
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
|
||||
size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
|
||||
internal_zero(a, false, allocator) or_return;
|
||||
internal_grow(a, size_in_digits, false, allocator) or_return;
|
||||
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS
|
||||
size_in_digits += 0 if size_in_bits % 8 == 0 else 1
|
||||
internal_zero(a, false, allocator) or_return
|
||||
internal_grow(a, size_in_digits, false, allocator) or_return
|
||||
|
||||
if signed {
|
||||
sign = .Zero_or_Positive if buf[0] == 0 else .Negative;
|
||||
buf = buf[1:];
|
||||
sign = .Zero_or_Positive if buf[0] == 0 else .Negative
|
||||
buf = buf[1:]
|
||||
}
|
||||
|
||||
for v in buf {
|
||||
internal_shl(a, a, 8) or_return;
|
||||
internal_shl(a, a, 8) or_return
|
||||
if signed && sign == .Negative {
|
||||
a.digit[0] |= DIGIT(255 - v);
|
||||
a.digit[0] |= DIGIT(255 - v)
|
||||
} else {
|
||||
a.digit[0] |= DIGIT(v);
|
||||
a.digit[0] |= DIGIT(v)
|
||||
}
|
||||
}
|
||||
a.sign = sign;
|
||||
a.used = size_in_digits;
|
||||
internal_clamp(a) or_return;
|
||||
a.sign = sign
|
||||
a.used = size_in_digits
|
||||
internal_clamp(a) or_return
|
||||
|
||||
if signed && sign == .Negative {
|
||||
return internal_sub(a, a, 1);
|
||||
return internal_sub(a, a, 1)
|
||||
}
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -681,37 +681,37 @@ int_from_bytes_big_python :: proc(a: ^Int, buf: []u8, signed := false, allocator
|
||||
Sign is detected from the last byte if `signed` is true.
|
||||
*/
|
||||
int_from_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(a);
|
||||
buf := buf;
|
||||
l := len(buf);
|
||||
assert_if_nil(a)
|
||||
buf := buf
|
||||
l := len(buf)
|
||||
if l == 0 { return .Invalid_Argument; }
|
||||
|
||||
sign: Sign;
|
||||
size_in_bits := l * 8;
|
||||
sign: Sign
|
||||
size_in_bits := l * 8
|
||||
if signed {
|
||||
/*
|
||||
First byte denotes the sign.
|
||||
*/
|
||||
size_in_bits -= 8;
|
||||
size_in_bits -= 8
|
||||
}
|
||||
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
|
||||
size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
|
||||
internal_zero(a, false, allocator) or_return;
|
||||
internal_grow(a, size_in_digits, false, allocator) or_return;
|
||||
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS
|
||||
size_in_digits += 0 if size_in_bits % 8 == 0 else 1
|
||||
internal_zero(a, false, allocator) or_return
|
||||
internal_grow(a, size_in_digits, false, allocator) or_return
|
||||
|
||||
if signed {
|
||||
sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative;
|
||||
buf = buf[:l-1];
|
||||
l -= 1;
|
||||
sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative
|
||||
buf = buf[:l-1]
|
||||
l -= 1
|
||||
}
|
||||
|
||||
for _, i in buf {
|
||||
internal_shl(a, a, 8) or_return;
|
||||
a.digit[0] |= DIGIT(buf[l-i-1]);
|
||||
internal_shl(a, a, 8) or_return
|
||||
a.digit[0] |= DIGIT(buf[l-i-1])
|
||||
}
|
||||
a.sign = sign;
|
||||
a.used = size_in_digits;
|
||||
return internal_clamp(a);
|
||||
a.sign = sign
|
||||
a.used = size_in_digits
|
||||
return internal_clamp(a)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -719,67 +719,67 @@ int_from_bytes_little :: proc(a: ^Int, buf: []u8, signed := false, allocator :=
|
||||
Sign is detected from the first byte if `signed` is true.
|
||||
*/
|
||||
int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(a);
|
||||
buf := buf;
|
||||
l := len(buf);
|
||||
assert_if_nil(a)
|
||||
buf := buf
|
||||
l := len(buf)
|
||||
if l == 0 { return .Invalid_Argument; }
|
||||
|
||||
sign: Sign;
|
||||
size_in_bits := l * 8;
|
||||
sign: Sign
|
||||
size_in_bits := l * 8
|
||||
if signed {
|
||||
/*
|
||||
First byte denotes the sign.
|
||||
*/
|
||||
size_in_bits -= 8;
|
||||
size_in_bits -= 8
|
||||
}
|
||||
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS;
|
||||
size_in_digits += 0 if size_in_bits % 8 == 0 else 1;
|
||||
internal_zero(a, false, allocator) or_return;
|
||||
internal_grow(a, size_in_digits, false, allocator) or_return;
|
||||
size_in_digits := (size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS
|
||||
size_in_digits += 0 if size_in_bits % 8 == 0 else 1
|
||||
internal_zero(a, false, allocator) or_return
|
||||
internal_grow(a, size_in_digits, false, allocator) or_return
|
||||
|
||||
if signed {
|
||||
sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative;
|
||||
buf = buf[:l-1];
|
||||
l -= 1;
|
||||
sign = .Zero_or_Positive if buf[l-1] == 0 else .Negative
|
||||
buf = buf[:l-1]
|
||||
l -= 1
|
||||
}
|
||||
|
||||
for _, i in buf {
|
||||
internal_shl(a, a, 8) or_return;
|
||||
internal_shl(a, a, 8) or_return
|
||||
if signed && sign == .Negative {
|
||||
a.digit[0] |= DIGIT(255 - buf[l-i-1]);
|
||||
a.digit[0] |= DIGIT(255 - buf[l-i-1])
|
||||
} else {
|
||||
a.digit[0] |= DIGIT(buf[l-i-1]);
|
||||
a.digit[0] |= DIGIT(buf[l-i-1])
|
||||
}
|
||||
}
|
||||
a.sign = sign;
|
||||
a.used = size_in_digits;
|
||||
internal_clamp(a) or_return;
|
||||
a.sign = sign
|
||||
a.used = size_in_digits
|
||||
internal_clamp(a) or_return
|
||||
|
||||
if signed && sign == .Negative {
|
||||
return internal_sub(a, a, 1);
|
||||
return internal_sub(a, a, 1)
|
||||
}
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize constants.
|
||||
*/
|
||||
INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
||||
INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}
|
||||
|
||||
initialize_constants :: proc() -> (res: int) {
|
||||
internal_set( INT_ZERO, 0); INT_ZERO.flags = {.Immutable};
|
||||
internal_set( INT_ONE, 1); INT_ONE.flags = {.Immutable};
|
||||
internal_set(INT_MINUS_ONE, -1); INT_MINUS_ONE.flags = {.Immutable};
|
||||
internal_set( INT_ZERO, 0); INT_ZERO.flags = {.Immutable}
|
||||
internal_set( INT_ONE, 1); INT_ONE.flags = {.Immutable}
|
||||
internal_set(INT_MINUS_ONE, -1); INT_MINUS_ONE.flags = {.Immutable}
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
internal_set( INT_NAN, 1); INT_NAN.flags = {.Immutable, .NaN};
|
||||
internal_set( INT_INF, 1); INT_INF.flags = {.Immutable, .Inf};
|
||||
internal_set( INT_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf};
|
||||
internal_set( INT_NAN, 1); INT_NAN.flags = {.Immutable, .NaN}
|
||||
internal_set( INT_INF, 1); INT_INF.flags = {.Immutable, .Inf}
|
||||
internal_set( INT_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf}
|
||||
|
||||
return _DEFAULT_MUL_KARATSUBA_CUTOFF;
|
||||
return _DEFAULT_MUL_KARATSUBA_CUTOFF
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -787,14 +787,14 @@ initialize_constants :: proc() -> (res: int) {
|
||||
Optional for an EXE, as this would be called at the very end of a process.
|
||||
*/
|
||||
destroy_constants :: proc() {
|
||||
internal_destroy(INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN);
|
||||
internal_destroy(INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN)
|
||||
}
|
||||
|
||||
|
||||
assert_if_nil :: #force_inline proc(integers: ..^Int, loc := #caller_location) {
|
||||
integers := integers;
|
||||
integers := integers
|
||||
|
||||
for i in &integers {
|
||||
assert(i != nil, "(nil)", loc);
|
||||
assert(i != nil, "(nil)", loc)
|
||||
}
|
||||
}
|
||||
|
||||
+719
-719
File diff suppressed because it is too large
Load Diff
+45
-45
@@ -22,37 +22,37 @@ package math_big
|
||||
2's complement `and`, returns `dest = a & b;`
|
||||
*/
|
||||
int_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a, b);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return;
|
||||
return #force_inline internal_int_and(dest, a, b);
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
return #force_inline internal_int_and(dest, a, b)
|
||||
}
|
||||
and :: proc { int_and, };
|
||||
and :: proc { int_and, }
|
||||
|
||||
/*
|
||||
2's complement `or`, returns `dest = a | b;`
|
||||
*/
|
||||
int_or :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a, b);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return;
|
||||
return #force_inline internal_int_or(dest, a, b);
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
return #force_inline internal_int_or(dest, a, b)
|
||||
}
|
||||
or :: proc { int_or, };
|
||||
or :: proc { int_or, }
|
||||
|
||||
/*
|
||||
2's complement `xor`, returns `dest = a ^ b;`
|
||||
*/
|
||||
int_xor :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a, b);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return;
|
||||
return #force_inline internal_int_xor(dest, a, b);
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
return #force_inline internal_int_xor(dest, a, b)
|
||||
}
|
||||
xor :: proc { int_xor, };
|
||||
xor :: proc { int_xor, }
|
||||
|
||||
/*
|
||||
dest = ~src
|
||||
@@ -61,31 +61,31 @@ int_complement :: proc(dest, src: ^Int, allocator := context.allocator) -> (err:
|
||||
/*
|
||||
Check that `src` and `dest` are usable.
|
||||
*/
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, src) or_return;
|
||||
return #force_inline internal_int_complement(dest, src);
|
||||
internal_clear_if_uninitialized(dest, src) or_return
|
||||
return #force_inline internal_int_complement(dest, src)
|
||||
}
|
||||
complement :: proc { int_complement, };
|
||||
complement :: proc { int_complement, }
|
||||
|
||||
/*
|
||||
quotient, remainder := numerator >> bits;
|
||||
`remainder` is allowed to be passed a `nil`, in which case `mod` won't be computed.
|
||||
*/
|
||||
int_shrmod :: proc(quotient, remainder, numerator: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(quotient, numerator);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(quotient, numerator)
|
||||
context.allocator = allocator
|
||||
|
||||
if err = internal_clear_if_uninitialized(quotient, numerator); err != nil { return err; }
|
||||
return #force_inline internal_int_shrmod(quotient, remainder, numerator, bits);
|
||||
return #force_inline internal_int_shrmod(quotient, remainder, numerator, bits)
|
||||
}
|
||||
shrmod :: proc { int_shrmod, };
|
||||
shrmod :: proc { int_shrmod, }
|
||||
|
||||
int_shr :: proc(dest, source: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
|
||||
return #force_inline shrmod(dest, nil, source, bits, allocator);
|
||||
return #force_inline shrmod(dest, nil, source, bits, allocator)
|
||||
}
|
||||
shr :: proc { int_shr, };
|
||||
shr :: proc { int_shr, }
|
||||
|
||||
/*
|
||||
Shift right by `digits` * _DIGIT_BITS bits.
|
||||
@@ -94,38 +94,38 @@ int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocato
|
||||
/*
|
||||
Check that `quotient` is usable.
|
||||
*/
|
||||
assert_if_nil(quotient);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(quotient)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(quotient) or_return;
|
||||
return #force_inline internal_int_shr_digit(quotient, digits);
|
||||
internal_clear_if_uninitialized(quotient) or_return
|
||||
return #force_inline internal_int_shr_digit(quotient, digits)
|
||||
}
|
||||
shr_digit :: proc { int_shr_digit, };
|
||||
shr_digit :: proc { int_shr_digit, }
|
||||
|
||||
/*
|
||||
Shift right by a certain bit count with sign extension.
|
||||
*/
|
||||
int_shr_signed :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, src) or_return;
|
||||
return #force_inline internal_int_shr_signed(dest, src, bits);
|
||||
internal_clear_if_uninitialized(dest, src) or_return
|
||||
return #force_inline internal_int_shr_signed(dest, src, bits)
|
||||
}
|
||||
|
||||
shr_signed :: proc { int_shr_signed, };
|
||||
shr_signed :: proc { int_shr_signed, }
|
||||
|
||||
/*
|
||||
Shift left by a certain bit count.
|
||||
*/
|
||||
int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, src) or_return;
|
||||
return #force_inline internal_int_shl(dest, src, bits);
|
||||
internal_clear_if_uninitialized(dest, src) or_return
|
||||
return #force_inline internal_int_shl(dest, src, bits)
|
||||
}
|
||||
shl :: proc { int_shl, };
|
||||
shl :: proc { int_shl, }
|
||||
|
||||
|
||||
/*
|
||||
@@ -135,10 +135,10 @@ int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocato
|
||||
/*
|
||||
Check that `quotient` is usable.
|
||||
*/
|
||||
assert_if_nil(quotient);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(quotient)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(quotient) or_return;
|
||||
return #force_inline internal_int_shl_digit(quotient, digits);
|
||||
internal_clear_if_uninitialized(quotient) or_return
|
||||
return #force_inline internal_int_shl_digit(quotient, digits)
|
||||
}
|
||||
shl_digit :: proc { int_shl_digit, };
|
||||
+73
-73
@@ -16,43 +16,43 @@ package math_big
|
||||
Returns true if it is, false if not.
|
||||
*/
|
||||
int_prime_is_divisible :: proc(a: ^Int, allocator := context.allocator) -> (res: bool, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
for prime in _private_prime_table {
|
||||
rem := #force_inline int_mod_digit(a, prime) or_return;
|
||||
rem := #force_inline int_mod_digit(a, prime) or_return
|
||||
if rem == 0 {
|
||||
return true, nil;
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
/*
|
||||
Default to not divisible.
|
||||
*/
|
||||
return false, nil;
|
||||
return false, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Computes xR**-1 == x (mod N) via Montgomery Reduction.
|
||||
*/
|
||||
internal_int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||
context.allocator = allocator;
|
||||
context.allocator = allocator
|
||||
/*
|
||||
Can the fast reduction [comba] method be used?
|
||||
Note that unlike in mul, you're safely allowed *less* than the available columns [255 per default],
|
||||
since carries are fixed up in the inner loop.
|
||||
*/
|
||||
digs := (n.used * 2) + 1;
|
||||
digs := (n.used * 2) + 1
|
||||
if digs < _WARRAY && x.used <= _WARRAY && n.used < _MAX_COMBA {
|
||||
return _private_montgomery_reduce_comba(x, n, rho);
|
||||
return _private_montgomery_reduce_comba(x, n, rho)
|
||||
}
|
||||
|
||||
/*
|
||||
Grow the input as required
|
||||
*/
|
||||
internal_grow(x, digs) or_return;
|
||||
x.used = digs;
|
||||
internal_grow(x, digs) or_return
|
||||
x.used = digs
|
||||
|
||||
for ix := 0; ix < n.used; ix += 1 {
|
||||
/*
|
||||
@@ -62,29 +62,29 @@ internal_int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := cont
|
||||
to reduce the input one digit at a time.
|
||||
*/
|
||||
|
||||
mu := DIGIT((_WORD(x.digit[ix]) * _WORD(rho)) & _WORD(_MASK));
|
||||
mu := DIGIT((_WORD(x.digit[ix]) * _WORD(rho)) & _WORD(_MASK))
|
||||
|
||||
/*
|
||||
a = a + mu * m * b**i
|
||||
Multiply and add in place.
|
||||
*/
|
||||
u := DIGIT(0);
|
||||
iy := int(0);
|
||||
u := DIGIT(0)
|
||||
iy := int(0)
|
||||
for ; iy < n.used; iy += 1 {
|
||||
/*
|
||||
Compute product and sum.
|
||||
*/
|
||||
r := (_WORD(mu) * _WORD(n.digit[iy]) + _WORD(u) + _WORD(x.digit[ix + iy]));
|
||||
r := (_WORD(mu) * _WORD(n.digit[iy]) + _WORD(u) + _WORD(x.digit[ix + iy]))
|
||||
|
||||
/*
|
||||
Get carry.
|
||||
*/
|
||||
u = DIGIT(r >> _DIGIT_BITS);
|
||||
u = DIGIT(r >> _DIGIT_BITS)
|
||||
|
||||
/*
|
||||
Fix digit.
|
||||
*/
|
||||
x.digit[ix + iy] = DIGIT(r & _WORD(_MASK));
|
||||
x.digit[ix + iy] = DIGIT(r & _WORD(_MASK))
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -92,10 +92,10 @@ internal_int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := cont
|
||||
Propagate carries upwards as required.
|
||||
*/
|
||||
for u != 0 {
|
||||
x.digit[ix + iy] += u;
|
||||
u = x.digit[ix + iy] >> _DIGIT_BITS;
|
||||
x.digit[ix + iy] &= _MASK;
|
||||
iy += 1;
|
||||
x.digit[ix + iy] += u
|
||||
u = x.digit[ix + iy] >> _DIGIT_BITS
|
||||
x.digit[ix + iy] &= _MASK
|
||||
iy += 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,26 +106,26 @@ internal_int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := cont
|
||||
|
||||
x = x/b**n.used.
|
||||
*/
|
||||
internal_clamp(x);
|
||||
internal_shr_digit(x, n.used);
|
||||
internal_clamp(x)
|
||||
internal_shr_digit(x, n.used)
|
||||
|
||||
/*
|
||||
if x >= n then x = x - n
|
||||
*/
|
||||
if internal_cmp_mag(x, n) != -1 {
|
||||
return internal_sub(x, x, n);
|
||||
return internal_sub(x, x, n)
|
||||
}
|
||||
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(x, n);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(x, n)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(x, n) or_return;
|
||||
internal_clear_if_uninitialized(x, n) or_return
|
||||
|
||||
return #force_inline internal_int_montgomery_reduce(x, n, rho);
|
||||
return #force_inline internal_int_montgomery_reduce(x, n, rho)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -135,39 +135,39 @@ int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := context.alloc
|
||||
the leading bit of b. This saves alot of multiple precision shifting.
|
||||
*/
|
||||
internal_int_montgomery_calc_normalization :: proc(a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
context.allocator = allocator;
|
||||
context.allocator = allocator
|
||||
/*
|
||||
How many bits of last digit does b use.
|
||||
*/
|
||||
bits := internal_count_bits(b) % _DIGIT_BITS;
|
||||
bits := internal_count_bits(b) % _DIGIT_BITS
|
||||
|
||||
if b.used > 1 {
|
||||
power := ((b.used - 1) * _DIGIT_BITS) + bits - 1;
|
||||
internal_int_power_of_two(a, power) or_return;
|
||||
power := ((b.used - 1) * _DIGIT_BITS) + bits - 1
|
||||
internal_int_power_of_two(a, power) or_return
|
||||
} else {
|
||||
internal_one(a);
|
||||
bits = 1;
|
||||
internal_one(a)
|
||||
bits = 1
|
||||
}
|
||||
|
||||
/*
|
||||
Now compute C = A * B mod b.
|
||||
*/
|
||||
for x := bits - 1; x < _DIGIT_BITS; x += 1 {
|
||||
internal_int_shl1(a, a) or_return;
|
||||
internal_int_shl1(a, a) or_return
|
||||
if internal_cmp_mag(a, b) != -1 {
|
||||
internal_sub(a, a, b) or_return;
|
||||
internal_sub(a, a, b) or_return
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
int_montgomery_calc_normalization :: proc(a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(a, b);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return;
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
|
||||
return #force_inline internal_int_montgomery_calc_normalization(a, b);
|
||||
return #force_inline internal_int_montgomery_calc_normalization(a, b)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -182,29 +182,29 @@ internal_int_montgomery_setup :: proc(n: ^Int) -> (rho: DIGIT, err: Error) {
|
||||
=> 2*X*A - X*X*A*A = 1
|
||||
=> 2*(1) - (1) = 1
|
||||
*/
|
||||
b := n.digit[0];
|
||||
b := n.digit[0]
|
||||
if b & 1 == 0 { return 0, .Invalid_Argument; }
|
||||
|
||||
x := (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
|
||||
x *= 2 - (b * x); /* here x*a==1 mod 2**8 */
|
||||
x *= 2 - (b * x); /* here x*a==1 mod 2**16 */
|
||||
x := (((b + 2) & 4) << 1) + b /* here x*a==1 mod 2**4 */
|
||||
x *= 2 - (b * x) /* here x*a==1 mod 2**8 */
|
||||
x *= 2 - (b * x) /* here x*a==1 mod 2**16 */
|
||||
when _WORD_TYPE_BITS == 64 {
|
||||
x *= 2 - (b * x); /* here x*a==1 mod 2**32 */
|
||||
x *= 2 - (b * x); /* here x*a==1 mod 2**64 */
|
||||
x *= 2 - (b * x) /* here x*a==1 mod 2**32 */
|
||||
x *= 2 - (b * x) /* here x*a==1 mod 2**64 */
|
||||
}
|
||||
|
||||
/*
|
||||
rho = -1/m mod b
|
||||
*/
|
||||
rho = DIGIT(((_WORD(1) << _WORD(_DIGIT_BITS)) - _WORD(x)) & _WORD(_MASK));
|
||||
return rho, nil;
|
||||
rho = DIGIT(((_WORD(1) << _WORD(_DIGIT_BITS)) - _WORD(x)) & _WORD(_MASK))
|
||||
return rho, nil
|
||||
}
|
||||
|
||||
int_montgomery_setup :: proc(n: ^Int, allocator := context.allocator) -> (rho: DIGIT, err: Error) {
|
||||
assert_if_nil(n);
|
||||
internal_clear_if_uninitialized(n, allocator) or_return;
|
||||
assert_if_nil(n)
|
||||
internal_clear_if_uninitialized(n, allocator) or_return
|
||||
|
||||
return #force_inline internal_int_montgomery_setup(n);
|
||||
return #force_inline internal_int_montgomery_setup(n)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -213,44 +213,44 @@ int_montgomery_setup :: proc(n: ^Int, allocator := context.allocator) -> (rho: D
|
||||
number_of_rabin_miller_trials :: proc(bit_size: int) -> (number_of_trials: int) {
|
||||
switch {
|
||||
case bit_size <= 80:
|
||||
return - 1; /* Use deterministic algorithm for size <= 80 bits */
|
||||
return - 1 /* Use deterministic algorithm for size <= 80 bits */
|
||||
case bit_size >= 81 && bit_size < 96:
|
||||
return 37; /* max. error = 2^(-96) */
|
||||
return 37 /* max. error = 2^(-96) */
|
||||
case bit_size >= 96 && bit_size < 128:
|
||||
return 32; /* max. error = 2^(-96) */
|
||||
return 32 /* max. error = 2^(-96) */
|
||||
case bit_size >= 128 && bit_size < 160:
|
||||
return 40; /* max. error = 2^(-112) */
|
||||
return 40 /* max. error = 2^(-112) */
|
||||
case bit_size >= 160 && bit_size < 256:
|
||||
return 35; /* max. error = 2^(-112) */
|
||||
return 35 /* max. error = 2^(-112) */
|
||||
case bit_size >= 256 && bit_size < 384:
|
||||
return 27; /* max. error = 2^(-128) */
|
||||
return 27 /* max. error = 2^(-128) */
|
||||
case bit_size >= 384 && bit_size < 512:
|
||||
return 16; /* max. error = 2^(-128) */
|
||||
return 16 /* max. error = 2^(-128) */
|
||||
case bit_size >= 512 && bit_size < 768:
|
||||
return 18; /* max. error = 2^(-160) */
|
||||
return 18 /* max. error = 2^(-160) */
|
||||
case bit_size >= 768 && bit_size < 896:
|
||||
return 11; /* max. error = 2^(-160) */
|
||||
return 11 /* max. error = 2^(-160) */
|
||||
case bit_size >= 896 && bit_size < 1_024:
|
||||
return 10; /* max. error = 2^(-160) */
|
||||
return 10 /* max. error = 2^(-160) */
|
||||
case bit_size >= 1_024 && bit_size < 1_536:
|
||||
return 12; /* max. error = 2^(-192) */
|
||||
return 12 /* max. error = 2^(-192) */
|
||||
case bit_size >= 1_536 && bit_size < 2_048:
|
||||
return 8; /* max. error = 2^(-192) */
|
||||
return 8 /* max. error = 2^(-192) */
|
||||
case bit_size >= 2_048 && bit_size < 3_072:
|
||||
return 6; /* max. error = 2^(-192) */
|
||||
return 6 /* max. error = 2^(-192) */
|
||||
case bit_size >= 3_072 && bit_size < 4_096:
|
||||
return 4; /* max. error = 2^(-192) */
|
||||
return 4 /* max. error = 2^(-192) */
|
||||
case bit_size >= 4_096 && bit_size < 5_120:
|
||||
return 5; /* max. error = 2^(-256) */
|
||||
return 5 /* max. error = 2^(-256) */
|
||||
case bit_size >= 5_120 && bit_size < 6_144:
|
||||
return 4; /* max. error = 2^(-256) */
|
||||
return 4 /* max. error = 2^(-256) */
|
||||
case bit_size >= 6_144 && bit_size < 8_192:
|
||||
return 4; /* max. error = 2^(-256) */
|
||||
return 4 /* max. error = 2^(-256) */
|
||||
case bit_size >= 8_192 && bit_size < 9_216:
|
||||
return 3; /* max. error = 2^(-256) */
|
||||
return 3 /* max. error = 2^(-256) */
|
||||
case bit_size >= 9_216 && bit_size < 10_240:
|
||||
return 3; /* max. error = 2^(-256) */
|
||||
return 3 /* max. error = 2^(-256) */
|
||||
case:
|
||||
return 2; /* For keysizes bigger than 10_240 use always at least 2 Rounds */
|
||||
return 2 /* For keysizes bigger than 10_240 use always at least 2 Rounds */
|
||||
}
|
||||
}
|
||||
+645
-645
File diff suppressed because it is too large
Load Diff
+175
-175
@@ -21,14 +21,14 @@ package math_big
|
||||
High-level addition. Handles sign.
|
||||
*/
|
||||
int_add :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a, b);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, a, b) or_return;
|
||||
internal_clear_if_uninitialized(dest, a, b) or_return
|
||||
/*
|
||||
All parameters have been initialized.
|
||||
*/
|
||||
return #force_inline internal_int_add_signed(dest, a, b);
|
||||
return #force_inline internal_int_add_signed(dest, a, b)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -38,33 +38,33 @@ int_add :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error
|
||||
dest = a + digit;
|
||||
*/
|
||||
int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
/*
|
||||
Grow destination as required.
|
||||
*/
|
||||
grow(dest, a.used + 1) or_return;
|
||||
grow(dest, a.used + 1) or_return
|
||||
|
||||
/*
|
||||
All parameters have been initialized.
|
||||
*/
|
||||
return #force_inline internal_int_add_digit(dest, a, digit);
|
||||
return #force_inline internal_int_add_digit(dest, a, digit)
|
||||
}
|
||||
|
||||
/*
|
||||
High-level subtraction, dest = number - decrease. Handles signs.
|
||||
*/
|
||||
int_sub :: proc(dest, number, decrease: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, number, decrease);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, number, decrease)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, number, decrease) or_return;
|
||||
internal_clear_if_uninitialized(dest, number, decrease) or_return
|
||||
/*
|
||||
All parameters have been initialized.
|
||||
*/
|
||||
return #force_inline internal_int_sub_signed(dest, number, decrease);
|
||||
return #force_inline internal_int_sub_signed(dest, number, decrease)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -74,19 +74,19 @@ int_sub :: proc(dest, number, decrease: ^Int, allocator := context.allocator) ->
|
||||
dest = a - digit;
|
||||
*/
|
||||
int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
/*
|
||||
Grow destination as required.
|
||||
*/
|
||||
grow(dest, a.used + 1) or_return;
|
||||
grow(dest, a.used + 1) or_return
|
||||
|
||||
/*
|
||||
All parameters have been initialized.
|
||||
*/
|
||||
return #force_inline internal_int_sub_digit(dest, a, digit);
|
||||
return #force_inline internal_int_sub_digit(dest, a, digit)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -94,64 +94,64 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocato
|
||||
dest = src >> 1
|
||||
*/
|
||||
int_halve :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, src) or_return;
|
||||
internal_clear_if_uninitialized(dest, src) or_return
|
||||
/*
|
||||
Grow destination as required.
|
||||
*/
|
||||
if dest != src { grow(dest, src.used + 1) or_return }
|
||||
|
||||
return #force_inline internal_int_shr1(dest, src);
|
||||
return #force_inline internal_int_shr1(dest, src)
|
||||
}
|
||||
halve :: proc { int_halve, };
|
||||
shr1 :: halve;
|
||||
halve :: proc { int_halve, }
|
||||
shr1 :: halve
|
||||
|
||||
/*
|
||||
dest = src * 2
|
||||
dest = src << 1
|
||||
*/
|
||||
int_double :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, src) or_return;
|
||||
internal_clear_if_uninitialized(dest, src) or_return
|
||||
/*
|
||||
Grow destination as required.
|
||||
*/
|
||||
if dest != src { grow(dest, src.used + 1) or_return; }
|
||||
|
||||
return #force_inline internal_int_shl1(dest, src);
|
||||
return #force_inline internal_int_shl1(dest, src)
|
||||
}
|
||||
double :: proc { int_double, };
|
||||
shl1 :: double;
|
||||
double :: proc { int_double, }
|
||||
shl1 :: double
|
||||
|
||||
/*
|
||||
Multiply by a DIGIT.
|
||||
*/
|
||||
int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(src, dest) or_return;
|
||||
internal_clear_if_uninitialized(src, dest) or_return
|
||||
|
||||
return #force_inline internal_int_mul_digit(dest, src, multiplier);
|
||||
return #force_inline internal_int_mul_digit(dest, src, multiplier)
|
||||
}
|
||||
|
||||
/*
|
||||
High level multiplication (handles sign).
|
||||
*/
|
||||
int_mul :: proc(dest, src, multiplier: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, src, multiplier);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src, multiplier)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, src, multiplier) or_return;
|
||||
internal_clear_if_uninitialized(dest, src, multiplier) or_return
|
||||
|
||||
return #force_inline internal_int_mul(dest, src, multiplier);
|
||||
return #force_inline internal_int_mul(dest, src, multiplier)
|
||||
}
|
||||
|
||||
mul :: proc { int_mul, int_mul_digit, };
|
||||
mul :: proc { int_mul, int_mul_digit, }
|
||||
|
||||
sqr :: proc(dest, src: ^Int) -> (err: Error) { return mul(dest, src, src); }
|
||||
|
||||
@@ -160,46 +160,46 @@ sqr :: proc(dest, src: ^Int) -> (err: Error) { return mul(dest, src, src); }
|
||||
Both the quotient and remainder are optional and may be passed a nil.
|
||||
*/
|
||||
int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
context.allocator = allocator;
|
||||
context.allocator = allocator
|
||||
|
||||
/*
|
||||
Early out if neither of the results is wanted.
|
||||
*/
|
||||
if quotient == nil && remainder == nil { return nil; }
|
||||
internal_clear_if_uninitialized(numerator, denominator) or_return;
|
||||
internal_clear_if_uninitialized(numerator, denominator) or_return
|
||||
|
||||
return #force_inline internal_divmod(quotient, remainder, numerator, denominator);
|
||||
return #force_inline internal_divmod(quotient, remainder, numerator, denominator)
|
||||
}
|
||||
|
||||
int_divmod_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, allocator := context.allocator) -> (remainder: DIGIT, err: Error) {
|
||||
assert_if_nil(quotient, numerator);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(quotient, numerator)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(numerator) or_return;
|
||||
internal_clear_if_uninitialized(numerator) or_return
|
||||
|
||||
return #force_inline internal_divmod(quotient, numerator, denominator);
|
||||
return #force_inline internal_divmod(quotient, numerator, denominator)
|
||||
}
|
||||
divmod :: proc{ int_divmod, int_divmod_digit, };
|
||||
divmod :: proc{ int_divmod, int_divmod_digit, }
|
||||
|
||||
int_div :: proc(quotient, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(quotient, numerator, denominator);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(quotient, numerator, denominator)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(numerator, denominator) or_return;
|
||||
internal_clear_if_uninitialized(numerator, denominator) or_return
|
||||
|
||||
return #force_inline internal_divmod(quotient, nil, numerator, denominator);
|
||||
return #force_inline internal_divmod(quotient, nil, numerator, denominator)
|
||||
}
|
||||
|
||||
int_div_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(quotient, numerator);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(quotient, numerator)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(numerator) or_return;
|
||||
internal_clear_if_uninitialized(numerator) or_return
|
||||
|
||||
_ = #force_inline internal_divmod(quotient, numerator, denominator) or_return;
|
||||
return;
|
||||
_ = #force_inline internal_divmod(quotient, numerator, denominator) or_return
|
||||
return
|
||||
}
|
||||
div :: proc { int_div, int_div_digit, };
|
||||
div :: proc { int_div, int_div_digit, }
|
||||
|
||||
/*
|
||||
remainder = numerator % denominator.
|
||||
@@ -207,80 +207,80 @@ div :: proc { int_div, int_div_digit, };
|
||||
denominator < remainder <= 0 if denominator < 0
|
||||
*/
|
||||
int_mod :: proc(remainder, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(remainder, numerator, denominator);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(remainder, numerator, denominator)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(numerator, denominator) or_return;
|
||||
internal_clear_if_uninitialized(numerator, denominator) or_return
|
||||
|
||||
return #force_inline internal_int_mod(remainder, numerator, denominator);
|
||||
return #force_inline internal_int_mod(remainder, numerator, denominator)
|
||||
}
|
||||
|
||||
int_mod_digit :: proc(numerator: ^Int, denominator: DIGIT, allocator := context.allocator) -> (remainder: DIGIT, err: Error) {
|
||||
return #force_inline internal_divmod(nil, numerator, denominator, allocator);
|
||||
return #force_inline internal_divmod(nil, numerator, denominator, allocator)
|
||||
}
|
||||
|
||||
mod :: proc { int_mod, int_mod_digit, };
|
||||
mod :: proc { int_mod, int_mod_digit, }
|
||||
|
||||
/*
|
||||
remainder = (number + addend) % modulus.
|
||||
*/
|
||||
int_addmod :: proc(remainder, number, addend, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(remainder, number, addend);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(remainder, number, addend)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(number, addend, modulus) or_return;
|
||||
internal_clear_if_uninitialized(number, addend, modulus) or_return
|
||||
|
||||
return #force_inline internal_addmod(remainder, number, addend, modulus);
|
||||
return #force_inline internal_addmod(remainder, number, addend, modulus)
|
||||
}
|
||||
addmod :: proc { int_addmod, };
|
||||
addmod :: proc { int_addmod, }
|
||||
|
||||
/*
|
||||
remainder = (number - decrease) % modulus.
|
||||
*/
|
||||
int_submod :: proc(remainder, number, decrease, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(remainder, number, decrease);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(remainder, number, decrease)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(number, decrease, modulus) or_return;
|
||||
internal_clear_if_uninitialized(number, decrease, modulus) or_return
|
||||
|
||||
return #force_inline internal_submod(remainder, number, decrease, modulus);
|
||||
return #force_inline internal_submod(remainder, number, decrease, modulus)
|
||||
}
|
||||
submod :: proc { int_submod, };
|
||||
submod :: proc { int_submod, }
|
||||
|
||||
/*
|
||||
remainder = (number * multiplicand) % modulus.
|
||||
*/
|
||||
int_mulmod :: proc(remainder, number, multiplicand, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(remainder, number, multiplicand);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(remainder, number, multiplicand)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(number, multiplicand, modulus) or_return;
|
||||
internal_clear_if_uninitialized(number, multiplicand, modulus) or_return
|
||||
|
||||
return #force_inline internal_mulmod(remainder, number, multiplicand, modulus);
|
||||
return #force_inline internal_mulmod(remainder, number, multiplicand, modulus)
|
||||
}
|
||||
mulmod :: proc { int_mulmod, };
|
||||
mulmod :: proc { int_mulmod, }
|
||||
|
||||
/*
|
||||
remainder = (number * number) % modulus.
|
||||
*/
|
||||
int_sqrmod :: proc(remainder, number, modulus: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(remainder, number, modulus);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(remainder, number, modulus)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(number, modulus) or_return;
|
||||
internal_clear_if_uninitialized(number, modulus) or_return
|
||||
|
||||
return #force_inline internal_sqrmod(remainder, number, modulus);
|
||||
return #force_inline internal_sqrmod(remainder, number, modulus)
|
||||
}
|
||||
sqrmod :: proc { int_sqrmod, };
|
||||
sqrmod :: proc { int_sqrmod, }
|
||||
|
||||
|
||||
int_factorial :: proc(res: ^Int, n: int, allocator := context.allocator) -> (err: Error) {
|
||||
if n < 0 || n > FACTORIAL_MAX_N { return .Invalid_Argument; }
|
||||
assert_if_nil(res);
|
||||
assert_if_nil(res)
|
||||
|
||||
return #force_inline internal_int_factorial(res, n, allocator);
|
||||
return #force_inline internal_int_factorial(res, n, allocator)
|
||||
}
|
||||
factorial :: proc { int_factorial, };
|
||||
factorial :: proc { int_factorial, }
|
||||
|
||||
|
||||
/*
|
||||
@@ -299,8 +299,8 @@ factorial :: proc { int_factorial, };
|
||||
|
||||
*/
|
||||
int_choose_digit :: proc(res: ^Int, n, k: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(res);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(res)
|
||||
context.allocator = allocator
|
||||
|
||||
if n < 0 || n > FACTORIAL_MAX_N { return .Invalid_Argument; }
|
||||
if k > n { return internal_zero(res); }
|
||||
@@ -308,8 +308,8 @@ int_choose_digit :: proc(res: ^Int, n, k: int, allocator := context.allocator) -
|
||||
/*
|
||||
res = n! / (k! * (n - k)!)
|
||||
*/
|
||||
n_fac, k_fac, n_minus_k_fac := &Int{}, &Int{}, &Int{};
|
||||
defer internal_destroy(n_fac, k_fac, n_minus_k_fac);
|
||||
n_fac, k_fac, n_minus_k_fac := &Int{}, &Int{}, &Int{}
|
||||
defer internal_destroy(n_fac, k_fac, n_minus_k_fac)
|
||||
|
||||
#force_inline internal_int_factorial(n_minus_k_fac, n - k) or_return;
|
||||
#force_inline internal_int_factorial(k_fac, k) or_return;
|
||||
@@ -318,112 +318,112 @@ int_choose_digit :: proc(res: ^Int, n, k: int, allocator := context.allocator) -
|
||||
#force_inline internal_int_factorial(n_fac, n) or_return;
|
||||
#force_inline internal_div(res, n_fac, k_fac) or_return;
|
||||
|
||||
return;
|
||||
return
|
||||
}
|
||||
choose :: proc { int_choose_digit, };
|
||||
choose :: proc { int_choose_digit, }
|
||||
|
||||
/*
|
||||
Function computing both GCD and (if target isn't `nil`) also LCM.
|
||||
*/
|
||||
int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
if res_gcd == nil && res_lcm == nil { return nil; }
|
||||
assert_if_nil(a, b);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return;
|
||||
return #force_inline internal_int_gcd_lcm(res_gcd, res_lcm, a, b);
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
return #force_inline internal_int_gcd_lcm(res_gcd, res_lcm, a, b)
|
||||
}
|
||||
gcd_lcm :: proc { int_gcd_lcm, };
|
||||
gcd_lcm :: proc { int_gcd_lcm, }
|
||||
|
||||
/*
|
||||
Greatest Common Divisor.
|
||||
*/
|
||||
int_gcd :: proc(res, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
return #force_inline int_gcd_lcm(res, nil, a, b, allocator);
|
||||
return #force_inline int_gcd_lcm(res, nil, a, b, allocator)
|
||||
}
|
||||
gcd :: proc { int_gcd, };
|
||||
gcd :: proc { int_gcd, }
|
||||
|
||||
/*
|
||||
Least Common Multiple.
|
||||
*/
|
||||
int_lcm :: proc(res, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
return #force_inline int_gcd_lcm(nil, res, a, b, allocator);
|
||||
return #force_inline int_gcd_lcm(nil, res, a, b, allocator)
|
||||
}
|
||||
lcm :: proc { int_lcm, };
|
||||
lcm :: proc { int_lcm, }
|
||||
|
||||
/*
|
||||
remainder = numerator % (1 << bits)
|
||||
*/
|
||||
int_mod_bits :: proc(remainder, numerator: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(remainder, numerator);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(remainder, numerator)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(remainder, numerator) or_return;
|
||||
internal_clear_if_uninitialized(remainder, numerator) or_return
|
||||
if bits < 0 { return .Invalid_Argument; }
|
||||
|
||||
return #force_inline internal_int_mod_bits(remainder, numerator, bits);
|
||||
return #force_inline internal_int_mod_bits(remainder, numerator, bits)
|
||||
}
|
||||
|
||||
mod_bits :: proc { int_mod_bits, };
|
||||
mod_bits :: proc { int_mod_bits, }
|
||||
|
||||
|
||||
/*
|
||||
Logs and roots and such.
|
||||
*/
|
||||
int_log :: proc(a: ^Int, base: DIGIT, allocator := context.allocator) -> (res: int, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_int_log(a, base);
|
||||
return #force_inline internal_int_log(a, base)
|
||||
}
|
||||
|
||||
digit_log :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error) {
|
||||
return #force_inline internal_digit_log(a, base);
|
||||
return #force_inline internal_digit_log(a, base)
|
||||
}
|
||||
log :: proc { int_log, digit_log, };
|
||||
log :: proc { int_log, digit_log, }
|
||||
|
||||
/*
|
||||
Calculate `dest = base^power` using a square-multiply algorithm.
|
||||
*/
|
||||
int_pow :: proc(dest, base: ^Int, power: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, base);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, base)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, base) or_return;
|
||||
internal_clear_if_uninitialized(dest, base) or_return
|
||||
|
||||
return #force_inline internal_int_pow(dest, base, power);
|
||||
return #force_inline internal_int_pow(dest, base, power)
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate `dest = base^power` using a square-multiply algorithm.
|
||||
*/
|
||||
int_pow_int :: proc(dest: ^Int, base, power: int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest);
|
||||
assert_if_nil(dest)
|
||||
|
||||
return #force_inline internal_pow(dest, base, power, allocator);
|
||||
return #force_inline internal_pow(dest, base, power, allocator)
|
||||
}
|
||||
|
||||
pow :: proc { int_pow, int_pow_int, small_pow, };
|
||||
exp :: pow;
|
||||
pow :: proc { int_pow, int_pow_int, small_pow, }
|
||||
exp :: pow
|
||||
|
||||
small_pow :: proc(base: _WORD, exponent: _WORD) -> (result: _WORD) {
|
||||
return #force_inline internal_small_pow(base, exponent);
|
||||
return #force_inline internal_small_pow(base, exponent)
|
||||
}
|
||||
|
||||
/*
|
||||
This function is less generic than `root_n`, simpler and faster.
|
||||
*/
|
||||
int_sqrt :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, src);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(dest, src)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(dest, src) or_return;
|
||||
internal_clear_if_uninitialized(dest, src) or_return
|
||||
|
||||
return #force_inline internal_int_sqrt(dest, src);
|
||||
return #force_inline internal_int_sqrt(dest, src)
|
||||
}
|
||||
sqrt :: proc { int_sqrt, };
|
||||
sqrt :: proc { int_sqrt, }
|
||||
|
||||
|
||||
/*
|
||||
@@ -434,22 +434,22 @@ sqrt :: proc { int_sqrt, };
|
||||
which will find the root in `log(n)` time where each step involves a fair bit.
|
||||
*/
|
||||
int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.allocator) -> (err: Error) {
|
||||
context.allocator = allocator;
|
||||
context.allocator = allocator
|
||||
|
||||
/*
|
||||
Fast path for n == 2.
|
||||
*/
|
||||
if n == 2 { return sqrt(dest, src); }
|
||||
|
||||
assert_if_nil(dest, src);
|
||||
assert_if_nil(dest, src)
|
||||
/*
|
||||
Initialize dest + src if needed.
|
||||
*/
|
||||
internal_clear_if_uninitialized(dest, src) or_return;
|
||||
internal_clear_if_uninitialized(dest, src) or_return
|
||||
|
||||
return #force_inline internal_int_root_n(dest, src, n);
|
||||
return #force_inline internal_int_root_n(dest, src, n)
|
||||
}
|
||||
root_n :: proc { int_root_n, };
|
||||
root_n :: proc { int_root_n, }
|
||||
|
||||
/*
|
||||
Comparison routines.
|
||||
@@ -458,103 +458,103 @@ root_n :: proc { int_root_n, };
|
||||
int_is_initialized :: proc(a: ^Int) -> bool {
|
||||
if a == nil { return false; }
|
||||
|
||||
return #force_inline internal_int_is_initialized(a);
|
||||
return #force_inline internal_int_is_initialized(a)
|
||||
}
|
||||
|
||||
int_is_zero :: proc(a: ^Int, allocator := context.allocator) -> (zero: bool, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_is_zero(a), nil;
|
||||
return #force_inline internal_is_zero(a), nil
|
||||
}
|
||||
|
||||
int_is_positive :: proc(a: ^Int, allocator := context.allocator) -> (positive: bool, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_is_positive(a), nil;
|
||||
return #force_inline internal_is_positive(a), nil
|
||||
}
|
||||
|
||||
int_is_negative :: proc(a: ^Int, allocator := context.allocator) -> (negative: bool, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_is_negative(a), nil;
|
||||
return #force_inline internal_is_negative(a), nil
|
||||
}
|
||||
|
||||
int_is_even :: proc(a: ^Int, allocator := context.allocator) -> (even: bool, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_is_even(a), nil;
|
||||
return #force_inline internal_is_even(a), nil
|
||||
}
|
||||
|
||||
int_is_odd :: proc(a: ^Int, allocator := context.allocator) -> (odd: bool, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_is_odd(a), nil;
|
||||
return #force_inline internal_is_odd(a), nil
|
||||
}
|
||||
|
||||
platform_int_is_power_of_two :: #force_inline proc(a: int) -> bool {
|
||||
return ((a) != 0) && (((a) & ((a) - 1)) == 0);
|
||||
return ((a) != 0) && (((a) & ((a) - 1)) == 0)
|
||||
}
|
||||
|
||||
int_is_power_of_two :: proc(a: ^Int, allocator := context.allocator) -> (res: bool, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_is_power_of_two(a), nil;
|
||||
return #force_inline internal_is_power_of_two(a), nil
|
||||
}
|
||||
|
||||
/*
|
||||
Compare two `Int`s, signed.
|
||||
*/
|
||||
int_compare :: proc(a, b: ^Int, allocator := context.allocator) -> (comparison: int, err: Error) {
|
||||
assert_if_nil(a, b);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return;
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
|
||||
return #force_inline internal_cmp(a, b), nil;
|
||||
return #force_inline internal_cmp(a, b), nil
|
||||
}
|
||||
int_cmp :: int_compare;
|
||||
int_cmp :: int_compare
|
||||
|
||||
/*
|
||||
Compare an `Int` to an unsigned number upto the size of the backing type.
|
||||
*/
|
||||
int_compare_digit :: proc(a: ^Int, b: DIGIT, allocator := context.allocator) -> (comparison: int, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_cmp_digit(a, b), nil;
|
||||
return #force_inline internal_cmp_digit(a, b), nil
|
||||
}
|
||||
int_cmp_digit :: int_compare_digit;
|
||||
int_cmp_digit :: int_compare_digit
|
||||
|
||||
/*
|
||||
Compare the magnitude of two `Int`s, unsigned.
|
||||
*/
|
||||
int_compare_magnitude :: proc(a, b: ^Int, allocator := context.allocator) -> (res: int, err: Error) {
|
||||
assert_if_nil(a, b);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return;
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
|
||||
return #force_inline internal_cmp_mag(a, b), nil;
|
||||
return #force_inline internal_cmp_mag(a, b), nil
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -564,10 +564,10 @@ int_compare_magnitude :: proc(a, b: ^Int, allocator := context.allocator) -> (re
|
||||
Assumes `a` not to be `nil` and to have been initialized.
|
||||
*/
|
||||
int_is_square :: proc(a: ^Int, allocator := context.allocator) -> (square: bool, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a) or_return;
|
||||
internal_clear_if_uninitialized(a) or_return
|
||||
|
||||
return #force_inline internal_int_is_square(a);
|
||||
return #force_inline internal_int_is_square(a)
|
||||
}
|
||||
+140
-140
@@ -22,15 +22,15 @@ import "core:mem"
|
||||
This version of `itoa` allocates one behalf of the caller. The caller must free the string.
|
||||
*/
|
||||
int_itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator := context.allocator) -> (res: string, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
a := a; radix := radix;
|
||||
clear_if_uninitialized(a) or_return;
|
||||
a := a; radix := radix
|
||||
clear_if_uninitialized(a) or_return
|
||||
/*
|
||||
Radix defaults to 10.
|
||||
*/
|
||||
radix = radix if radix > 0 else 10;
|
||||
radix = radix if radix > 0 else 10
|
||||
|
||||
/*
|
||||
TODO: If we want to write a prefix for some of the radixes, we can oversize the buffer.
|
||||
@@ -41,39 +41,39 @@ int_itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, alloc
|
||||
Calculate the size of the buffer we need, and
|
||||
Exit if calculating the size returned an error.
|
||||
*/
|
||||
size := radix_size(a, radix, zero_terminate) or_return;
|
||||
size := radix_size(a, radix, zero_terminate) or_return
|
||||
|
||||
/*
|
||||
Allocate the buffer we need.
|
||||
*/
|
||||
buffer := make([]u8, size);
|
||||
buffer := make([]u8, size)
|
||||
|
||||
/*
|
||||
Write the digits out into the buffer.
|
||||
*/
|
||||
written: int;
|
||||
written, err = int_itoa_raw(a, radix, buffer, size, zero_terminate);
|
||||
written: int
|
||||
written, err = int_itoa_raw(a, radix, buffer, size, zero_terminate)
|
||||
|
||||
return string(buffer[:written]), err;
|
||||
return string(buffer[:written]), err
|
||||
}
|
||||
|
||||
/*
|
||||
This version of `itoa` allocates one behalf of the caller. The caller must free the string.
|
||||
*/
|
||||
int_itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -> (res: cstring, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
a := a; radix := radix;
|
||||
clear_if_uninitialized(a) or_return;
|
||||
a := a; radix := radix
|
||||
clear_if_uninitialized(a) or_return
|
||||
/*
|
||||
Radix defaults to 10.
|
||||
*/
|
||||
radix = radix if radix > 0 else 10;
|
||||
radix = radix if radix > 0 else 10
|
||||
|
||||
s: string;
|
||||
s, err = int_itoa_string(a, radix, true);
|
||||
return cstring(raw_data(s)), err;
|
||||
s: string
|
||||
s, err = int_itoa_string(a, radix, true)
|
||||
return cstring(raw_data(s)), err
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -97,57 +97,57 @@ int_itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocato
|
||||
and having to perform a buffer overflow check each character.
|
||||
*/
|
||||
int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
|
||||
assert_if_nil(a);
|
||||
a := a; radix := radix; size := size;
|
||||
clear_if_uninitialized(a) or_return;
|
||||
assert_if_nil(a)
|
||||
a := a; radix := radix; size := size
|
||||
clear_if_uninitialized(a) or_return
|
||||
/*
|
||||
Radix defaults to 10.
|
||||
*/
|
||||
radix = radix if radix > 0 else 10;
|
||||
radix = radix if radix > 0 else 10
|
||||
if radix < 2 || radix > 64 {
|
||||
return 0, .Invalid_Argument;
|
||||
return 0, .Invalid_Argument
|
||||
}
|
||||
|
||||
/*
|
||||
We weren't given a size. Let's compute it.
|
||||
*/
|
||||
if size == -1 {
|
||||
size = radix_size(a, radix, zero_terminate) or_return;
|
||||
size = radix_size(a, radix, zero_terminate) or_return
|
||||
}
|
||||
|
||||
/*
|
||||
Early exit if the buffer we were given is too small.
|
||||
*/
|
||||
available := len(buffer);
|
||||
available := len(buffer)
|
||||
if available < size {
|
||||
return 0, .Buffer_Overflow;
|
||||
return 0, .Buffer_Overflow
|
||||
}
|
||||
/*
|
||||
Fast path for when `Int` == 0 or the entire `Int` fits in a single radix digit.
|
||||
*/
|
||||
z, _ := is_zero(a);
|
||||
z, _ := is_zero(a)
|
||||
if z || (a.used == 1 && a.digit[0] < DIGIT(radix)) {
|
||||
if zero_terminate {
|
||||
available -= 1;
|
||||
buffer[available] = 0;
|
||||
available -= 1
|
||||
buffer[available] = 0
|
||||
}
|
||||
available -= 1;
|
||||
buffer[available] = RADIX_TABLE[a.digit[0]];
|
||||
available -= 1
|
||||
buffer[available] = RADIX_TABLE[a.digit[0]]
|
||||
|
||||
if n, _ := is_neg(a); n {
|
||||
available -= 1;
|
||||
buffer[available] = '-';
|
||||
available -= 1
|
||||
buffer[available] = '-'
|
||||
}
|
||||
|
||||
/*
|
||||
If we overestimated the size, we need to move the buffer left.
|
||||
*/
|
||||
written = len(buffer) - available;
|
||||
written = len(buffer) - available
|
||||
if written < size {
|
||||
diff := size - written;
|
||||
mem.copy(&buffer[0], &buffer[diff], written);
|
||||
diff := size - written
|
||||
mem.copy(&buffer[0], &buffer[diff], written)
|
||||
}
|
||||
return written, nil;
|
||||
return written, nil
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -155,32 +155,32 @@ int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_ter
|
||||
*/
|
||||
if a.used == 1 || a.used == 2 {
|
||||
if zero_terminate {
|
||||
available -= 1;
|
||||
buffer[available] = 0;
|
||||
available -= 1
|
||||
buffer[available] = 0
|
||||
}
|
||||
|
||||
val := _WORD(a.digit[1]) << _DIGIT_BITS + _WORD(a.digit[0]);
|
||||
val := _WORD(a.digit[1]) << _DIGIT_BITS + _WORD(a.digit[0])
|
||||
for val > 0 {
|
||||
q := val / _WORD(radix);
|
||||
available -= 1;
|
||||
buffer[available] = RADIX_TABLE[val - (q * _WORD(radix))];
|
||||
q := val / _WORD(radix)
|
||||
available -= 1
|
||||
buffer[available] = RADIX_TABLE[val - (q * _WORD(radix))]
|
||||
|
||||
val = q;
|
||||
val = q
|
||||
}
|
||||
if n, _ := is_neg(a); n {
|
||||
available -= 1;
|
||||
buffer[available] = '-';
|
||||
available -= 1
|
||||
buffer[available] = '-'
|
||||
}
|
||||
|
||||
/*
|
||||
If we overestimated the size, we need to move the buffer left.
|
||||
*/
|
||||
written = len(buffer) - available;
|
||||
written = len(buffer) - available
|
||||
if written < size {
|
||||
diff := size - written;
|
||||
mem.copy(&buffer[0], &buffer[diff], written);
|
||||
diff := size - written
|
||||
mem.copy(&buffer[0], &buffer[diff], written)
|
||||
}
|
||||
return written, nil;
|
||||
return written, nil
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -188,57 +188,57 @@ int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_ter
|
||||
*/
|
||||
if is_power_of_two(int(radix)) {
|
||||
if zero_terminate {
|
||||
available -= 1;
|
||||
buffer[available] = 0;
|
||||
available -= 1
|
||||
buffer[available] = 0
|
||||
}
|
||||
|
||||
shift, count: int;
|
||||
shift, count: int
|
||||
// mask := _WORD(radix - 1);
|
||||
shift, err = log(DIGIT(radix), 2);
|
||||
count, err = count_bits(a);
|
||||
digit: _WORD;
|
||||
shift, err = log(DIGIT(radix), 2)
|
||||
count, err = count_bits(a)
|
||||
digit: _WORD
|
||||
|
||||
for offset := 0; offset < count; offset += shift {
|
||||
bits_to_get := int(min(count - offset, shift));
|
||||
bits_to_get := int(min(count - offset, shift))
|
||||
|
||||
digit, err = int_bitfield_extract(a, offset, bits_to_get);
|
||||
digit, err = int_bitfield_extract(a, offset, bits_to_get)
|
||||
if err != nil {
|
||||
return len(buffer) - available, .Invalid_Argument;
|
||||
return len(buffer) - available, .Invalid_Argument
|
||||
}
|
||||
available -= 1;
|
||||
buffer[available] = RADIX_TABLE[digit];
|
||||
available -= 1
|
||||
buffer[available] = RADIX_TABLE[digit]
|
||||
}
|
||||
|
||||
if n, _ := is_neg(a); n {
|
||||
available -= 1;
|
||||
buffer[available] = '-';
|
||||
available -= 1
|
||||
buffer[available] = '-'
|
||||
}
|
||||
|
||||
/*
|
||||
If we overestimated the size, we need to move the buffer left.
|
||||
*/
|
||||
written = len(buffer) - available;
|
||||
written = len(buffer) - available
|
||||
if written < size {
|
||||
diff := size - written;
|
||||
mem.copy(&buffer[0], &buffer[diff], written);
|
||||
diff := size - written
|
||||
mem.copy(&buffer[0], &buffer[diff], written)
|
||||
}
|
||||
return written, nil;
|
||||
return written, nil
|
||||
}
|
||||
|
||||
return _itoa_raw_full(a, radix, buffer, zero_terminate);
|
||||
return _itoa_raw_full(a, radix, buffer, zero_terminate)
|
||||
}
|
||||
|
||||
itoa :: proc{int_itoa_string, int_itoa_raw};
|
||||
int_to_string :: int_itoa_string;
|
||||
int_to_cstring :: int_itoa_cstring;
|
||||
itoa :: proc{int_itoa_string, int_itoa_raw}
|
||||
int_to_string :: int_itoa_string
|
||||
int_to_cstring :: int_itoa_cstring
|
||||
|
||||
/*
|
||||
Read a string [ASCII] in a given radix.
|
||||
*/
|
||||
int_atoi :: proc(res: ^Int, input: string, radix := i8(10), allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(res);
|
||||
input := input;
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(res)
|
||||
input := input
|
||||
context.allocator = allocator
|
||||
|
||||
/*
|
||||
Make sure the radix is ok.
|
||||
@@ -249,92 +249,92 @@ int_atoi :: proc(res: ^Int, input: string, radix := i8(10), allocator := context
|
||||
/*
|
||||
Set the integer to the default of zero.
|
||||
*/
|
||||
internal_zero(res) or_return;
|
||||
internal_zero(res) or_return
|
||||
|
||||
/*
|
||||
We'll interpret an empty string as zero.
|
||||
*/
|
||||
if len(input) == 0 {
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
If the leading digit is a minus set the sign to negative.
|
||||
Given the above early out, the length should be at least 1.
|
||||
*/
|
||||
sign := Sign.Zero_or_Positive;
|
||||
sign := Sign.Zero_or_Positive
|
||||
if input[0] == '-' {
|
||||
input = input[1:];
|
||||
sign = .Negative;
|
||||
input = input[1:]
|
||||
sign = .Negative
|
||||
}
|
||||
|
||||
/*
|
||||
Process each digit of the string.
|
||||
*/
|
||||
ch: rune;
|
||||
ch: rune
|
||||
for len(input) > 0 {
|
||||
/* if the radix <= 36 the conversion is case insensitive
|
||||
* this allows numbers like 1AB and 1ab to represent the same value
|
||||
* [e.g. in hex]
|
||||
*/
|
||||
|
||||
ch = rune(input[0]);
|
||||
ch = rune(input[0])
|
||||
if radix <= 36 && ch >= 'a' && ch <= 'z' {
|
||||
ch -= 32; // 'a' - 'A'
|
||||
ch -= 32 // 'a' - 'A'
|
||||
}
|
||||
|
||||
pos := ch - '+';
|
||||
pos := ch - '+'
|
||||
if RADIX_TABLE_REVERSE_SIZE <= pos {
|
||||
break;
|
||||
break
|
||||
}
|
||||
y := RADIX_TABLE_REVERSE[pos];
|
||||
y := RADIX_TABLE_REVERSE[pos]
|
||||
/* if the char was found in the map
|
||||
* and is less than the given radix add it
|
||||
* to the number, otherwise exit the loop.
|
||||
*/
|
||||
if y >= u8(radix) {
|
||||
break;
|
||||
break
|
||||
}
|
||||
|
||||
internal_mul(res, res, DIGIT(radix)) or_return;
|
||||
internal_add(res, res, DIGIT(y)) or_return;
|
||||
internal_mul(res, res, DIGIT(radix)) or_return
|
||||
internal_add(res, res, DIGIT(y)) or_return
|
||||
|
||||
input = input[1:];
|
||||
input = input[1:]
|
||||
}
|
||||
/*
|
||||
If an illegal character was found, fail.
|
||||
*/
|
||||
if len(input) > 0 && ch != 0 && ch != '\r' && ch != '\n' {
|
||||
return .Invalid_Argument;
|
||||
return .Invalid_Argument
|
||||
}
|
||||
/*
|
||||
Set the sign only if res != 0.
|
||||
*/
|
||||
if res.used > 0 {
|
||||
res.sign = sign;
|
||||
res.sign = sign
|
||||
}
|
||||
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
atoi :: proc { int_atoi, };
|
||||
atoi :: proc { int_atoi, }
|
||||
|
||||
/*
|
||||
We size for `string` by default.
|
||||
*/
|
||||
radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false, allocator := context.allocator) -> (size: int, err: Error) {
|
||||
a := a;
|
||||
assert_if_nil(a);
|
||||
a := a
|
||||
assert_if_nil(a)
|
||||
|
||||
if radix < 2 || radix > 64 { return -1, .Invalid_Argument; }
|
||||
clear_if_uninitialized(a) or_return;
|
||||
clear_if_uninitialized(a) or_return
|
||||
|
||||
if internal_is_zero(a) {
|
||||
if zero_terminate {
|
||||
return 2, nil;
|
||||
return 2, nil
|
||||
}
|
||||
return 1, nil;
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
if internal_is_power_of_two(a) {
|
||||
@@ -345,37 +345,37 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false, allocator := con
|
||||
used = a.used,
|
||||
sign = .Zero_or_Positive,
|
||||
digit = a.digit,
|
||||
};
|
||||
}
|
||||
|
||||
size = internal_log(t, DIGIT(radix)) or_return;
|
||||
size = internal_log(t, DIGIT(radix)) or_return
|
||||
} else {
|
||||
la, k := &Int{}, &Int{};
|
||||
defer internal_destroy(la, k);
|
||||
la, k := &Int{}, &Int{}
|
||||
defer internal_destroy(la, k)
|
||||
|
||||
/* la = floor(log_2(a)) + 1 */
|
||||
bit_count := internal_count_bits(a);
|
||||
internal_set(la, bit_count) or_return;
|
||||
bit_count := internal_count_bits(a)
|
||||
internal_set(la, bit_count) or_return
|
||||
|
||||
/* k = floor(2^29/log_2(radix)) + 1 */
|
||||
lb := _log_bases;
|
||||
internal_set(k, lb[radix]) or_return;
|
||||
lb := _log_bases
|
||||
internal_set(k, lb[radix]) or_return
|
||||
|
||||
/* n = floor((la * k) / 2^29) + 1 */
|
||||
internal_mul(k, la, k) or_return;
|
||||
internal_shr(k, k, _RADIX_SIZE_SCALE) or_return;
|
||||
internal_mul(k, la, k) or_return
|
||||
internal_shr(k, k, _RADIX_SIZE_SCALE) or_return
|
||||
|
||||
/* The "+1" here is the "+1" in "floor((la * k) / 2^29) + 1" */
|
||||
/* n = n + 1 + EOS + sign */
|
||||
size_, _ := internal_get(k, u128);
|
||||
size = int(size_);
|
||||
size_, _ := internal_get(k, u128)
|
||||
size = int(size_)
|
||||
}
|
||||
|
||||
/*
|
||||
log truncates to zero, so we need to add one more, and one for `-` if negative.
|
||||
*/
|
||||
size += 2 if a.sign == .Negative else 1;
|
||||
size += 1 if zero_terminate else 0;
|
||||
return size, nil;
|
||||
size += 2 if a.sign == .Negative else 1
|
||||
size += 1 if zero_terminate else 0
|
||||
return size, nil
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -392,7 +392,7 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false, allocator := con
|
||||
for 64 bit "int".
|
||||
*/
|
||||
|
||||
_RADIX_SIZE_SCALE :: 29;
|
||||
_RADIX_SIZE_SCALE :: 29
|
||||
_log_bases :: [65]u32{
|
||||
0, 0, 0x20000001, 0x14309399, 0x10000001,
|
||||
0xdc81a35, 0xc611924, 0xb660c9e, 0xaaaaaab, 0xa1849cd,
|
||||
@@ -407,12 +407,12 @@ _log_bases :: [65]u32{
|
||||
0x5ab7d68, 0x5a42df0, 0x59d1506, 0x5962ffe, 0x58f7c57,
|
||||
0x588f7bc, 0x582a000, 0x57c7319, 0x5766f1d, 0x5709243,
|
||||
0x56adad9, 0x565474d, 0x55fd61f, 0x55a85e8, 0x5555556,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
Characters used in radix conversions.
|
||||
*/
|
||||
RADIX_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
|
||||
RADIX_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"
|
||||
RADIX_TABLE_REVERSE := [RADIX_TABLE_REVERSE_SIZE]u8{
|
||||
0x3e, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x01, 0x02, 0x03, 0x04, /* +,-./01234 */
|
||||
0x05, 0x06, 0x07, 0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, /* 56789:;<=> */
|
||||
@@ -422,59 +422,59 @@ RADIX_TABLE_REVERSE := [RADIX_TABLE_REVERSE_SIZE]u8{
|
||||
0xff, 0xff, 0xff, 0xff, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, /* ]^_`abcdef */
|
||||
0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, /* ghijklmnop */
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, /* qrstuvwxyz */
|
||||
};
|
||||
RADIX_TABLE_REVERSE_SIZE :: 80;
|
||||
}
|
||||
RADIX_TABLE_REVERSE_SIZE :: 80
|
||||
|
||||
/*
|
||||
Stores a bignum as a ASCII string in a given radix (2..64)
|
||||
The buffer must be appropriately sized. This routine doesn't check.
|
||||
*/
|
||||
_itoa_raw_full :: proc(a: ^Int, radix: i8, buffer: []u8, zero_terminate := false, allocator := context.allocator) -> (written: int, err: Error) {
|
||||
assert_if_nil(a);
|
||||
context.allocator = allocator;
|
||||
assert_if_nil(a)
|
||||
context.allocator = allocator
|
||||
|
||||
temp, denominator := &Int{}, &Int{};
|
||||
temp, denominator := &Int{}, &Int{}
|
||||
|
||||
internal_copy(temp, a) or_return;
|
||||
internal_set(denominator, radix) or_return;
|
||||
internal_copy(temp, a) or_return
|
||||
internal_set(denominator, radix) or_return
|
||||
|
||||
available := len(buffer);
|
||||
available := len(buffer)
|
||||
if zero_terminate {
|
||||
available -= 1;
|
||||
buffer[available] = 0;
|
||||
available -= 1
|
||||
buffer[available] = 0
|
||||
}
|
||||
|
||||
if a.sign == .Negative {
|
||||
temp.sign = .Zero_or_Positive;
|
||||
temp.sign = .Zero_or_Positive
|
||||
}
|
||||
|
||||
remainder: DIGIT;
|
||||
remainder: DIGIT
|
||||
for {
|
||||
if remainder, err = #force_inline internal_divmod(temp, temp, DIGIT(radix)); err != nil {
|
||||
internal_destroy(temp, denominator);
|
||||
return len(buffer) - available, err;
|
||||
internal_destroy(temp, denominator)
|
||||
return len(buffer) - available, err
|
||||
}
|
||||
available -= 1;
|
||||
buffer[available] = RADIX_TABLE[remainder];
|
||||
available -= 1
|
||||
buffer[available] = RADIX_TABLE[remainder]
|
||||
if temp.used == 0 {
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if a.sign == .Negative {
|
||||
available -= 1;
|
||||
buffer[available] = '-';
|
||||
available -= 1
|
||||
buffer[available] = '-'
|
||||
}
|
||||
|
||||
internal_destroy(temp, denominator);
|
||||
internal_destroy(temp, denominator)
|
||||
|
||||
/*
|
||||
If we overestimated the size, we need to move the buffer left.
|
||||
*/
|
||||
written = len(buffer) - available;
|
||||
written = len(buffer) - available
|
||||
if written < len(buffer) {
|
||||
diff := len(buffer) - written;
|
||||
mem.copy(&buffer[0], &buffer[diff], written);
|
||||
diff := len(buffer) - written
|
||||
mem.copy(&buffer[0], &buffer[diff], written)
|
||||
}
|
||||
return written, nil;
|
||||
return written, nil
|
||||
}
|
||||
+137
-137
@@ -25,24 +25,24 @@ PyRes :: struct {
|
||||
}
|
||||
|
||||
@export test_initialize_constants :: proc "c" () -> (res: u64) {
|
||||
context = runtime.default_context();
|
||||
res = u64(initialize_constants());
|
||||
context = runtime.default_context()
|
||||
res = u64(initialize_constants())
|
||||
//assert(MUL_KARATSUBA_CUTOFF >= 40);
|
||||
return res;
|
||||
return res
|
||||
}
|
||||
|
||||
@export test_error_string :: proc "c" (err: Error) -> (res: cstring) {
|
||||
context = runtime.default_context();
|
||||
es := Error_String;
|
||||
return strings.clone_to_cstring(es[err], context.temp_allocator);
|
||||
context = runtime.default_context()
|
||||
es := Error_String
|
||||
return strings.clone_to_cstring(es[err], context.temp_allocator)
|
||||
}
|
||||
|
||||
@export test_add :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
aa, bb, sum := &Int{}, &Int{}, &Int{};
|
||||
defer internal_destroy(aa, bb, sum);
|
||||
aa, bb, sum := &Int{}, &Int{}, &Int{}
|
||||
defer internal_destroy(aa, bb, sum)
|
||||
|
||||
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":add:atoi(a):", err=err}; }
|
||||
if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":add:atoi(b):", err=err}; }
|
||||
@@ -52,18 +52,18 @@ PyRes :: struct {
|
||||
if err = #force_inline internal_add(sum, aa, bb); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; }
|
||||
}
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(sum, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(sum, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":add:itoa(sum):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
@export test_sub :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
aa, bb, sum := &Int{}, &Int{}, &Int{};
|
||||
defer internal_destroy(aa, bb, sum);
|
||||
aa, bb, sum := &Int{}, &Int{}, &Int{}
|
||||
defer internal_destroy(aa, bb, sum)
|
||||
|
||||
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":sub:atoi(a):", err=err}; }
|
||||
if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":sub:atoi(b):", err=err}; }
|
||||
@@ -73,63 +73,63 @@ PyRes :: struct {
|
||||
if err = #force_inline internal_sub(sum, aa, bb); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; }
|
||||
}
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(sum, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(sum, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":sub:itoa(sum):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
@export test_mul :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
aa, bb, product := &Int{}, &Int{}, &Int{};
|
||||
defer internal_destroy(aa, bb, product);
|
||||
aa, bb, product := &Int{}, &Int{}, &Int{}
|
||||
defer internal_destroy(aa, bb, product)
|
||||
|
||||
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":mul:atoi(a):", err=err}; }
|
||||
if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":mul:atoi(b):", err=err}; }
|
||||
if err = #force_inline internal_mul(product, aa, bb); err != nil { return PyRes{res=":mul:mul(product,a,b):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(product, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(product, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":mul:itoa(product):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
@export test_sqr :: proc "c" (a: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
aa, square := &Int{}, &Int{};
|
||||
defer internal_destroy(aa, square);
|
||||
aa, square := &Int{}, &Int{}
|
||||
defer internal_destroy(aa, square)
|
||||
|
||||
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":sqr:atoi(a):", err=err}; }
|
||||
if err = #force_inline internal_sqr(square, aa); err != nil { return PyRes{res=":sqr:sqr(square,a):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(square, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(square, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":sqr:itoa(square):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
NOTE(Jeroen): For simplicity, we don't return the quotient and the remainder, just the quotient.
|
||||
*/
|
||||
@export test_div :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
aa, bb, quotient := &Int{}, &Int{}, &Int{};
|
||||
defer internal_destroy(aa, bb, quotient);
|
||||
aa, bb, quotient := &Int{}, &Int{}, &Int{}
|
||||
defer internal_destroy(aa, bb, quotient)
|
||||
|
||||
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":div:atoi(a):", err=err}; }
|
||||
if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":div:atoi(b):", err=err}; }
|
||||
if err = #force_inline internal_div(quotient, aa, bb); err != nil { return PyRes{res=":div:div(quotient,a,b):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(quotient, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(quotient, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":div:itoa(quotient):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,254 +137,254 @@ PyRes :: struct {
|
||||
res = log(a, base)
|
||||
*/
|
||||
@export test_log :: proc "c" (a: cstring, base := DIGIT(2)) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
l: int;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
l: int
|
||||
|
||||
aa := &Int{};
|
||||
defer internal_destroy(aa);
|
||||
aa := &Int{}
|
||||
defer internal_destroy(aa)
|
||||
|
||||
if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":log:atoi(a):", err=err}; }
|
||||
if l, err = #force_inline internal_log(aa, base); err != nil { return PyRes{res=":log:log(a, base):", err=err}; }
|
||||
|
||||
#force_inline internal_zero(aa);
|
||||
aa.digit[0] = DIGIT(l) & _MASK;
|
||||
aa.digit[1] = DIGIT(l) >> _DIGIT_BITS;
|
||||
aa.used = 2;
|
||||
clamp(aa);
|
||||
aa.digit[0] = DIGIT(l) & _MASK
|
||||
aa.digit[1] = DIGIT(l) >> _DIGIT_BITS
|
||||
aa.used = 2
|
||||
clamp(aa)
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(aa, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(aa, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":log:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = base^power
|
||||
*/
|
||||
@export test_pow :: proc "c" (base: cstring, power := int(2)) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
dest, bb := &Int{}, &Int{};
|
||||
defer internal_destroy(dest, bb);
|
||||
dest, bb := &Int{}, &Int{}
|
||||
defer internal_destroy(dest, bb)
|
||||
|
||||
if err = atoi(bb, string(base), 16); err != nil { return PyRes{res=":pow:atoi(base):", err=err}; }
|
||||
if err = #force_inline internal_pow(dest, bb, power); err != nil { return PyRes{res=":pow:pow(dest, base, power):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":log:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = sqrt(src)
|
||||
*/
|
||||
@export test_sqrt :: proc "c" (source: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
src := &Int{};
|
||||
defer internal_destroy(src);
|
||||
src := &Int{}
|
||||
defer internal_destroy(src)
|
||||
|
||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":sqrt:atoi(src):", err=err}; }
|
||||
if err = #force_inline internal_sqrt(src, src); err != nil { return PyRes{res=":sqrt:sqrt(src):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":log:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = root_n(src, power)
|
||||
*/
|
||||
@export test_root_n :: proc "c" (source: cstring, power: int) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
src := &Int{};
|
||||
defer internal_destroy(src);
|
||||
src := &Int{}
|
||||
defer internal_destroy(src)
|
||||
|
||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":root_n:atoi(src):", err=err}; }
|
||||
if err = #force_inline internal_root_n(src, src, power); err != nil { return PyRes{res=":root_n:root_n(src):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":root_n:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = shr_digit(src, digits)
|
||||
*/
|
||||
@export test_shr_digit :: proc "c" (source: cstring, digits: int) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
src := &Int{};
|
||||
defer internal_destroy(src);
|
||||
src := &Int{}
|
||||
defer internal_destroy(src)
|
||||
|
||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_digit:atoi(src):", err=err}; }
|
||||
if err = #force_inline internal_shr_digit(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":shr_digit:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = shl_digit(src, digits)
|
||||
*/
|
||||
@export test_shl_digit :: proc "c" (source: cstring, digits: int) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
src := &Int{};
|
||||
defer internal_destroy(src);
|
||||
src := &Int{}
|
||||
defer internal_destroy(src)
|
||||
|
||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl_digit:atoi(src):", err=err}; }
|
||||
if err = #force_inline internal_shl_digit(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":shl_digit:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = shr(src, bits)
|
||||
*/
|
||||
@export test_shr :: proc "c" (source: cstring, bits: int) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
src := &Int{};
|
||||
defer internal_destroy(src);
|
||||
src := &Int{}
|
||||
defer internal_destroy(src)
|
||||
|
||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr:atoi(src):", err=err}; }
|
||||
if err = #force_inline internal_shr(src, src, bits); err != nil { return PyRes{res=":shr:shr(src, bits):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":shr:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = shr_signed(src, bits)
|
||||
*/
|
||||
@export test_shr_signed :: proc "c" (source: cstring, bits: int) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
src := &Int{};
|
||||
defer internal_destroy(src);
|
||||
src := &Int{}
|
||||
defer internal_destroy(src)
|
||||
|
||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_signed:atoi(src):", err=err}; }
|
||||
if err = #force_inline internal_shr_signed(src, src, bits); err != nil { return PyRes{res=":shr_signed:shr_signed(src, bits):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":shr_signed:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = shl(src, bits)
|
||||
*/
|
||||
@export test_shl :: proc "c" (source: cstring, bits: int) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
src := &Int{};
|
||||
defer internal_destroy(src);
|
||||
src := &Int{}
|
||||
defer internal_destroy(src)
|
||||
|
||||
if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl:atoi(src):", err=err}; }
|
||||
if err = #force_inline internal_shl(src, src, bits); err != nil { return PyRes{res=":shl:shl(src, bits):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(src, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":shl:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = factorial(n)
|
||||
*/
|
||||
@export test_factorial :: proc "c" (n: int) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
dest := &Int{};
|
||||
defer internal_destroy(dest);
|
||||
dest := &Int{}
|
||||
defer internal_destroy(dest)
|
||||
|
||||
if err = #force_inline internal_int_factorial(dest, n); err != nil { return PyRes{res=":factorial:factorial(n):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":factorial:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = gcd(a, b)
|
||||
*/
|
||||
@export test_gcd :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
ai, bi, dest := &Int{}, &Int{}, &Int{};
|
||||
defer internal_destroy(ai, bi, dest);
|
||||
ai, bi, dest := &Int{}, &Int{}, &Int{}
|
||||
defer internal_destroy(ai, bi, dest)
|
||||
|
||||
if err = atoi(ai, string(a), 16); err != nil { return PyRes{res=":gcd:atoi(a):", err=err}; }
|
||||
if err = atoi(bi, string(b), 16); err != nil { return PyRes{res=":gcd:atoi(b):", err=err}; }
|
||||
if err = #force_inline internal_int_gcd_lcm(dest, nil, ai, bi); err != nil { return PyRes{res=":gcd:gcd(a, b):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":gcd:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = lcm(a, b)
|
||||
*/
|
||||
@export test_lcm :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
|
||||
ai, bi, dest := &Int{}, &Int{}, &Int{};
|
||||
defer internal_destroy(ai, bi, dest);
|
||||
ai, bi, dest := &Int{}, &Int{}, &Int{}
|
||||
defer internal_destroy(ai, bi, dest)
|
||||
|
||||
if err = atoi(ai, string(a), 16); err != nil { return PyRes{res=":lcm:atoi(a):", err=err}; }
|
||||
if err = atoi(bi, string(b), 16); err != nil { return PyRes{res=":lcm:atoi(b):", err=err}; }
|
||||
if err = #force_inline internal_int_gcd_lcm(nil, dest, ai, bi); err != nil { return PyRes{res=":lcm:lcm(a, b):", err=err}; }
|
||||
|
||||
r: cstring;
|
||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
|
||||
r: cstring
|
||||
r, err = int_itoa_cstring(dest, 16, context.temp_allocator)
|
||||
if err != nil { return PyRes{res=":lcm:itoa(res):", err=err}; }
|
||||
return PyRes{res = r, err = nil};
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = lcm(a, b)
|
||||
*/
|
||||
@export test_is_square :: proc "c" (a: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context();
|
||||
err: Error;
|
||||
square: bool;
|
||||
context = runtime.default_context()
|
||||
err: Error
|
||||
square: bool
|
||||
|
||||
ai := &Int{};
|
||||
defer internal_destroy(ai);
|
||||
ai := &Int{}
|
||||
defer internal_destroy(ai)
|
||||
|
||||
if err = atoi(ai, string(a), 16); err != nil { return PyRes{res=":is_square:atoi(a):", err=err}; }
|
||||
if square, err = #force_inline internal_int_is_square(ai); err != nil { return PyRes{res=":is_square:is_square(a):", err=err}; }
|
||||
|
||||
if square {
|
||||
return PyRes{"True", nil};
|
||||
return PyRes{"True", nil}
|
||||
}
|
||||
return PyRes{"False", nil};
|
||||
return PyRes{"False", nil}
|
||||
}
|
||||
+19
-19
@@ -24,58 +24,58 @@ Category :: enum {
|
||||
sqr,
|
||||
bitfield_extract,
|
||||
rm_trials,
|
||||
};
|
||||
}
|
||||
|
||||
Event :: struct {
|
||||
ticks: time.Duration,
|
||||
count: int,
|
||||
cycles: u64,
|
||||
}
|
||||
Timings := [Category]Event{};
|
||||
Timings := [Category]Event{}
|
||||
|
||||
print_timings :: proc() {
|
||||
duration :: proc(d: time.Duration) -> (res: string) {
|
||||
switch {
|
||||
case d < time.Microsecond:
|
||||
return fmt.tprintf("%v ns", time.duration_nanoseconds(d));
|
||||
return fmt.tprintf("%v ns", time.duration_nanoseconds(d))
|
||||
case d < time.Millisecond:
|
||||
return fmt.tprintf("%v µs", time.duration_microseconds(d));
|
||||
return fmt.tprintf("%v µs", time.duration_microseconds(d))
|
||||
case:
|
||||
return fmt.tprintf("%v ms", time.duration_milliseconds(d));
|
||||
return fmt.tprintf("%v ms", time.duration_milliseconds(d))
|
||||
}
|
||||
}
|
||||
|
||||
for v in Timings {
|
||||
if v.count > 0 {
|
||||
fmt.println("\nTimings:");
|
||||
break;
|
||||
fmt.println("\nTimings:")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for v, i in Timings {
|
||||
if v.count > 0 {
|
||||
avg_ticks := time.Duration(f64(v.ticks) / f64(v.count));
|
||||
avg_cycles := f64(v.cycles) / f64(v.count);
|
||||
avg_ticks := time.Duration(f64(v.ticks) / f64(v.count))
|
||||
avg_cycles := f64(v.cycles) / f64(v.count)
|
||||
|
||||
fmt.printf("\t%v: %s / %v cycles (avg), %s / %v cycles (total, %v calls)\n", i, duration(avg_ticks), avg_cycles, duration(v.ticks), v.cycles, v.count);
|
||||
fmt.printf("\t%v: %s / %v cycles (avg), %s / %v cycles (total, %v calls)\n", i, duration(avg_ticks), avg_cycles, duration(v.ticks), v.cycles, v.count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@(deferred_in_out=_SCOPE_END)
|
||||
SCOPED_TIMING :: #force_inline proc(c: Category) -> (ticks: time.Tick, cycles: u64) {
|
||||
cycles = time.read_cycle_counter();
|
||||
ticks = time.tick_now();
|
||||
return;
|
||||
cycles = time.read_cycle_counter()
|
||||
ticks = time.tick_now()
|
||||
return
|
||||
}
|
||||
_SCOPE_END :: #force_inline proc(c: Category, ticks: time.Tick, cycles: u64) {
|
||||
cycles_now := time.read_cycle_counter();
|
||||
ticks_now := time.tick_now();
|
||||
cycles_now := time.read_cycle_counter()
|
||||
ticks_now := time.tick_now()
|
||||
|
||||
Timings[c].ticks = time.tick_diff(ticks, ticks_now);
|
||||
Timings[c].cycles = cycles_now - cycles;
|
||||
Timings[c].count += 1;
|
||||
Timings[c].ticks = time.tick_diff(ticks, ticks_now)
|
||||
Timings[c].cycles = cycles_now - cycles
|
||||
Timings[c].count += 1
|
||||
}
|
||||
SCOPED_COUNT_ADD :: #force_inline proc(c: Category, count: int) {
|
||||
Timings[c].count += count;
|
||||
Timings[c].count += count
|
||||
}
|
||||
|
||||
+192
-192
@@ -2,66 +2,66 @@ package math_bits
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
U8_MIN :: 0;
|
||||
U16_MIN :: 0;
|
||||
U32_MIN :: 0;
|
||||
U64_MIN :: 0;
|
||||
U8_MIN :: 0
|
||||
U16_MIN :: 0
|
||||
U32_MIN :: 0
|
||||
U64_MIN :: 0
|
||||
|
||||
U8_MAX :: 1 << 8 - 1;
|
||||
U16_MAX :: 1 << 16 - 1;
|
||||
U32_MAX :: 1 << 32 - 1;
|
||||
U64_MAX :: 1 << 64 - 1;
|
||||
U8_MAX :: 1 << 8 - 1
|
||||
U16_MAX :: 1 << 16 - 1
|
||||
U32_MAX :: 1 << 32 - 1
|
||||
U64_MAX :: 1 << 64 - 1
|
||||
|
||||
I8_MIN :: - 1 << 7;
|
||||
I16_MIN :: - 1 << 15;
|
||||
I32_MIN :: - 1 << 31;
|
||||
I64_MIN :: - 1 << 63;
|
||||
I8_MIN :: - 1 << 7
|
||||
I16_MIN :: - 1 << 15
|
||||
I32_MIN :: - 1 << 31
|
||||
I64_MIN :: - 1 << 63
|
||||
|
||||
I8_MAX :: 1 << 7 - 1;
|
||||
I16_MAX :: 1 << 15 - 1;
|
||||
I32_MAX :: 1 << 31 - 1;
|
||||
I64_MAX :: 1 << 63 - 1;
|
||||
I8_MAX :: 1 << 7 - 1
|
||||
I16_MAX :: 1 << 15 - 1
|
||||
I32_MAX :: 1 << 31 - 1
|
||||
I64_MAX :: 1 << 63 - 1
|
||||
|
||||
|
||||
count_ones :: intrinsics.count_ones;
|
||||
count_zeros :: intrinsics.count_zeros;
|
||||
trailing_zeros :: intrinsics.count_trailing_zeros;
|
||||
leading_zeros :: intrinsics.count_leading_zeros;
|
||||
count_trailing_zeros :: intrinsics.count_trailing_zeros;
|
||||
count_leading_zeros :: intrinsics.count_leading_zeros;
|
||||
reverse_bits :: intrinsics.reverse_bits;
|
||||
byte_swap :: intrinsics.byte_swap;
|
||||
count_ones :: intrinsics.count_ones
|
||||
count_zeros :: intrinsics.count_zeros
|
||||
trailing_zeros :: intrinsics.count_trailing_zeros
|
||||
leading_zeros :: intrinsics.count_leading_zeros
|
||||
count_trailing_zeros :: intrinsics.count_trailing_zeros
|
||||
count_leading_zeros :: intrinsics.count_leading_zeros
|
||||
reverse_bits :: intrinsics.reverse_bits
|
||||
byte_swap :: intrinsics.byte_swap
|
||||
|
||||
overflowing_add :: intrinsics.overflow_add;
|
||||
overflowing_sub :: intrinsics.overflow_sub;
|
||||
overflowing_mul :: intrinsics.overflow_mul;
|
||||
overflowing_add :: intrinsics.overflow_add
|
||||
overflowing_sub :: intrinsics.overflow_sub
|
||||
overflowing_mul :: intrinsics.overflow_mul
|
||||
|
||||
|
||||
rotate_left8 :: proc(x: u8, k: int) -> u8 {
|
||||
n :: 8;
|
||||
s := uint(k) & (n-1);
|
||||
return x <<s | x>>(n-s);
|
||||
n :: 8
|
||||
s := uint(k) & (n-1)
|
||||
return x <<s | x>>(n-s)
|
||||
}
|
||||
rotate_left16 :: proc(x: u16, k: int) -> u16 {
|
||||
n :: 16;
|
||||
s := uint(k) & (n-1);
|
||||
return x <<s | x>>(n-s);
|
||||
n :: 16
|
||||
s := uint(k) & (n-1)
|
||||
return x <<s | x>>(n-s)
|
||||
}
|
||||
rotate_left32 :: proc(x: u32, k: int) -> u32 {
|
||||
n :: 32;
|
||||
s := uint(k) & (n-1);
|
||||
return x <<s | x>>(n-s);
|
||||
n :: 32
|
||||
s := uint(k) & (n-1)
|
||||
return x <<s | x>>(n-s)
|
||||
}
|
||||
rotate_left64 :: proc(x: u64, k: int) -> u64 {
|
||||
n :: 64;
|
||||
s := uint(k) & (n-1);
|
||||
return x <<s | x>>(n-s);
|
||||
n :: 64
|
||||
s := uint(k) & (n-1)
|
||||
return x <<s | x>>(n-s)
|
||||
}
|
||||
|
||||
rotate_left :: proc(x: uint, k: int) -> uint {
|
||||
n :: 8*size_of(uint);
|
||||
s := uint(k) & (n-1);
|
||||
return x <<s | x>>(n-s);
|
||||
n :: 8*size_of(uint)
|
||||
s := uint(k) & (n-1)
|
||||
return x <<s | x>>(n-s)
|
||||
}
|
||||
|
||||
from_be_u8 :: proc(i: u8) -> u8 { return i; }
|
||||
@@ -92,205 +92,205 @@ to_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; }
|
||||
|
||||
|
||||
len_u8 :: proc(x: u8) -> int {
|
||||
return int(len_u8_table[x]);
|
||||
return int(len_u8_table[x])
|
||||
}
|
||||
len_u16 :: proc(x: u16) -> (n: int) {
|
||||
x := x;
|
||||
x := x
|
||||
if x >= 1<<8 {
|
||||
x >>= 8;
|
||||
n = 8;
|
||||
x >>= 8
|
||||
n = 8
|
||||
}
|
||||
return n + int(len_u8_table[x]);
|
||||
return n + int(len_u8_table[x])
|
||||
}
|
||||
len_u32 :: proc(x: u32) -> (n: int) {
|
||||
x := x;
|
||||
x := x
|
||||
if x >= 1<<16 {
|
||||
x >>= 16;
|
||||
n = 16;
|
||||
x >>= 16
|
||||
n = 16
|
||||
}
|
||||
if x >= 1<<8 {
|
||||
x >>= 8;
|
||||
n += 8;
|
||||
x >>= 8
|
||||
n += 8
|
||||
}
|
||||
return n + int(len_u8_table[x]);
|
||||
return n + int(len_u8_table[x])
|
||||
}
|
||||
len_u64 :: proc(x: u64) -> (n: int) {
|
||||
x := x;
|
||||
x := x
|
||||
if x >= 1<<32 {
|
||||
x >>= 32;
|
||||
n = 32;
|
||||
x >>= 32
|
||||
n = 32
|
||||
}
|
||||
if x >= 1<<16 {
|
||||
x >>= 16;
|
||||
n += 16;
|
||||
x >>= 16
|
||||
n += 16
|
||||
}
|
||||
if x >= 1<<8 {
|
||||
x >>= 8;
|
||||
n += 8;
|
||||
x >>= 8
|
||||
n += 8
|
||||
}
|
||||
return n + int(len_u8_table[x]);
|
||||
return n + int(len_u8_table[x])
|
||||
}
|
||||
len_uint :: proc(x: uint) -> (n: int) {
|
||||
when size_of(uint) == size_of(u64) {
|
||||
return len_u64(u64(x));
|
||||
return len_u64(u64(x))
|
||||
} else {
|
||||
return len_u32(u32(x));
|
||||
return len_u32(u32(x))
|
||||
}
|
||||
}
|
||||
|
||||
// returns the minimum number of bits required to represent x
|
||||
len :: proc{len_u8, len_u16, len_u32, len_u64, len_uint};
|
||||
len :: proc{len_u8, len_u16, len_u32, len_u64, len_uint}
|
||||
|
||||
|
||||
add_u32 :: proc(x, y, carry: u32) -> (sum, carry_out: u32) {
|
||||
yc := y + carry;
|
||||
sum = x + yc;
|
||||
yc := y + carry
|
||||
sum = x + yc
|
||||
if sum < x || yc < y {
|
||||
carry_out = 1;
|
||||
carry_out = 1
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
add_u64 :: proc(x, y, carry: u64) -> (sum, carry_out: u64) {
|
||||
yc := y + carry;
|
||||
sum = x + yc;
|
||||
yc := y + carry
|
||||
sum = x + yc
|
||||
if sum < x || yc < y {
|
||||
carry_out = 1;
|
||||
carry_out = 1
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
add_uint :: proc(x, y, carry: uint) -> (sum, carry_out: uint) {
|
||||
yc := y + carry;
|
||||
sum = x + yc;
|
||||
yc := y + carry
|
||||
sum = x + yc
|
||||
if sum < x || yc < y {
|
||||
carry_out = 1;
|
||||
carry_out = 1
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
add :: proc{add_u32, add_u64, add_uint};
|
||||
add :: proc{add_u32, add_u64, add_uint}
|
||||
|
||||
|
||||
sub_u32 :: proc(x, y, borrow: u32) -> (diff, borrow_out: u32) {
|
||||
yb := y + borrow;
|
||||
diff = x - yb;
|
||||
yb := y + borrow
|
||||
diff = x - yb
|
||||
if diff > x || yb < y {
|
||||
borrow_out = 1;
|
||||
borrow_out = 1
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
sub_u64 :: proc(x, y, borrow: u64) -> (diff, borrow_out: u64) {
|
||||
yb := y + borrow;
|
||||
diff = x - yb;
|
||||
yb := y + borrow
|
||||
diff = x - yb
|
||||
if diff > x || yb < y {
|
||||
borrow_out = 1;
|
||||
borrow_out = 1
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
sub_uint :: proc(x, y, borrow: uint) -> (diff, borrow_out: uint) {
|
||||
yb := y + borrow;
|
||||
diff = x - yb;
|
||||
yb := y + borrow
|
||||
diff = x - yb
|
||||
if diff > x || yb < y {
|
||||
borrow_out = 1;
|
||||
borrow_out = 1
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
sub :: proc{sub_u32, sub_u64, sub_uint};
|
||||
sub :: proc{sub_u32, sub_u64, sub_uint}
|
||||
|
||||
|
||||
mul_u32 :: proc(x, y: u32) -> (hi, lo: u32) {
|
||||
z := u64(x) * u64(y);
|
||||
hi, lo = u32(z>>32), u32(z);
|
||||
return;
|
||||
z := u64(x) * u64(y)
|
||||
hi, lo = u32(z>>32), u32(z)
|
||||
return
|
||||
}
|
||||
mul_u64 :: proc(x, y: u64) -> (hi, lo: u64) {
|
||||
mask :: 1<<32 - 1;
|
||||
mask :: 1<<32 - 1
|
||||
|
||||
x0, x1 := x & mask, x >> 32;
|
||||
y0, y1 := y & mask, y >> 32;
|
||||
x0, x1 := x & mask, x >> 32
|
||||
y0, y1 := y & mask, y >> 32
|
||||
|
||||
w0 := x0 * y0;
|
||||
t := x1*y0 + w0>>32;
|
||||
w0 := x0 * y0
|
||||
t := x1*y0 + w0>>32
|
||||
|
||||
w1, w2 := t & mask, t >> 32;
|
||||
w1 += x0 * y1;
|
||||
hi = x1*y1 + w2 + w1>>32;
|
||||
lo = x * y;
|
||||
return;
|
||||
w1, w2 := t & mask, t >> 32
|
||||
w1 += x0 * y1
|
||||
hi = x1*y1 + w2 + w1>>32
|
||||
lo = x * y
|
||||
return
|
||||
}
|
||||
|
||||
mul_uint :: proc(x, y: uint) -> (hi, lo: uint) {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
a, b := mul_u32(u32(x), u32(y));
|
||||
a, b := mul_u32(u32(x), u32(y))
|
||||
} else {
|
||||
#assert(size_of(uint) == size_of(u64));
|
||||
a, b := mul_u64(u64(x), u64(y));
|
||||
a, b := mul_u64(u64(x), u64(y))
|
||||
}
|
||||
return uint(a), uint(b);
|
||||
return uint(a), uint(b)
|
||||
}
|
||||
|
||||
mul :: proc{mul_u32, mul_u64, mul_uint};
|
||||
mul :: proc{mul_u32, mul_u64, mul_uint}
|
||||
|
||||
|
||||
div_u32 :: proc(hi, lo, y: u32) -> (quo, rem: u32) {
|
||||
assert(y != 0 && y <= hi);
|
||||
z := u64(hi)<<32 | u64(lo);
|
||||
quo, rem = u32(z/u64(y)), u32(z%u64(y));
|
||||
return;
|
||||
assert(y != 0 && y <= hi)
|
||||
z := u64(hi)<<32 | u64(lo)
|
||||
quo, rem = u32(z/u64(y)), u32(z%u64(y))
|
||||
return
|
||||
}
|
||||
div_u64 :: proc(hi, lo, y: u64) -> (quo, rem: u64) {
|
||||
y := y;
|
||||
two32 :: 1 << 32;
|
||||
mask32 :: two32 - 1;
|
||||
y := y
|
||||
two32 :: 1 << 32
|
||||
mask32 :: two32 - 1
|
||||
if y == 0 {
|
||||
panic("divide error");
|
||||
panic("divide error")
|
||||
}
|
||||
if y <= hi {
|
||||
panic("overflow error");
|
||||
panic("overflow error")
|
||||
}
|
||||
|
||||
s := uint(count_leading_zeros(y));
|
||||
y <<= s;
|
||||
s := uint(count_leading_zeros(y))
|
||||
y <<= s
|
||||
|
||||
yn1 := y >> 32;
|
||||
yn0 := y & mask32;
|
||||
un32 := hi<<s | lo>>(64-s);
|
||||
un10 := lo << s;
|
||||
un1 := un10 >> 32;
|
||||
un0 := un10 & mask32;
|
||||
q1 := un32 / yn1;
|
||||
rhat := un32 - q1*yn1;
|
||||
yn1 := y >> 32
|
||||
yn0 := y & mask32
|
||||
un32 := hi<<s | lo>>(64-s)
|
||||
un10 := lo << s
|
||||
un1 := un10 >> 32
|
||||
un0 := un10 & mask32
|
||||
q1 := un32 / yn1
|
||||
rhat := un32 - q1*yn1
|
||||
|
||||
for q1 >= two32 || q1*yn0 > two32*rhat+un1 {
|
||||
q1 -= 1;
|
||||
rhat += yn1;
|
||||
q1 -= 1
|
||||
rhat += yn1
|
||||
if rhat >= two32 {
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
un21 := un32*two32 + un1 - q1*y;
|
||||
q0 := un21 / yn1;
|
||||
rhat = un21 - q0*yn1;
|
||||
un21 := un32*two32 + un1 - q1*y
|
||||
q0 := un21 / yn1
|
||||
rhat = un21 - q0*yn1
|
||||
|
||||
for q0 >= two32 || q0*yn0 > two32*rhat+un0 {
|
||||
q0 -= 1;
|
||||
rhat += yn1;
|
||||
q0 -= 1
|
||||
rhat += yn1
|
||||
if rhat >= two32 {
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return q1*two32 + q0, (un21*two32 + un0 - q0*y) >> s;
|
||||
return q1*two32 + q0, (un21*two32 + un0 - q0*y) >> s
|
||||
}
|
||||
div_uint :: proc(hi, lo, y: uint) -> (quo, rem: uint) {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
a, b := div_u32(u32(hi), u32(lo), u32(y));
|
||||
a, b := div_u32(u32(hi), u32(lo), u32(y))
|
||||
} else {
|
||||
#assert(size_of(uint) == size_of(u64));
|
||||
a, b := div_u64(u64(hi), u64(lo), u64(y));
|
||||
a, b := div_u64(u64(hi), u64(lo), u64(y))
|
||||
}
|
||||
return uint(a), uint(b);
|
||||
return uint(a), uint(b)
|
||||
}
|
||||
div :: proc{div_u32, div_u64, div_uint};
|
||||
div :: proc{div_u32, div_u64, div_uint}
|
||||
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ is_power_of_two :: proc{
|
||||
is_power_of_two_u32, is_power_of_two_i32,
|
||||
is_power_of_two_u64, is_power_of_two_i64,
|
||||
is_power_of_two_uint, is_power_of_two_int,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@private
|
||||
@@ -325,7 +325,7 @@ len_u8_table := [256]u8{
|
||||
32..<64 = 6,
|
||||
64..<128 = 7,
|
||||
128..<256 = 8,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
bitfield_extract_u8 :: proc(value: u8, offset, bits: uint) -> u8 { return (value >> offset) & u8(1<<bits - 1); }
|
||||
@@ -336,40 +336,40 @@ bitfield_extract_u128 :: proc(value: u128, offset, bits: uint) -> u128 { return
|
||||
bitfield_extract_uint :: proc(value: uint, offset, bits: uint) -> uint { return (value >> offset) & uint(1<<bits - 1); }
|
||||
|
||||
bitfield_extract_i8 :: proc(value: i8, offset, bits: uint) -> i8 {
|
||||
v := (u8(value) >> offset) & u8(1<<bits - 1);
|
||||
m := u8(1<<(bits-1));
|
||||
r := (v~m) - m;
|
||||
return i8(r);
|
||||
v := (u8(value) >> offset) & u8(1<<bits - 1)
|
||||
m := u8(1<<(bits-1))
|
||||
r := (v~m) - m
|
||||
return i8(r)
|
||||
}
|
||||
bitfield_extract_i16 :: proc(value: i16, offset, bits: uint) -> i16 {
|
||||
v := (u16(value) >> offset) & u16(1<<bits - 1);
|
||||
m := u16(1<<(bits-1));
|
||||
r := (v~m) - m;
|
||||
return i16(r);
|
||||
v := (u16(value) >> offset) & u16(1<<bits - 1)
|
||||
m := u16(1<<(bits-1))
|
||||
r := (v~m) - m
|
||||
return i16(r)
|
||||
}
|
||||
bitfield_extract_i32 :: proc(value: i32, offset, bits: uint) -> i32 {
|
||||
v := (u32(value) >> offset) & u32(1<<bits - 1);
|
||||
m := u32(1<<(bits-1));
|
||||
r := (v~m) - m;
|
||||
return i32(r);
|
||||
v := (u32(value) >> offset) & u32(1<<bits - 1)
|
||||
m := u32(1<<(bits-1))
|
||||
r := (v~m) - m
|
||||
return i32(r)
|
||||
}
|
||||
bitfield_extract_i64 :: proc(value: i64, offset, bits: uint) -> i64 {
|
||||
v := (u64(value) >> offset) & u64(1<<bits - 1);
|
||||
m := u64(1<<(bits-1));
|
||||
r := (v~m) - m;
|
||||
return i64(r);
|
||||
v := (u64(value) >> offset) & u64(1<<bits - 1)
|
||||
m := u64(1<<(bits-1))
|
||||
r := (v~m) - m
|
||||
return i64(r)
|
||||
}
|
||||
bitfield_extract_i128 :: proc(value: i128, offset, bits: uint) -> i128 {
|
||||
v := (u128(value) >> offset) & u128(1<<bits - 1);
|
||||
m := u128(1<<(bits-1));
|
||||
r := (v~m) - m;
|
||||
return i128(r);
|
||||
v := (u128(value) >> offset) & u128(1<<bits - 1)
|
||||
m := u128(1<<(bits-1))
|
||||
r := (v~m) - m
|
||||
return i128(r)
|
||||
}
|
||||
bitfield_extract_int :: proc(value: int, offset, bits: uint) -> int {
|
||||
v := (uint(value) >> offset) & uint(1<<bits - 1);
|
||||
m := uint(1<<(bits-1));
|
||||
r := (v~m) - m;
|
||||
return int(r);
|
||||
v := (uint(value) >> offset) & uint(1<<bits - 1)
|
||||
m := uint(1<<(bits-1))
|
||||
r := (v~m) - m
|
||||
return int(r)
|
||||
}
|
||||
|
||||
|
||||
@@ -386,57 +386,57 @@ bitfield_extract :: proc{
|
||||
bitfield_extract_i64,
|
||||
bitfield_extract_i128,
|
||||
bitfield_extract_int,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
bitfield_insert_u8 :: proc(base, insert: u8, offset, bits: uint) -> u8 {
|
||||
mask := u8(1<<bits - 1);
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset);
|
||||
mask := u8(1<<bits - 1)
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset)
|
||||
}
|
||||
bitfield_insert_u16 :: proc(base, insert: u16, offset, bits: uint) -> u16 {
|
||||
mask := u16(1<<bits - 1);
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset);
|
||||
mask := u16(1<<bits - 1)
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset)
|
||||
}
|
||||
bitfield_insert_u32 :: proc(base, insert: u32, offset, bits: uint) -> u32 {
|
||||
mask := u32(1<<bits - 1);
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset);
|
||||
mask := u32(1<<bits - 1)
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset)
|
||||
}
|
||||
bitfield_insert_u64 :: proc(base, insert: u64, offset, bits: uint) -> u64 {
|
||||
mask := u64(1<<bits - 1);
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset);
|
||||
mask := u64(1<<bits - 1)
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset)
|
||||
}
|
||||
bitfield_insert_u128 :: proc(base, insert: u128, offset, bits: uint) -> u128 {
|
||||
mask := u128(1<<bits - 1);
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset);
|
||||
mask := u128(1<<bits - 1)
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset)
|
||||
}
|
||||
bitfield_insert_uint :: proc(base, insert: uint, offset, bits: uint) -> uint {
|
||||
mask := uint(1<<bits - 1);
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset);
|
||||
mask := uint(1<<bits - 1)
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset)
|
||||
}
|
||||
|
||||
bitfield_insert_i8 :: proc(base, insert: i8, offset, bits: uint) -> i8 {
|
||||
mask := i8(1<<bits - 1);
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset);
|
||||
mask := i8(1<<bits - 1)
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset)
|
||||
}
|
||||
bitfield_insert_i16 :: proc(base, insert: i16, offset, bits: uint) -> i16 {
|
||||
mask := i16(1<<bits - 1);
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset);
|
||||
mask := i16(1<<bits - 1)
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset)
|
||||
}
|
||||
bitfield_insert_i32 :: proc(base, insert: i32, offset, bits: uint) -> i32 {
|
||||
mask := i32(1<<bits - 1);
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset);
|
||||
mask := i32(1<<bits - 1)
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset)
|
||||
}
|
||||
bitfield_insert_i64 :: proc(base, insert: i64, offset, bits: uint) -> i64 {
|
||||
mask := i64(1<<bits - 1);
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset);
|
||||
mask := i64(1<<bits - 1)
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset)
|
||||
}
|
||||
bitfield_insert_i128 :: proc(base, insert: i128, offset, bits: uint) -> i128 {
|
||||
mask := i128(1<<bits - 1);
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset);
|
||||
mask := i128(1<<bits - 1)
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset)
|
||||
}
|
||||
bitfield_insert_int :: proc(base, insert: int, offset, bits: uint) -> int {
|
||||
mask := int(1<<bits - 1);
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset);
|
||||
mask := int(1<<bits - 1)
|
||||
return (base &~ (mask<<offset)) | ((insert&mask) << offset)
|
||||
}
|
||||
|
||||
bitfield_insert :: proc{
|
||||
@@ -452,4 +452,4 @@ bitfield_insert :: proc{
|
||||
bitfield_insert_i64,
|
||||
bitfield_insert_i128,
|
||||
bitfield_insert_int,
|
||||
};
|
||||
}
|
||||
|
||||
+60
-60
@@ -4,7 +4,7 @@ import "core:math"
|
||||
import "core:strconv"
|
||||
|
||||
import "core:intrinsics"
|
||||
_ :: intrinsics;
|
||||
_ :: intrinsics
|
||||
|
||||
Fixed :: struct($Backing: typeid, $Fraction_Width: uint)
|
||||
where
|
||||
@@ -14,120 +14,120 @@ Fixed :: struct($Backing: typeid, $Fraction_Width: uint)
|
||||
i: Backing,
|
||||
}
|
||||
|
||||
Fixed4_4 :: distinct Fixed(i8, 4);
|
||||
Fixed5_3 :: distinct Fixed(i8, 3);
|
||||
Fixed6_2 :: distinct Fixed(i8, 2);
|
||||
Fixed7_1 :: distinct Fixed(i8, 1);
|
||||
Fixed4_4 :: distinct Fixed(i8, 4)
|
||||
Fixed5_3 :: distinct Fixed(i8, 3)
|
||||
Fixed6_2 :: distinct Fixed(i8, 2)
|
||||
Fixed7_1 :: distinct Fixed(i8, 1)
|
||||
|
||||
Fixed8_8 :: distinct Fixed(i16, 8);
|
||||
Fixed13_3 :: distinct Fixed(i16, 3);
|
||||
Fixed8_8 :: distinct Fixed(i16, 8)
|
||||
Fixed13_3 :: distinct Fixed(i16, 3)
|
||||
|
||||
Fixed16_16 :: distinct Fixed(i32, 16);
|
||||
Fixed26_6 :: distinct Fixed(i32, 6);
|
||||
Fixed16_16 :: distinct Fixed(i32, 16)
|
||||
Fixed26_6 :: distinct Fixed(i32, 6)
|
||||
|
||||
Fixed32_32 :: distinct Fixed(i64, 32);
|
||||
Fixed52_12 :: distinct Fixed(i64, 12);
|
||||
Fixed32_32 :: distinct Fixed(i64, 32)
|
||||
Fixed52_12 :: distinct Fixed(i64, 12)
|
||||
|
||||
|
||||
init_from_f64 :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), val: f64) {
|
||||
i, f := math.modf(val);
|
||||
x.i = Backing(f * (1<<Fraction_Width));
|
||||
x.i &= 1<<Fraction_Width - 1;
|
||||
x.i |= Backing(i) << Fraction_Width;
|
||||
i, f := math.modf(val)
|
||||
x.i = Backing(f * (1<<Fraction_Width))
|
||||
x.i &= 1<<Fraction_Width - 1
|
||||
x.i |= Backing(i) << Fraction_Width
|
||||
}
|
||||
|
||||
|
||||
init_from_parts :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), integer, fraction: Backing) {
|
||||
i, f := math.modf(val);
|
||||
x.i = fraction;
|
||||
x.i &= 1<<Fraction_Width - 1;
|
||||
x.i |= integer;
|
||||
i, f := math.modf(val)
|
||||
x.i = fraction
|
||||
x.i &= 1<<Fraction_Width - 1
|
||||
x.i |= integer
|
||||
}
|
||||
|
||||
to_f64 :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> f64 {
|
||||
res := f64(x.i >> Fraction_Width);
|
||||
res += f64(x.i & (1<<Fraction_Width-1)) / f64(1<<Fraction_Width);
|
||||
return res;
|
||||
res := f64(x.i >> Fraction_Width)
|
||||
res += f64(x.i & (1<<Fraction_Width-1)) / f64(1<<Fraction_Width)
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
add :: proc(x, y: $T/Fixed) -> T {
|
||||
return {x.i + y.i};
|
||||
return {x.i + y.i}
|
||||
}
|
||||
sub :: proc(x, y: $T/Fixed) -> T {
|
||||
return {x.i - y.i};
|
||||
return {x.i - y.i}
|
||||
}
|
||||
|
||||
mul :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
|
||||
z.i = intrinsics.fixed_point_mul(x.i, y.i, Fraction_Width);
|
||||
return;
|
||||
z.i = intrinsics.fixed_point_mul(x.i, y.i, Fraction_Width)
|
||||
return
|
||||
}
|
||||
mul_sat :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
|
||||
z.i = intrinsics.fixed_point_mul_sat(x.i, y.i, Fraction_Width);
|
||||
return;
|
||||
z.i = intrinsics.fixed_point_mul_sat(x.i, y.i, Fraction_Width)
|
||||
return
|
||||
}
|
||||
|
||||
div :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
|
||||
z.i = intrinsics.fixed_point_div(x.i, y.i, Fraction_Width);
|
||||
return;
|
||||
z.i = intrinsics.fixed_point_div(x.i, y.i, Fraction_Width)
|
||||
return
|
||||
}
|
||||
div_sat :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
|
||||
z.i = intrinsics.fixed_point_div_sat(x.i, y.i, Fraction_Width);
|
||||
return;
|
||||
z.i = intrinsics.fixed_point_div_sat(x.i, y.i, Fraction_Width)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
floor :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
|
||||
return x.i >> Fraction_Width;
|
||||
return x.i >> Fraction_Width
|
||||
}
|
||||
ceil :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
|
||||
Integer :: 8*size_of(Backing) - Fraction_Width;
|
||||
return (x.i + (1 << Integer-1)) >> Fraction_Width;
|
||||
Integer :: 8*size_of(Backing) - Fraction_Width
|
||||
return (x.i + (1 << Integer-1)) >> Fraction_Width
|
||||
}
|
||||
round :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
|
||||
Integer :: 8*size_of(Backing) - Fraction_Width;
|
||||
return (x.i + (1 << (Integer - 1))) >> Fraction_Width;
|
||||
Integer :: 8*size_of(Backing) - Fraction_Width
|
||||
return (x.i + (1 << (Integer - 1))) >> Fraction_Width
|
||||
}
|
||||
|
||||
|
||||
|
||||
append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
|
||||
x := x;
|
||||
buf: [48]byte;
|
||||
i := 0;
|
||||
x := x
|
||||
buf: [48]byte
|
||||
i := 0
|
||||
if x.i < 0 {
|
||||
buf[i] = '-';
|
||||
i += 1;
|
||||
x.i = -x.i;
|
||||
buf[i] = '-'
|
||||
i += 1
|
||||
x.i = -x.i
|
||||
}
|
||||
|
||||
integer := x.i >> Fraction_Width;
|
||||
fraction := x.i & (1<<Fraction_Width - 1);
|
||||
integer := x.i >> Fraction_Width
|
||||
fraction := x.i & (1<<Fraction_Width - 1)
|
||||
|
||||
s := strconv.append_uint(buf[i:], u64(integer), 10);
|
||||
i += len(s);
|
||||
s := strconv.append_uint(buf[i:], u64(integer), 10)
|
||||
i += len(s)
|
||||
if fraction != 0 {
|
||||
buf[i] = '.';
|
||||
i += 1;
|
||||
buf[i] = '.'
|
||||
i += 1
|
||||
for fraction > 0 {
|
||||
fraction *= 10;
|
||||
buf[i] = byte('0' + (fraction>>Fraction_Width));
|
||||
i += 1;
|
||||
fraction &= 1<<Fraction_Width - 1;
|
||||
fraction *= 10
|
||||
buf[i] = byte('0' + (fraction>>Fraction_Width))
|
||||
i += 1
|
||||
fraction &= 1<<Fraction_Width - 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
n := copy(dst, buf[:i]);
|
||||
return string(dst[:i]);
|
||||
n := copy(dst, buf[:i])
|
||||
return string(dst[:i])
|
||||
}
|
||||
|
||||
|
||||
to_string :: proc(x: $T/Fixed($Backing, $Fraction_Width), allocator := context.allocator) -> string {
|
||||
buf: [48]byte;
|
||||
s := append(buf[:], x);
|
||||
str := make([]byte, len(s), allocator);
|
||||
copy(str, s);
|
||||
return string(str);
|
||||
buf: [48]byte
|
||||
s := append(buf[:], x)
|
||||
str := make([]byte, len(s), allocator)
|
||||
copy(str, s)
|
||||
return string(str)
|
||||
}
|
||||
|
||||
+164
-164
@@ -6,476 +6,476 @@ import "core:math"
|
||||
radians :: proc(degrees: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = degrees * RAD_PER_DEG;
|
||||
out[i] = degrees * RAD_PER_DEG
|
||||
}
|
||||
} else {
|
||||
out = degrees * RAD_PER_DEG;
|
||||
out = degrees * RAD_PER_DEG
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
degrees :: proc(radians: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = radians * DEG_PER_RAD;
|
||||
out[i] = radians * DEG_PER_RAD
|
||||
}
|
||||
} else {
|
||||
out = radians * DEG_PER_RAD;
|
||||
out = radians * DEG_PER_RAD
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
min_double :: proc(a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = builtin.min(a[i], b[i]);
|
||||
out[i] = builtin.min(a[i], b[i])
|
||||
}
|
||||
} else {
|
||||
out = builtin.min(a, b);
|
||||
out = builtin.min(a, b)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
min_single :: proc(a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
N :: len(T);
|
||||
N :: len(T)
|
||||
|
||||
when N == 1 {
|
||||
out = a[0];
|
||||
out = a[0]
|
||||
} else when N == 2 {
|
||||
out = builtin.min(a[0], a[1]);
|
||||
out = builtin.min(a[0], a[1])
|
||||
} else {
|
||||
out = builtin.min(a[0], a[1]);
|
||||
out = builtin.min(a[0], a[1])
|
||||
for i in 2..<N {
|
||||
out = builtin.min(out, a[i]);
|
||||
out = builtin.min(out, a[i])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out = a;
|
||||
out = a
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
min_triple :: proc(a, b, c: $T) -> T where IS_NUMERIC(ELEM_TYPE(T)) {
|
||||
return min_double(a, min_double(b, c));
|
||||
return min_double(a, min_double(b, c))
|
||||
}
|
||||
|
||||
min :: proc{min_single, min_double, min_triple};
|
||||
min :: proc{min_single, min_double, min_triple}
|
||||
|
||||
max_double :: proc(a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = builtin.max(a[i], b[i]);
|
||||
out[i] = builtin.max(a[i], b[i])
|
||||
}
|
||||
} else {
|
||||
out = builtin.max(a, b);
|
||||
out = builtin.max(a, b)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
max_single :: proc(a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
N :: len(T);
|
||||
N :: len(T)
|
||||
|
||||
when N == 1 {
|
||||
out = a[0];
|
||||
out = a[0]
|
||||
} else when N == 2 {
|
||||
out = builtin.max(a[0], a[1]);
|
||||
out = builtin.max(a[0], a[1])
|
||||
} else when N == 3 {
|
||||
out = builtin.max(a[0], a[1], a[3]);
|
||||
out = builtin.max(a[0], a[1], a[3])
|
||||
}else {
|
||||
out = builtin.max(a[0], a[1]);
|
||||
out = builtin.max(a[0], a[1])
|
||||
for i in 2..<N {
|
||||
out = builtin.max(out, a[i]);
|
||||
out = builtin.max(out, a[i])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out = a;
|
||||
out = a
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
max_triple :: proc(a, b, c: $T) -> T where IS_NUMERIC(ELEM_TYPE(T)) {
|
||||
return max_double(a, max_double(b, c));
|
||||
return max_double(a, max_double(b, c))
|
||||
}
|
||||
|
||||
max :: proc{max_single, max_double, max_triple};
|
||||
max :: proc{max_single, max_double, max_triple}
|
||||
|
||||
abs :: proc(a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = builtin.abs(a[i]);
|
||||
out[i] = builtin.abs(a[i])
|
||||
}
|
||||
} else {
|
||||
out = builtin.abs(a);
|
||||
out = builtin.abs(a)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
sign :: proc(a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = #force_inline math.sign(a[i]);
|
||||
out[i] = #force_inline math.sign(a[i])
|
||||
}
|
||||
} else {
|
||||
out = #force_inline math.sign(a);
|
||||
out = #force_inline math.sign(a)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
clamp :: proc(x, a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = builtin.clamp(x[i], a[i], b[i]);
|
||||
out[i] = builtin.clamp(x[i], a[i], b[i])
|
||||
}
|
||||
} else {
|
||||
out = builtin.clamp(x, a, b);
|
||||
out = builtin.clamp(x, a, b)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
saturate :: proc(x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
return clamp(x, 0.0, 1.0);
|
||||
return clamp(x, 0.0, 1.0)
|
||||
}
|
||||
|
||||
lerp :: proc(a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = a[i]*(1-t[i]) + b[i]*t[i];
|
||||
out[i] = a[i]*(1-t[i]) + b[i]*t[i]
|
||||
}
|
||||
} else {
|
||||
out = a * (1.0 - t) + b * t;
|
||||
out = a * (1.0 - t) + b * t
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
mix :: proc(a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = a[i]*(1-t[i]) + b[i]*t[i];
|
||||
out[i] = a[i]*(1-t[i]) + b[i]*t[i]
|
||||
}
|
||||
} else {
|
||||
out = a * (1.0 - t) + b * t;
|
||||
out = a * (1.0 - t) + b * t
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
unlerp :: proc(a, b, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
return (x - a) / (b - a);
|
||||
return (x - a) / (b - a)
|
||||
}
|
||||
|
||||
step :: proc(e, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = x[i] < e[i] ? 0.0 : 1.0;
|
||||
out[i] = x[i] < e[i] ? 0.0 : 1.0
|
||||
}
|
||||
} else {
|
||||
out = x < e ? 0.0 : 1.0;
|
||||
out = x < e ? 0.0 : 1.0
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
smoothstep :: proc(e0, e1, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
t := saturate(unlerp(e0, e1, x));
|
||||
return t * t * (3.0 - 2.0 * t);
|
||||
t := saturate(unlerp(e0, e1, x))
|
||||
return t * t * (3.0 - 2.0 * t)
|
||||
}
|
||||
|
||||
smootherstep :: proc(e0, e1, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
t := saturate(unlerp(e0, e1, x));
|
||||
return t * t * t * (t * (6*t - 15) + 10);
|
||||
t := saturate(unlerp(e0, e1, x))
|
||||
return t * t * t * (t * (6*t - 15) + 10)
|
||||
}
|
||||
|
||||
|
||||
sqrt :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = math.sqrt(x[i]);
|
||||
out[i] = math.sqrt(x[i])
|
||||
}
|
||||
} else {
|
||||
out = math.sqrt(x);
|
||||
out = math.sqrt(x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
inverse_sqrt :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = 1.0/math.sqrt(x[i]);
|
||||
out[i] = 1.0/math.sqrt(x[i])
|
||||
}
|
||||
} else {
|
||||
out = 1.0/math.sqrt(x);
|
||||
out = 1.0/math.sqrt(x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
cos :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = math.cos(x[i]);
|
||||
out[i] = math.cos(x[i])
|
||||
}
|
||||
} else {
|
||||
out = math.cos(x);
|
||||
out = math.cos(x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
sin :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = math.sin(x[i]);
|
||||
out[i] = math.sin(x[i])
|
||||
}
|
||||
} else {
|
||||
out = math.sin(x);
|
||||
out = math.sin(x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
tan :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = math.tan(x[i]);
|
||||
out[i] = math.tan(x[i])
|
||||
}
|
||||
} else {
|
||||
out = math.tan(x);
|
||||
out = math.tan(x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
acos :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = math.acos(x[i]);
|
||||
out[i] = math.acos(x[i])
|
||||
}
|
||||
} else {
|
||||
out = math.acos(x);
|
||||
out = math.acos(x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
asin :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = math.asin(x[i]);
|
||||
out[i] = math.asin(x[i])
|
||||
}
|
||||
} else {
|
||||
out = math.asin(x);
|
||||
out = math.asin(x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
atan :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = math.atan(x[i]);
|
||||
out[i] = math.atan(x[i])
|
||||
}
|
||||
} else {
|
||||
out = math.atan(x);
|
||||
out = math.atan(x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
atan2 :: proc(y, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = math.atan2(y[i], x[i]);
|
||||
out[i] = math.atan2(y[i], x[i])
|
||||
}
|
||||
} else {
|
||||
out = math.atan2(y, x);
|
||||
out = math.atan2(y, x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
ln :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = math.ln(x[i]);
|
||||
out[i] = math.ln(x[i])
|
||||
}
|
||||
} else {
|
||||
out = math.ln(x);
|
||||
out = math.ln(x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
log2 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = INVLN2 * math.ln(x[i]);
|
||||
out[i] = INVLN2 * math.ln(x[i])
|
||||
}
|
||||
} else {
|
||||
out = INVLN2 * math.ln(x);
|
||||
out = INVLN2 * math.ln(x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
log10 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = INVLN10 * math.ln(x[i]);
|
||||
out[i] = INVLN10 * math.ln(x[i])
|
||||
}
|
||||
} else {
|
||||
out = INVLN10 * math.ln(x);
|
||||
out = INVLN10 * math.ln(x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
log :: proc(x, b: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = math.ln(x[i]) / math.ln(cast(ELEM_TYPE(T))b[i]);
|
||||
out[i] = math.ln(x[i]) / math.ln(cast(ELEM_TYPE(T))b[i])
|
||||
}
|
||||
} else {
|
||||
out = INVLN10 * math.ln(x) / math.ln(cast(ELEM_TYPE(T))b);
|
||||
out = INVLN10 * math.ln(x) / math.ln(cast(ELEM_TYPE(T))b)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
exp :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = math.exp(x[i]);
|
||||
out[i] = math.exp(x[i])
|
||||
}
|
||||
} else {
|
||||
out = math.exp(x);
|
||||
out = math.exp(x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
exp2 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = math.exp(LN2 * x[i]);
|
||||
out[i] = math.exp(LN2 * x[i])
|
||||
}
|
||||
} else {
|
||||
out = math.exp(LN2 * x);
|
||||
out = math.exp(LN2 * x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
exp10 :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = math.exp(LN10 * x[i]);
|
||||
out[i] = math.exp(LN10 * x[i])
|
||||
}
|
||||
} else {
|
||||
out = math.exp(LN10 * x);
|
||||
out = math.exp(LN10 * x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
pow :: proc(x, e: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = math.pow(x[i], e[i]);
|
||||
out[i] = math.pow(x[i], e[i])
|
||||
}
|
||||
} else {
|
||||
out = math.pow(x, e);
|
||||
out = math.pow(x, e)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
ceil :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = #force_inline math.ceil(x[i]);
|
||||
out[i] = #force_inline math.ceil(x[i])
|
||||
}
|
||||
} else {
|
||||
out = #force_inline math.ceil(x);
|
||||
out = #force_inline math.ceil(x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
floor :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = #force_inline math.floor(x[i]);
|
||||
out[i] = #force_inline math.floor(x[i])
|
||||
}
|
||||
} else {
|
||||
out = #force_inline math.floor(x);
|
||||
out = #force_inline math.floor(x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
round :: proc(x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
when IS_ARRAY(T) {
|
||||
for i in 0..<len(T) {
|
||||
out[i] = #force_inline math.round(x[i]);
|
||||
out[i] = #force_inline math.round(x[i])
|
||||
}
|
||||
} else {
|
||||
out = #force_inline math.round(x);
|
||||
out = #force_inline math.round(x)
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
fract :: proc(x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
f := #force_inline floor(x);
|
||||
return x - f;
|
||||
f := #force_inline floor(x)
|
||||
return x - f
|
||||
}
|
||||
|
||||
mod :: proc(x, m: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
|
||||
f := #force_inline floor(x / m);
|
||||
return x - f * m;
|
||||
f := #force_inline floor(x / m)
|
||||
return x - f * m
|
||||
}
|
||||
|
||||
|
||||
face_forward :: proc(N, I, N_ref: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) {
|
||||
return dot(N_ref, I) < 0 ? N : -N;
|
||||
return dot(N_ref, I) < 0 ? N : -N
|
||||
}
|
||||
|
||||
distance :: proc(p0, p1: $V/[$N]$E) -> E where IS_NUMERIC(E) {
|
||||
return length(p1 - p0);
|
||||
return length(p1 - p0)
|
||||
}
|
||||
|
||||
reflect :: proc(I, N: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) {
|
||||
b := n * (2 * dot(n, i));
|
||||
return i - b;
|
||||
b := n * (2 * dot(n, i))
|
||||
return i - b
|
||||
}
|
||||
refract :: proc(I, N: $T) -> (out: T) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) {
|
||||
dv := dot(n, i);
|
||||
k := 1 - eta*eta - (1 - dv*dv);
|
||||
a := i * eta;
|
||||
b := n * eta*dv*math.sqrt(k);
|
||||
return (a - b) * E(int(k >= 0));
|
||||
dv := dot(n, i)
|
||||
k := 1 - eta*eta - (1 - dv*dv)
|
||||
a := i * eta
|
||||
b := n * eta*dv*math.sqrt(k)
|
||||
return (a - b) * E(int(k >= 0))
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
is_nan_single :: proc(x: $T) -> bool where IS_FLOAT(T) {
|
||||
return #force_inline math.is_nan(x);
|
||||
return #force_inline math.is_nan(x)
|
||||
}
|
||||
|
||||
is_nan_array :: proc(x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) {
|
||||
for i in 0..<N {
|
||||
out[i] = #force_inline is_nan(x[i]);
|
||||
out[i] = #force_inline is_nan(x[i])
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
is_inf_single :: proc(x: $T) -> bool where IS_FLOAT(T) {
|
||||
return #force_inline math.is_inf(x);
|
||||
return #force_inline math.is_inf(x)
|
||||
}
|
||||
|
||||
is_inf_array :: proc(x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) {
|
||||
for i in 0..<N {
|
||||
out[i] = #force_inline is_inf(x[i]);
|
||||
out[i] = #force_inline is_inf(x[i])
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
classify_single :: proc(x: $T) -> math.Float_Class where IS_FLOAT(T) {
|
||||
return #force_inline math.classify(x);
|
||||
return #force_inline math.classify(x)
|
||||
}
|
||||
|
||||
classify_array :: proc(x: $A/[$N]$T) -> (out: [N]math.Float_Class) where IS_FLOAT(T) {
|
||||
for i in 0..<N {
|
||||
out[i] = #force_inline classify_single(x[i]);
|
||||
out[i] = #force_inline classify_single(x[i])
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
is_nan :: proc{is_nan_single, is_nan_array};
|
||||
is_inf :: proc{is_inf_single, is_inf_array};
|
||||
classify :: proc{classify_single, classify_array};
|
||||
is_nan :: proc{is_nan_single, is_nan_array}
|
||||
is_inf :: proc{is_inf_single, is_inf_array}
|
||||
classify :: proc{classify_single, classify_array}
|
||||
|
||||
|
||||
less_than_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x < y; }
|
||||
@@ -487,67 +487,67 @@ not_equal_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), I
|
||||
|
||||
less_than_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
|
||||
for i in 0..<N {
|
||||
out[i] = x[i] < y[i];
|
||||
out[i] = x[i] < y[i]
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
less_than_equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
|
||||
for i in 0..<N {
|
||||
out[i] = x[i] <= y[i];
|
||||
out[i] = x[i] <= y[i]
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
greater_than_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
|
||||
for i in 0..<N {
|
||||
out[i] = x[i] > y[i];
|
||||
out[i] = x[i] > y[i]
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
greater_than_equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
|
||||
for i in 0..<N {
|
||||
out[i] = x[i] >= y[i];
|
||||
out[i] = x[i] >= y[i]
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
|
||||
for i in 0..<N {
|
||||
out[i] = x[i] == y[i];
|
||||
out[i] = x[i] == y[i]
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
not_equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
|
||||
for i in 0..<N {
|
||||
out[i] = x[i] != y[i];
|
||||
out[i] = x[i] != y[i]
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
less_than :: proc{less_than_single, less_than_array};
|
||||
less_than_equal :: proc{less_than_equal_single, less_than_equal_array};
|
||||
greater_than :: proc{greater_than_single, greater_than_array};
|
||||
greater_than_equal :: proc{greater_than_equal_single, greater_than_equal_array};
|
||||
equal :: proc{equal_single, equal_array};
|
||||
not_equal :: proc{not_equal_single, not_equal_array};
|
||||
less_than :: proc{less_than_single, less_than_array}
|
||||
less_than_equal :: proc{less_than_equal_single, less_than_equal_array}
|
||||
greater_than :: proc{greater_than_single, greater_than_array}
|
||||
greater_than_equal :: proc{greater_than_equal_single, greater_than_equal_array}
|
||||
equal :: proc{equal_single, equal_array}
|
||||
not_equal :: proc{not_equal_single, not_equal_array}
|
||||
|
||||
any :: proc(x: $A/[$N]bool) -> (out: bool) {
|
||||
for e in x {
|
||||
if x {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
all :: proc(x: $A/[$N]bool) -> (out: bool) {
|
||||
for e in x {
|
||||
if !e {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
not :: proc(x: $A/[$N]bool) -> (out: A) {
|
||||
for e, i in x {
|
||||
out[i] = !e;
|
||||
out[i] = !e
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
+122
-122
@@ -5,178 +5,178 @@ import "core:intrinsics"
|
||||
|
||||
// Generic
|
||||
|
||||
TAU :: 6.28318530717958647692528676655900576;
|
||||
PI :: 3.14159265358979323846264338327950288;
|
||||
TAU :: 6.28318530717958647692528676655900576
|
||||
PI :: 3.14159265358979323846264338327950288
|
||||
|
||||
E :: 2.71828182845904523536;
|
||||
E :: 2.71828182845904523536
|
||||
|
||||
τ :: TAU;
|
||||
π :: PI;
|
||||
e :: E;
|
||||
τ :: TAU
|
||||
π :: PI
|
||||
e :: E
|
||||
|
||||
SQRT_TWO :: 1.41421356237309504880168872420969808;
|
||||
SQRT_THREE :: 1.73205080756887729352744634150587236;
|
||||
SQRT_FIVE :: 2.23606797749978969640917366873127623;
|
||||
SQRT_TWO :: 1.41421356237309504880168872420969808
|
||||
SQRT_THREE :: 1.73205080756887729352744634150587236
|
||||
SQRT_FIVE :: 2.23606797749978969640917366873127623
|
||||
|
||||
LN2 :: 0.693147180559945309417232121458176568;
|
||||
LN10 :: 2.30258509299404568401799145468436421;
|
||||
LN2 :: 0.693147180559945309417232121458176568
|
||||
LN10 :: 2.30258509299404568401799145468436421
|
||||
|
||||
MAX_F64_PRECISION :: 16; // Maximum number of meaningful digits after the decimal point for 'f64'
|
||||
MAX_F32_PRECISION :: 8; // Maximum number of meaningful digits after the decimal point for 'f32'
|
||||
MAX_F64_PRECISION :: 16 // Maximum number of meaningful digits after the decimal point for 'f64'
|
||||
MAX_F32_PRECISION :: 8 // Maximum number of meaningful digits after the decimal point for 'f32'
|
||||
|
||||
RAD_PER_DEG :: TAU/360.0;
|
||||
DEG_PER_RAD :: 360.0/TAU;
|
||||
RAD_PER_DEG :: TAU/360.0
|
||||
DEG_PER_RAD :: 360.0/TAU
|
||||
|
||||
|
||||
|
||||
@private IS_NUMERIC :: intrinsics.type_is_numeric;
|
||||
@private IS_QUATERNION :: intrinsics.type_is_quaternion;
|
||||
@private IS_ARRAY :: intrinsics.type_is_array;
|
||||
@private IS_FLOAT :: intrinsics.type_is_float;
|
||||
@private BASE_TYPE :: intrinsics.type_base_type;
|
||||
@private ELEM_TYPE :: intrinsics.type_elem_type;
|
||||
@private IS_NUMERIC :: intrinsics.type_is_numeric
|
||||
@private IS_QUATERNION :: intrinsics.type_is_quaternion
|
||||
@private IS_ARRAY :: intrinsics.type_is_array
|
||||
@private IS_FLOAT :: intrinsics.type_is_float
|
||||
@private BASE_TYPE :: intrinsics.type_base_type
|
||||
@private ELEM_TYPE :: intrinsics.type_elem_type
|
||||
|
||||
|
||||
scalar_dot :: proc(a, b: $T) -> T where IS_FLOAT(T), !IS_ARRAY(T) {
|
||||
return a * b;
|
||||
return a * b
|
||||
}
|
||||
|
||||
vector_dot :: proc(a, b: $T/[$N]$E) -> (c: E) where IS_NUMERIC(E) #no_bounds_check {
|
||||
for i in 0..<N {
|
||||
c += a[i] * b[i];
|
||||
c += a[i] * b[i]
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
quaternion64_dot :: proc(a, b: $T/quaternion64) -> (c: f16) {
|
||||
return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z;
|
||||
return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z
|
||||
}
|
||||
quaternion128_dot :: proc(a, b: $T/quaternion128) -> (c: f32) {
|
||||
return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z;
|
||||
return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z
|
||||
}
|
||||
quaternion256_dot :: proc(a, b: $T/quaternion256) -> (c: f64) {
|
||||
return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z;
|
||||
return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z
|
||||
}
|
||||
|
||||
dot :: proc{scalar_dot, vector_dot, quaternion64_dot, quaternion128_dot, quaternion256_dot};
|
||||
dot :: proc{scalar_dot, vector_dot, quaternion64_dot, quaternion128_dot, quaternion256_dot}
|
||||
|
||||
inner_product :: dot;
|
||||
inner_product :: dot
|
||||
outer_product :: proc(a: $A/[$M]$E, b: $B/[$N]E) -> (out: [M][N]E) where IS_NUMERIC(E) #no_bounds_check {
|
||||
for i in 0..<M {
|
||||
for j in 0..<N {
|
||||
out[i][j] = a[i]*b[j];
|
||||
out[i][j] = a[i]*b[j]
|
||||
}
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
quaternion_inverse :: proc(q: $Q) -> Q where IS_QUATERNION(Q) {
|
||||
return conj(q) * quaternion(1.0/dot(q, q), 0, 0, 0);
|
||||
return conj(q) * quaternion(1.0/dot(q, q), 0, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
scalar_cross :: proc(a, b: $T) -> T where IS_FLOAT(T), !IS_ARRAY(T) {
|
||||
return a * b;
|
||||
return a * b
|
||||
}
|
||||
|
||||
vector_cross2 :: proc(a, b: $T/[2]$E) -> E where IS_NUMERIC(E) {
|
||||
return a[0]*b[1] - b[0]*a[1];
|
||||
return a[0]*b[1] - b[0]*a[1]
|
||||
}
|
||||
|
||||
vector_cross3 :: proc(a, b: $T/[3]$E) -> (c: T) where IS_NUMERIC(E) {
|
||||
c[0] = a[1]*b[2] - b[1]*a[2];
|
||||
c[1] = a[2]*b[0] - b[2]*a[0];
|
||||
c[2] = a[0]*b[1] - b[0]*a[1];
|
||||
return;
|
||||
c[0] = a[1]*b[2] - b[1]*a[2]
|
||||
c[1] = a[2]*b[0] - b[2]*a[0]
|
||||
c[2] = a[0]*b[1] - b[0]*a[1]
|
||||
return
|
||||
}
|
||||
|
||||
quaternion_cross :: proc(q1, q2: $Q) -> (q3: Q) where IS_QUATERNION(Q) {
|
||||
q3.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y;
|
||||
q3.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z;
|
||||
q3.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x;
|
||||
q3.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z;
|
||||
return;
|
||||
q3.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y
|
||||
q3.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z
|
||||
q3.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x
|
||||
q3.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z
|
||||
return
|
||||
}
|
||||
|
||||
vector_cross :: proc{scalar_cross, vector_cross2, vector_cross3};
|
||||
cross :: proc{scalar_cross, vector_cross2, vector_cross3, quaternion_cross};
|
||||
vector_cross :: proc{scalar_cross, vector_cross2, vector_cross3}
|
||||
cross :: proc{scalar_cross, vector_cross2, vector_cross3, quaternion_cross}
|
||||
|
||||
vector_normalize :: proc(v: $T/[$N]$E) -> T where IS_NUMERIC(E) {
|
||||
return v / length(v);
|
||||
return v / length(v)
|
||||
}
|
||||
quaternion_normalize :: proc(q: $Q) -> Q where IS_QUATERNION(Q) {
|
||||
return q/abs(q);
|
||||
return q/abs(q)
|
||||
}
|
||||
normalize :: proc{vector_normalize, quaternion_normalize};
|
||||
normalize :: proc{vector_normalize, quaternion_normalize}
|
||||
|
||||
vector_normalize0 :: proc(v: $T/[$N]$E) -> T where IS_NUMERIC(E) {
|
||||
m := length(v);
|
||||
return 0 if m == 0 else v/m;
|
||||
m := length(v)
|
||||
return 0 if m == 0 else v/m
|
||||
}
|
||||
quaternion_normalize0 :: proc(q: $Q) -> Q where IS_QUATERNION(Q) {
|
||||
m := abs(q);
|
||||
return 0 if m == 0 else q/m;
|
||||
m := abs(q)
|
||||
return 0 if m == 0 else q/m
|
||||
}
|
||||
normalize0 :: proc{vector_normalize0, quaternion_normalize0};
|
||||
normalize0 :: proc{vector_normalize0, quaternion_normalize0}
|
||||
|
||||
|
||||
vector_length :: proc(v: $T/[$N]$E) -> E where IS_NUMERIC(E) {
|
||||
return math.sqrt(dot(v, v));
|
||||
return math.sqrt(dot(v, v))
|
||||
}
|
||||
|
||||
vector_length2 :: proc(v: $T/[$N]$E) -> E where IS_NUMERIC(E) {
|
||||
return dot(v, v);
|
||||
return dot(v, v)
|
||||
}
|
||||
|
||||
quaternion_length :: proc(q: $Q) -> Q where IS_QUATERNION(Q) {
|
||||
return abs(q);
|
||||
return abs(q)
|
||||
}
|
||||
|
||||
quaternion_length2 :: proc(q: $Q) -> Q where IS_QUATERNION(Q) {
|
||||
return dot(q, q);
|
||||
return dot(q, q)
|
||||
}
|
||||
|
||||
scalar_triple_product :: proc(a, b, c: $T/[$N]$E) -> E where IS_NUMERIC(E) {
|
||||
// a . (b x c)
|
||||
// b . (c x a)
|
||||
// c . (a x b)
|
||||
return dot(a, cross(b, c));
|
||||
return dot(a, cross(b, c))
|
||||
}
|
||||
|
||||
vector_triple_product :: proc(a, b, c: $T/[$N]$E) -> T where IS_NUMERIC(E) {
|
||||
// a x (b x c)
|
||||
// (a . c)b - (a . b)c
|
||||
return cross(a, cross(b, c));
|
||||
return cross(a, cross(b, c))
|
||||
}
|
||||
|
||||
|
||||
length :: proc{vector_length, quaternion_length};
|
||||
length2 :: proc{vector_length2, quaternion_length2};
|
||||
length :: proc{vector_length, quaternion_length}
|
||||
length2 :: proc{vector_length2, quaternion_length2}
|
||||
|
||||
projection :: proc(x, normal: $T/[$N]$E) -> T where IS_NUMERIC(E) {
|
||||
return dot(x, normal) / dot(normal, normal) * normal;
|
||||
return dot(x, normal) / dot(normal, normal) * normal
|
||||
}
|
||||
|
||||
identity :: proc($T: typeid/[$N][N]$E) -> (m: T) #no_bounds_check {
|
||||
for i in 0..<N {
|
||||
m[i][i] = E(1);
|
||||
m[i][i] = E(1)
|
||||
}
|
||||
return m;
|
||||
return m
|
||||
}
|
||||
|
||||
trace :: proc(m: $T/[$N][N]$E) -> (tr: E) {
|
||||
for i in 0..<N {
|
||||
tr += m[i][i];
|
||||
tr += m[i][i]
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
transpose :: proc(a: $T/[$N][$M]$E) -> (m: (T when N == M else [M][N]E)) #no_bounds_check {
|
||||
for j in 0..<M {
|
||||
for i in 0..<N {
|
||||
m[j][i] = a[i][j];
|
||||
m[j][i] = a[i][j]
|
||||
}
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
matrix_mul :: proc(a, b: $M/[$N][N]$E) -> (c: M)
|
||||
@@ -184,21 +184,21 @@ matrix_mul :: proc(a, b: $M/[$N][N]$E) -> (c: M)
|
||||
for i in 0..<N {
|
||||
for k in 0..<N {
|
||||
for j in 0..<N {
|
||||
c[k][i] += a[j][i] * b[k][j];
|
||||
c[k][i] += a[j][i] * b[k][j]
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
matrix_comp_mul :: proc(a, b: $M/[$J][$I]$E) -> (c: M)
|
||||
where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check {
|
||||
for j in 0..<J {
|
||||
for i in 0..<I {
|
||||
c[j][i] = a[j][i] * b[j][i];
|
||||
c[j][i] = a[j][i] * b[j][i]
|
||||
}
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
matrix_mul_differ :: proc(a: $A/[$J][$I]$E, b: $B/[$K][J]E) -> (c: [K][I]E)
|
||||
@@ -206,11 +206,11 @@ matrix_mul_differ :: proc(a: $A/[$J][$I]$E, b: $B/[$K][J]E) -> (c: [K][I]E)
|
||||
for k in 0..<K {
|
||||
for j in 0..<J {
|
||||
for i in 0..<I {
|
||||
c[k][i] += a[j][i] * b[k][j];
|
||||
c[k][i] += a[j][i] * b[k][j]
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -218,44 +218,44 @@ matrix_mul_vector :: proc(a: $A/[$I][$J]$E, b: $B/[I]E) -> (c: B)
|
||||
where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check {
|
||||
for i in 0..<I {
|
||||
for j in 0..<J {
|
||||
c[j] += a[i][j] * b[i];
|
||||
c[j] += a[i][j] * b[i]
|
||||
}
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
quaternion_mul_quaternion :: proc(q1, q2: $Q) -> Q where IS_QUATERNION(Q) {
|
||||
return q1 * q2;
|
||||
return q1 * q2
|
||||
}
|
||||
|
||||
quaternion64_mul_vector3 :: proc(q: $Q/quaternion64, v: $V/[3]$F/f16) -> V {
|
||||
Raw_Quaternion :: struct {xyz: [3]f16, r: f16};
|
||||
Raw_Quaternion :: struct {xyz: [3]f16, r: f16}
|
||||
|
||||
q := transmute(Raw_Quaternion)q;
|
||||
v := transmute([3]f16)v;
|
||||
q := transmute(Raw_Quaternion)q
|
||||
v := transmute([3]f16)v
|
||||
|
||||
t := cross(2*q.xyz, v);
|
||||
return V(v + q.r*t + cross(q.xyz, t));
|
||||
t := cross(2*q.xyz, v)
|
||||
return V(v + q.r*t + cross(q.xyz, t))
|
||||
}
|
||||
quaternion128_mul_vector3 :: proc(q: $Q/quaternion128, v: $V/[3]$F/f32) -> V {
|
||||
Raw_Quaternion :: struct {xyz: [3]f32, r: f32};
|
||||
Raw_Quaternion :: struct {xyz: [3]f32, r: f32}
|
||||
|
||||
q := transmute(Raw_Quaternion)q;
|
||||
v := transmute([3]f32)v;
|
||||
q := transmute(Raw_Quaternion)q
|
||||
v := transmute([3]f32)v
|
||||
|
||||
t := cross(2*q.xyz, v);
|
||||
return V(v + q.r*t + cross(q.xyz, t));
|
||||
t := cross(2*q.xyz, v)
|
||||
return V(v + q.r*t + cross(q.xyz, t))
|
||||
}
|
||||
quaternion256_mul_vector3 :: proc(q: $Q/quaternion256, v: $V/[3]$F/f64) -> V {
|
||||
Raw_Quaternion :: struct {xyz: [3]f64, r: f64};
|
||||
Raw_Quaternion :: struct {xyz: [3]f64, r: f64}
|
||||
|
||||
q := transmute(Raw_Quaternion)q;
|
||||
v := transmute([3]f64)v;
|
||||
q := transmute(Raw_Quaternion)q
|
||||
v := transmute([3]f64)v
|
||||
|
||||
t := cross(2*q.xyz, v);
|
||||
return V(v + q.r*t + cross(q.xyz, t));
|
||||
t := cross(2*q.xyz, v)
|
||||
return V(v + q.r*t + cross(q.xyz, t))
|
||||
}
|
||||
quaternion_mul_vector3 :: proc{quaternion64_mul_vector3, quaternion128_mul_vector3, quaternion256_mul_vector3};
|
||||
quaternion_mul_vector3 :: proc{quaternion64_mul_vector3, quaternion128_mul_vector3, quaternion256_mul_vector3}
|
||||
|
||||
mul :: proc{
|
||||
matrix_mul,
|
||||
@@ -265,16 +265,16 @@ mul :: proc{
|
||||
quaternion128_mul_vector3,
|
||||
quaternion256_mul_vector3,
|
||||
quaternion_mul_quaternion,
|
||||
};
|
||||
}
|
||||
|
||||
vector_to_ptr :: proc(v: ^$V/[$N]$E) -> ^E where IS_NUMERIC(E), N > 0 #no_bounds_check {
|
||||
return &v[0];
|
||||
return &v[0]
|
||||
}
|
||||
matrix_to_ptr :: proc(m: ^$A/[$I][$J]$E) -> ^E where IS_NUMERIC(E), I > 0, J > 0 #no_bounds_check {
|
||||
return &m[0][0];
|
||||
return &m[0][0]
|
||||
}
|
||||
|
||||
to_ptr :: proc{vector_to_ptr, matrix_to_ptr};
|
||||
to_ptr :: proc{vector_to_ptr, matrix_to_ptr}
|
||||
|
||||
|
||||
|
||||
@@ -283,60 +283,60 @@ to_ptr :: proc{vector_to_ptr, matrix_to_ptr};
|
||||
// Splines
|
||||
|
||||
vector_slerp :: proc(x, y: $T/[$N]$E, a: E) -> T {
|
||||
cos_alpha := dot(x, y);
|
||||
alpha := math.acos(cos_alpha);
|
||||
sin_alpha := math.sin(alpha);
|
||||
cos_alpha := dot(x, y)
|
||||
alpha := math.acos(cos_alpha)
|
||||
sin_alpha := math.sin(alpha)
|
||||
|
||||
t1 := math.sin((1 - a) * alpha) / sin_alpha;
|
||||
t2 := math.sin(a * alpha) / sin_alpha;
|
||||
t1 := math.sin((1 - a) * alpha) / sin_alpha
|
||||
t2 := math.sin(a * alpha) / sin_alpha
|
||||
|
||||
return x * t1 + y * t2;
|
||||
return x * t1 + y * t2
|
||||
}
|
||||
|
||||
catmull_rom :: proc(v1, v2, v3, v4: $T/[$N]$E, s: E) -> T {
|
||||
s2 := s*s;
|
||||
s3 := s2*s;
|
||||
s2 := s*s
|
||||
s3 := s2*s
|
||||
|
||||
f1 := -s3 + 2 * s2 - s;
|
||||
f2 := 3 * s3 - 5 * s2 + 2;
|
||||
f3 := -3 * s3 + 4 * s2 + s;
|
||||
f4 := s3 - s2;
|
||||
f1 := -s3 + 2 * s2 - s
|
||||
f2 := 3 * s3 - 5 * s2 + 2
|
||||
f3 := -3 * s3 + 4 * s2 + s
|
||||
f4 := s3 - s2
|
||||
|
||||
return (f1 * v1 + f2 * v2 + f3 * v3 + f4 * v4) * 0.5;
|
||||
return (f1 * v1 + f2 * v2 + f3 * v3 + f4 * v4) * 0.5
|
||||
}
|
||||
|
||||
hermite :: proc(v1, t1, v2, t2: $T/[$N]$E, s: E) -> T {
|
||||
s2 := s*s;
|
||||
s3 := s2*s;
|
||||
s2 := s*s
|
||||
s3 := s2*s
|
||||
|
||||
f1 := 2 * s3 - 3 * s2 + 1;
|
||||
f2 := -2 * s3 + 3 * s2;
|
||||
f3 := s3 - 2 * s2 + s;
|
||||
f4 := s3 - s2;
|
||||
f1 := 2 * s3 - 3 * s2 + 1
|
||||
f2 := -2 * s3 + 3 * s2
|
||||
f3 := s3 - 2 * s2 + s
|
||||
f4 := s3 - s2
|
||||
|
||||
return f1 * v1 + f2 * v2 + f3 * t1 + f4 * t2;
|
||||
return f1 * v1 + f2 * v2 + f3 * t1 + f4 * t2
|
||||
}
|
||||
|
||||
cubic :: proc(v1, v2, v3, v4: $T/[$N]$E, s: E) -> T {
|
||||
return ((v1 * s + v2) * s + v3) * s + v4;
|
||||
return ((v1 * s + v2) * s + v3) * s + v4
|
||||
}
|
||||
|
||||
|
||||
|
||||
array_cast :: proc(v: $A/[$N]$T, $Elem_Type: typeid) -> (w: [N]Elem_Type) #no_bounds_check {
|
||||
for i in 0..<N {
|
||||
w[i] = Elem_Type(v[i]);
|
||||
w[i] = Elem_Type(v[i])
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
matrix_cast :: proc(v: $A/[$M][$N]$T, $Elem_Type: typeid) -> (w: [M][N]Elem_Type) #no_bounds_check {
|
||||
for i in 0..<M {
|
||||
for j in 0..<N {
|
||||
w[i][j] = Elem_Type(v[i][j]);
|
||||
w[i][j] = Elem_Type(v[i][j])
|
||||
}
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
to_f32 :: #force_inline proc(v: $A/[$N]$T) -> [N]f32 { return array_cast(v, f32); }
|
||||
|
||||
+1455
-1455
File diff suppressed because it is too large
Load Diff
@@ -19,109 +19,109 @@ Euler_Angle_Order :: enum {
|
||||
}
|
||||
|
||||
|
||||
quaternion_from_euler_angles :: proc{quaternion_from_euler_angles_f16, quaternion_from_euler_angles_f32, quaternion_from_euler_angles_f64};
|
||||
quaternion_from_euler_angle_x :: proc{quaternion_from_euler_angle_x_f16, quaternion_from_euler_angle_x_f32, quaternion_from_euler_angle_x_f64};
|
||||
quaternion_from_euler_angle_y :: proc{quaternion_from_euler_angle_y_f16, quaternion_from_euler_angle_y_f32, quaternion_from_euler_angle_y_f64};
|
||||
quaternion_from_euler_angle_z :: proc{quaternion_from_euler_angle_z_f16, quaternion_from_euler_angle_z_f32, quaternion_from_euler_angle_z_f64};
|
||||
quaternion_from_pitch_yaw_roll :: proc{quaternion_from_pitch_yaw_roll_f16, quaternion_from_pitch_yaw_roll_f32, quaternion_from_pitch_yaw_roll_f64};
|
||||
quaternion_from_euler_angles :: proc{quaternion_from_euler_angles_f16, quaternion_from_euler_angles_f32, quaternion_from_euler_angles_f64}
|
||||
quaternion_from_euler_angle_x :: proc{quaternion_from_euler_angle_x_f16, quaternion_from_euler_angle_x_f32, quaternion_from_euler_angle_x_f64}
|
||||
quaternion_from_euler_angle_y :: proc{quaternion_from_euler_angle_y_f16, quaternion_from_euler_angle_y_f32, quaternion_from_euler_angle_y_f64}
|
||||
quaternion_from_euler_angle_z :: proc{quaternion_from_euler_angle_z_f16, quaternion_from_euler_angle_z_f32, quaternion_from_euler_angle_z_f64}
|
||||
quaternion_from_pitch_yaw_roll :: proc{quaternion_from_pitch_yaw_roll_f16, quaternion_from_pitch_yaw_roll_f32, quaternion_from_pitch_yaw_roll_f64}
|
||||
|
||||
euler_angles_from_quaternion :: proc{euler_angles_from_quaternion_f16, euler_angles_from_quaternion_f32, euler_angles_from_quaternion_f64};
|
||||
euler_angles_xyz_from_quaternion :: proc{euler_angles_xyz_from_quaternion_f16, euler_angles_xyz_from_quaternion_f32, euler_angles_xyz_from_quaternion_f64};
|
||||
euler_angles_yxz_from_quaternion :: proc{euler_angles_yxz_from_quaternion_f16, euler_angles_yxz_from_quaternion_f32, euler_angles_yxz_from_quaternion_f64};
|
||||
euler_angles_xzx_from_quaternion :: proc{euler_angles_xzx_from_quaternion_f16, euler_angles_xzx_from_quaternion_f32, euler_angles_xzx_from_quaternion_f64};
|
||||
euler_angles_xyx_from_quaternion :: proc{euler_angles_xyx_from_quaternion_f16, euler_angles_xyx_from_quaternion_f32, euler_angles_xyx_from_quaternion_f64};
|
||||
euler_angles_yxy_from_quaternion :: proc{euler_angles_yxy_from_quaternion_f16, euler_angles_yxy_from_quaternion_f32, euler_angles_yxy_from_quaternion_f64};
|
||||
euler_angles_yzy_from_quaternion :: proc{euler_angles_yzy_from_quaternion_f16, euler_angles_yzy_from_quaternion_f32, euler_angles_yzy_from_quaternion_f64};
|
||||
euler_angles_zyz_from_quaternion :: proc{euler_angles_zyz_from_quaternion_f16, euler_angles_zyz_from_quaternion_f32, euler_angles_zyz_from_quaternion_f64};
|
||||
euler_angles_zxz_from_quaternion :: proc{euler_angles_zxz_from_quaternion_f16, euler_angles_zxz_from_quaternion_f32, euler_angles_zxz_from_quaternion_f64};
|
||||
euler_angles_xzy_from_quaternion :: proc{euler_angles_xzy_from_quaternion_f16, euler_angles_xzy_from_quaternion_f32, euler_angles_xzy_from_quaternion_f64};
|
||||
euler_angles_yzx_from_quaternion :: proc{euler_angles_yzx_from_quaternion_f16, euler_angles_yzx_from_quaternion_f32, euler_angles_yzx_from_quaternion_f64};
|
||||
euler_angles_zyx_from_quaternion :: proc{euler_angles_zyx_from_quaternion_f16, euler_angles_zyx_from_quaternion_f32, euler_angles_zyx_from_quaternion_f64};
|
||||
euler_angles_zxy_from_quaternion :: proc{euler_angles_zxy_from_quaternion_f16, euler_angles_zxy_from_quaternion_f32, euler_angles_zxy_from_quaternion_f64};
|
||||
euler_angles_from_quaternion :: proc{euler_angles_from_quaternion_f16, euler_angles_from_quaternion_f32, euler_angles_from_quaternion_f64}
|
||||
euler_angles_xyz_from_quaternion :: proc{euler_angles_xyz_from_quaternion_f16, euler_angles_xyz_from_quaternion_f32, euler_angles_xyz_from_quaternion_f64}
|
||||
euler_angles_yxz_from_quaternion :: proc{euler_angles_yxz_from_quaternion_f16, euler_angles_yxz_from_quaternion_f32, euler_angles_yxz_from_quaternion_f64}
|
||||
euler_angles_xzx_from_quaternion :: proc{euler_angles_xzx_from_quaternion_f16, euler_angles_xzx_from_quaternion_f32, euler_angles_xzx_from_quaternion_f64}
|
||||
euler_angles_xyx_from_quaternion :: proc{euler_angles_xyx_from_quaternion_f16, euler_angles_xyx_from_quaternion_f32, euler_angles_xyx_from_quaternion_f64}
|
||||
euler_angles_yxy_from_quaternion :: proc{euler_angles_yxy_from_quaternion_f16, euler_angles_yxy_from_quaternion_f32, euler_angles_yxy_from_quaternion_f64}
|
||||
euler_angles_yzy_from_quaternion :: proc{euler_angles_yzy_from_quaternion_f16, euler_angles_yzy_from_quaternion_f32, euler_angles_yzy_from_quaternion_f64}
|
||||
euler_angles_zyz_from_quaternion :: proc{euler_angles_zyz_from_quaternion_f16, euler_angles_zyz_from_quaternion_f32, euler_angles_zyz_from_quaternion_f64}
|
||||
euler_angles_zxz_from_quaternion :: proc{euler_angles_zxz_from_quaternion_f16, euler_angles_zxz_from_quaternion_f32, euler_angles_zxz_from_quaternion_f64}
|
||||
euler_angles_xzy_from_quaternion :: proc{euler_angles_xzy_from_quaternion_f16, euler_angles_xzy_from_quaternion_f32, euler_angles_xzy_from_quaternion_f64}
|
||||
euler_angles_yzx_from_quaternion :: proc{euler_angles_yzx_from_quaternion_f16, euler_angles_yzx_from_quaternion_f32, euler_angles_yzx_from_quaternion_f64}
|
||||
euler_angles_zyx_from_quaternion :: proc{euler_angles_zyx_from_quaternion_f16, euler_angles_zyx_from_quaternion_f32, euler_angles_zyx_from_quaternion_f64}
|
||||
euler_angles_zxy_from_quaternion :: proc{euler_angles_zxy_from_quaternion_f16, euler_angles_zxy_from_quaternion_f32, euler_angles_zxy_from_quaternion_f64}
|
||||
|
||||
roll_from_quaternion :: proc{roll_from_quaternion_f16, roll_from_quaternion_f32, roll_from_quaternion_f64};
|
||||
pitch_from_quaternion :: proc{pitch_from_quaternion_f16, pitch_from_quaternion_f32, pitch_from_quaternion_f64};
|
||||
yaw_from_quaternion :: proc{yaw_from_quaternion_f16, yaw_from_quaternion_f32, yaw_from_quaternion_f64};
|
||||
pitch_yaw_roll_from_quaternion :: proc{pitch_yaw_roll_from_quaternion_f16, pitch_yaw_roll_from_quaternion_f32, pitch_yaw_roll_from_quaternion_f64};
|
||||
roll_from_quaternion :: proc{roll_from_quaternion_f16, roll_from_quaternion_f32, roll_from_quaternion_f64}
|
||||
pitch_from_quaternion :: proc{pitch_from_quaternion_f16, pitch_from_quaternion_f32, pitch_from_quaternion_f64}
|
||||
yaw_from_quaternion :: proc{yaw_from_quaternion_f16, yaw_from_quaternion_f32, yaw_from_quaternion_f64}
|
||||
pitch_yaw_roll_from_quaternion :: proc{pitch_yaw_roll_from_quaternion_f16, pitch_yaw_roll_from_quaternion_f32, pitch_yaw_roll_from_quaternion_f64}
|
||||
|
||||
matrix3_from_euler_angles :: proc{matrix3_from_euler_angles_f16, matrix3_from_euler_angles_f32, matrix3_from_euler_angles_f64};
|
||||
matrix3_from_euler_angle_x :: proc{matrix3_from_euler_angle_x_f16, matrix3_from_euler_angle_x_f32, matrix3_from_euler_angle_x_f64};
|
||||
matrix3_from_euler_angle_y :: proc{matrix3_from_euler_angle_y_f16, matrix3_from_euler_angle_y_f32, matrix3_from_euler_angle_y_f64};
|
||||
matrix3_from_euler_angle_z :: proc{matrix3_from_euler_angle_z_f16, matrix3_from_euler_angle_z_f32, matrix3_from_euler_angle_z_f64};
|
||||
matrix3_from_derived_euler_angle_x :: proc{matrix3_from_derived_euler_angle_x_f16, matrix3_from_derived_euler_angle_x_f32, matrix3_from_derived_euler_angle_x_f64};
|
||||
matrix3_from_derived_euler_angle_y :: proc{matrix3_from_derived_euler_angle_y_f16, matrix3_from_derived_euler_angle_y_f32, matrix3_from_derived_euler_angle_y_f64};
|
||||
matrix3_from_derived_euler_angle_z :: proc{matrix3_from_derived_euler_angle_z_f16, matrix3_from_derived_euler_angle_z_f32, matrix3_from_derived_euler_angle_z_f64};
|
||||
matrix3_from_euler_angles_xy :: proc{matrix3_from_euler_angles_xy_f16, matrix3_from_euler_angles_xy_f32, matrix3_from_euler_angles_xy_f64};
|
||||
matrix3_from_euler_angles_yx :: proc{matrix3_from_euler_angles_yx_f16, matrix3_from_euler_angles_yx_f32, matrix3_from_euler_angles_yx_f64};
|
||||
matrix3_from_euler_angles_xz :: proc{matrix3_from_euler_angles_xz_f16, matrix3_from_euler_angles_xz_f32, matrix3_from_euler_angles_xz_f64};
|
||||
matrix3_from_euler_angles_zx :: proc{matrix3_from_euler_angles_zx_f16, matrix3_from_euler_angles_zx_f32, matrix3_from_euler_angles_zx_f64};
|
||||
matrix3_from_euler_angles_yz :: proc{matrix3_from_euler_angles_yz_f16, matrix3_from_euler_angles_yz_f32, matrix3_from_euler_angles_yz_f64};
|
||||
matrix3_from_euler_angles_zy :: proc{matrix3_from_euler_angles_zy_f16, matrix3_from_euler_angles_zy_f32, matrix3_from_euler_angles_zy_f64};
|
||||
matrix3_from_euler_angles_xyz :: proc{matrix3_from_euler_angles_xyz_f16, matrix3_from_euler_angles_xyz_f32, matrix3_from_euler_angles_xyz_f64};
|
||||
matrix3_from_euler_angles_yxz :: proc{matrix3_from_euler_angles_yxz_f16, matrix3_from_euler_angles_yxz_f32, matrix3_from_euler_angles_yxz_f64};
|
||||
matrix3_from_euler_angles_xzx :: proc{matrix3_from_euler_angles_xzx_f16, matrix3_from_euler_angles_xzx_f32, matrix3_from_euler_angles_xzx_f64};
|
||||
matrix3_from_euler_angles_xyx :: proc{matrix3_from_euler_angles_xyx_f16, matrix3_from_euler_angles_xyx_f32, matrix3_from_euler_angles_xyx_f64};
|
||||
matrix3_from_euler_angles_yxy :: proc{matrix3_from_euler_angles_yxy_f16, matrix3_from_euler_angles_yxy_f32, matrix3_from_euler_angles_yxy_f64};
|
||||
matrix3_from_euler_angles_yzy :: proc{matrix3_from_euler_angles_yzy_f16, matrix3_from_euler_angles_yzy_f32, matrix3_from_euler_angles_yzy_f64};
|
||||
matrix3_from_euler_angles_zyz :: proc{matrix3_from_euler_angles_zyz_f16, matrix3_from_euler_angles_zyz_f32, matrix3_from_euler_angles_zyz_f64};
|
||||
matrix3_from_euler_angles_zxz :: proc{matrix3_from_euler_angles_zxz_f16, matrix3_from_euler_angles_zxz_f32, matrix3_from_euler_angles_zxz_f64};
|
||||
matrix3_from_euler_angles_xzy :: proc{matrix3_from_euler_angles_xzy_f16, matrix3_from_euler_angles_xzy_f32, matrix3_from_euler_angles_xzy_f64};
|
||||
matrix3_from_euler_angles_yzx :: proc{matrix3_from_euler_angles_yzx_f16, matrix3_from_euler_angles_yzx_f32, matrix3_from_euler_angles_yzx_f64};
|
||||
matrix3_from_euler_angles_zyx :: proc{matrix3_from_euler_angles_zyx_f16, matrix3_from_euler_angles_zyx_f32, matrix3_from_euler_angles_zyx_f64};
|
||||
matrix3_from_euler_angles_zxy :: proc{matrix3_from_euler_angles_zxy_f16, matrix3_from_euler_angles_zxy_f32, matrix3_from_euler_angles_zxy_f64};
|
||||
matrix3_from_yaw_pitch_roll :: proc{matrix3_from_yaw_pitch_roll_f16, matrix3_from_yaw_pitch_roll_f32, matrix3_from_yaw_pitch_roll_f64};
|
||||
matrix3_from_euler_angles :: proc{matrix3_from_euler_angles_f16, matrix3_from_euler_angles_f32, matrix3_from_euler_angles_f64}
|
||||
matrix3_from_euler_angle_x :: proc{matrix3_from_euler_angle_x_f16, matrix3_from_euler_angle_x_f32, matrix3_from_euler_angle_x_f64}
|
||||
matrix3_from_euler_angle_y :: proc{matrix3_from_euler_angle_y_f16, matrix3_from_euler_angle_y_f32, matrix3_from_euler_angle_y_f64}
|
||||
matrix3_from_euler_angle_z :: proc{matrix3_from_euler_angle_z_f16, matrix3_from_euler_angle_z_f32, matrix3_from_euler_angle_z_f64}
|
||||
matrix3_from_derived_euler_angle_x :: proc{matrix3_from_derived_euler_angle_x_f16, matrix3_from_derived_euler_angle_x_f32, matrix3_from_derived_euler_angle_x_f64}
|
||||
matrix3_from_derived_euler_angle_y :: proc{matrix3_from_derived_euler_angle_y_f16, matrix3_from_derived_euler_angle_y_f32, matrix3_from_derived_euler_angle_y_f64}
|
||||
matrix3_from_derived_euler_angle_z :: proc{matrix3_from_derived_euler_angle_z_f16, matrix3_from_derived_euler_angle_z_f32, matrix3_from_derived_euler_angle_z_f64}
|
||||
matrix3_from_euler_angles_xy :: proc{matrix3_from_euler_angles_xy_f16, matrix3_from_euler_angles_xy_f32, matrix3_from_euler_angles_xy_f64}
|
||||
matrix3_from_euler_angles_yx :: proc{matrix3_from_euler_angles_yx_f16, matrix3_from_euler_angles_yx_f32, matrix3_from_euler_angles_yx_f64}
|
||||
matrix3_from_euler_angles_xz :: proc{matrix3_from_euler_angles_xz_f16, matrix3_from_euler_angles_xz_f32, matrix3_from_euler_angles_xz_f64}
|
||||
matrix3_from_euler_angles_zx :: proc{matrix3_from_euler_angles_zx_f16, matrix3_from_euler_angles_zx_f32, matrix3_from_euler_angles_zx_f64}
|
||||
matrix3_from_euler_angles_yz :: proc{matrix3_from_euler_angles_yz_f16, matrix3_from_euler_angles_yz_f32, matrix3_from_euler_angles_yz_f64}
|
||||
matrix3_from_euler_angles_zy :: proc{matrix3_from_euler_angles_zy_f16, matrix3_from_euler_angles_zy_f32, matrix3_from_euler_angles_zy_f64}
|
||||
matrix3_from_euler_angles_xyz :: proc{matrix3_from_euler_angles_xyz_f16, matrix3_from_euler_angles_xyz_f32, matrix3_from_euler_angles_xyz_f64}
|
||||
matrix3_from_euler_angles_yxz :: proc{matrix3_from_euler_angles_yxz_f16, matrix3_from_euler_angles_yxz_f32, matrix3_from_euler_angles_yxz_f64}
|
||||
matrix3_from_euler_angles_xzx :: proc{matrix3_from_euler_angles_xzx_f16, matrix3_from_euler_angles_xzx_f32, matrix3_from_euler_angles_xzx_f64}
|
||||
matrix3_from_euler_angles_xyx :: proc{matrix3_from_euler_angles_xyx_f16, matrix3_from_euler_angles_xyx_f32, matrix3_from_euler_angles_xyx_f64}
|
||||
matrix3_from_euler_angles_yxy :: proc{matrix3_from_euler_angles_yxy_f16, matrix3_from_euler_angles_yxy_f32, matrix3_from_euler_angles_yxy_f64}
|
||||
matrix3_from_euler_angles_yzy :: proc{matrix3_from_euler_angles_yzy_f16, matrix3_from_euler_angles_yzy_f32, matrix3_from_euler_angles_yzy_f64}
|
||||
matrix3_from_euler_angles_zyz :: proc{matrix3_from_euler_angles_zyz_f16, matrix3_from_euler_angles_zyz_f32, matrix3_from_euler_angles_zyz_f64}
|
||||
matrix3_from_euler_angles_zxz :: proc{matrix3_from_euler_angles_zxz_f16, matrix3_from_euler_angles_zxz_f32, matrix3_from_euler_angles_zxz_f64}
|
||||
matrix3_from_euler_angles_xzy :: proc{matrix3_from_euler_angles_xzy_f16, matrix3_from_euler_angles_xzy_f32, matrix3_from_euler_angles_xzy_f64}
|
||||
matrix3_from_euler_angles_yzx :: proc{matrix3_from_euler_angles_yzx_f16, matrix3_from_euler_angles_yzx_f32, matrix3_from_euler_angles_yzx_f64}
|
||||
matrix3_from_euler_angles_zyx :: proc{matrix3_from_euler_angles_zyx_f16, matrix3_from_euler_angles_zyx_f32, matrix3_from_euler_angles_zyx_f64}
|
||||
matrix3_from_euler_angles_zxy :: proc{matrix3_from_euler_angles_zxy_f16, matrix3_from_euler_angles_zxy_f32, matrix3_from_euler_angles_zxy_f64}
|
||||
matrix3_from_yaw_pitch_roll :: proc{matrix3_from_yaw_pitch_roll_f16, matrix3_from_yaw_pitch_roll_f32, matrix3_from_yaw_pitch_roll_f64}
|
||||
|
||||
euler_angles_from_matrix3 :: proc{euler_angles_from_matrix3_f16, euler_angles_from_matrix3_f32, euler_angles_from_matrix3_f64};
|
||||
euler_angles_xyz_from_matrix3 :: proc{euler_angles_xyz_from_matrix3_f16, euler_angles_xyz_from_matrix3_f32, euler_angles_xyz_from_matrix3_f64};
|
||||
euler_angles_yxz_from_matrix3 :: proc{euler_angles_yxz_from_matrix3_f16, euler_angles_yxz_from_matrix3_f32, euler_angles_yxz_from_matrix3_f64};
|
||||
euler_angles_xzx_from_matrix3 :: proc{euler_angles_xzx_from_matrix3_f16, euler_angles_xzx_from_matrix3_f32, euler_angles_xzx_from_matrix3_f64};
|
||||
euler_angles_xyx_from_matrix3 :: proc{euler_angles_xyx_from_matrix3_f16, euler_angles_xyx_from_matrix3_f32, euler_angles_xyx_from_matrix3_f64};
|
||||
euler_angles_yxy_from_matrix3 :: proc{euler_angles_yxy_from_matrix3_f16, euler_angles_yxy_from_matrix3_f32, euler_angles_yxy_from_matrix3_f64};
|
||||
euler_angles_yzy_from_matrix3 :: proc{euler_angles_yzy_from_matrix3_f16, euler_angles_yzy_from_matrix3_f32, euler_angles_yzy_from_matrix3_f64};
|
||||
euler_angles_zyz_from_matrix3 :: proc{euler_angles_zyz_from_matrix3_f16, euler_angles_zyz_from_matrix3_f32, euler_angles_zyz_from_matrix3_f64};
|
||||
euler_angles_zxz_from_matrix3 :: proc{euler_angles_zxz_from_matrix3_f16, euler_angles_zxz_from_matrix3_f32, euler_angles_zxz_from_matrix3_f64};
|
||||
euler_angles_xzy_from_matrix3 :: proc{euler_angles_xzy_from_matrix3_f16, euler_angles_xzy_from_matrix3_f32, euler_angles_xzy_from_matrix3_f64};
|
||||
euler_angles_yzx_from_matrix3 :: proc{euler_angles_yzx_from_matrix3_f16, euler_angles_yzx_from_matrix3_f32, euler_angles_yzx_from_matrix3_f64};
|
||||
euler_angles_zyx_from_matrix3 :: proc{euler_angles_zyx_from_matrix3_f16, euler_angles_zyx_from_matrix3_f32, euler_angles_zyx_from_matrix3_f64};
|
||||
euler_angles_zxy_from_matrix3 :: proc{euler_angles_zxy_from_matrix3_f16, euler_angles_zxy_from_matrix3_f32, euler_angles_zxy_from_matrix3_f64};
|
||||
euler_angles_from_matrix3 :: proc{euler_angles_from_matrix3_f16, euler_angles_from_matrix3_f32, euler_angles_from_matrix3_f64}
|
||||
euler_angles_xyz_from_matrix3 :: proc{euler_angles_xyz_from_matrix3_f16, euler_angles_xyz_from_matrix3_f32, euler_angles_xyz_from_matrix3_f64}
|
||||
euler_angles_yxz_from_matrix3 :: proc{euler_angles_yxz_from_matrix3_f16, euler_angles_yxz_from_matrix3_f32, euler_angles_yxz_from_matrix3_f64}
|
||||
euler_angles_xzx_from_matrix3 :: proc{euler_angles_xzx_from_matrix3_f16, euler_angles_xzx_from_matrix3_f32, euler_angles_xzx_from_matrix3_f64}
|
||||
euler_angles_xyx_from_matrix3 :: proc{euler_angles_xyx_from_matrix3_f16, euler_angles_xyx_from_matrix3_f32, euler_angles_xyx_from_matrix3_f64}
|
||||
euler_angles_yxy_from_matrix3 :: proc{euler_angles_yxy_from_matrix3_f16, euler_angles_yxy_from_matrix3_f32, euler_angles_yxy_from_matrix3_f64}
|
||||
euler_angles_yzy_from_matrix3 :: proc{euler_angles_yzy_from_matrix3_f16, euler_angles_yzy_from_matrix3_f32, euler_angles_yzy_from_matrix3_f64}
|
||||
euler_angles_zyz_from_matrix3 :: proc{euler_angles_zyz_from_matrix3_f16, euler_angles_zyz_from_matrix3_f32, euler_angles_zyz_from_matrix3_f64}
|
||||
euler_angles_zxz_from_matrix3 :: proc{euler_angles_zxz_from_matrix3_f16, euler_angles_zxz_from_matrix3_f32, euler_angles_zxz_from_matrix3_f64}
|
||||
euler_angles_xzy_from_matrix3 :: proc{euler_angles_xzy_from_matrix3_f16, euler_angles_xzy_from_matrix3_f32, euler_angles_xzy_from_matrix3_f64}
|
||||
euler_angles_yzx_from_matrix3 :: proc{euler_angles_yzx_from_matrix3_f16, euler_angles_yzx_from_matrix3_f32, euler_angles_yzx_from_matrix3_f64}
|
||||
euler_angles_zyx_from_matrix3 :: proc{euler_angles_zyx_from_matrix3_f16, euler_angles_zyx_from_matrix3_f32, euler_angles_zyx_from_matrix3_f64}
|
||||
euler_angles_zxy_from_matrix3 :: proc{euler_angles_zxy_from_matrix3_f16, euler_angles_zxy_from_matrix3_f32, euler_angles_zxy_from_matrix3_f64}
|
||||
|
||||
matrix4_from_euler_angles :: proc{matrix4_from_euler_angles_f16, matrix4_from_euler_angles_f32, matrix4_from_euler_angles_f64};
|
||||
matrix4_from_euler_angle_x :: proc{matrix4_from_euler_angle_x_f16, matrix4_from_euler_angle_x_f32, matrix4_from_euler_angle_x_f64};
|
||||
matrix4_from_euler_angle_y :: proc{matrix4_from_euler_angle_y_f16, matrix4_from_euler_angle_y_f32, matrix4_from_euler_angle_y_f64};
|
||||
matrix4_from_euler_angle_z :: proc{matrix4_from_euler_angle_z_f16, matrix4_from_euler_angle_z_f32, matrix4_from_euler_angle_z_f64};
|
||||
matrix4_from_derived_euler_angle_x :: proc{matrix4_from_derived_euler_angle_x_f16, matrix4_from_derived_euler_angle_x_f32, matrix4_from_derived_euler_angle_x_f64};
|
||||
matrix4_from_derived_euler_angle_y :: proc{matrix4_from_derived_euler_angle_y_f16, matrix4_from_derived_euler_angle_y_f32, matrix4_from_derived_euler_angle_y_f64};
|
||||
matrix4_from_derived_euler_angle_z :: proc{matrix4_from_derived_euler_angle_z_f16, matrix4_from_derived_euler_angle_z_f32, matrix4_from_derived_euler_angle_z_f64};
|
||||
matrix4_from_euler_angles_xy :: proc{matrix4_from_euler_angles_xy_f16, matrix4_from_euler_angles_xy_f32, matrix4_from_euler_angles_xy_f64};
|
||||
matrix4_from_euler_angles_yx :: proc{matrix4_from_euler_angles_yx_f16, matrix4_from_euler_angles_yx_f32, matrix4_from_euler_angles_yx_f64};
|
||||
matrix4_from_euler_angles_xz :: proc{matrix4_from_euler_angles_xz_f16, matrix4_from_euler_angles_xz_f32, matrix4_from_euler_angles_xz_f64};
|
||||
matrix4_from_euler_angles_zx :: proc{matrix4_from_euler_angles_zx_f16, matrix4_from_euler_angles_zx_f32, matrix4_from_euler_angles_zx_f64};
|
||||
matrix4_from_euler_angles_yz :: proc{matrix4_from_euler_angles_yz_f16, matrix4_from_euler_angles_yz_f32, matrix4_from_euler_angles_yz_f64};
|
||||
matrix4_from_euler_angles_zy :: proc{matrix4_from_euler_angles_zy_f16, matrix4_from_euler_angles_zy_f32, matrix4_from_euler_angles_zy_f64};
|
||||
matrix4_from_euler_angles_xyz :: proc{matrix4_from_euler_angles_xyz_f16, matrix4_from_euler_angles_xyz_f32, matrix4_from_euler_angles_xyz_f64};
|
||||
matrix4_from_euler_angles_yxz :: proc{matrix4_from_euler_angles_yxz_f16, matrix4_from_euler_angles_yxz_f32, matrix4_from_euler_angles_yxz_f64};
|
||||
matrix4_from_euler_angles_xzx :: proc{matrix4_from_euler_angles_xzx_f16, matrix4_from_euler_angles_xzx_f32, matrix4_from_euler_angles_xzx_f64};
|
||||
matrix4_from_euler_angles_xyx :: proc{matrix4_from_euler_angles_xyx_f16, matrix4_from_euler_angles_xyx_f32, matrix4_from_euler_angles_xyx_f64};
|
||||
matrix4_from_euler_angles_yxy :: proc{matrix4_from_euler_angles_yxy_f16, matrix4_from_euler_angles_yxy_f32, matrix4_from_euler_angles_yxy_f64};
|
||||
matrix4_from_euler_angles_yzy :: proc{matrix4_from_euler_angles_yzy_f16, matrix4_from_euler_angles_yzy_f32, matrix4_from_euler_angles_yzy_f64};
|
||||
matrix4_from_euler_angles_zyz :: proc{matrix4_from_euler_angles_zyz_f16, matrix4_from_euler_angles_zyz_f32, matrix4_from_euler_angles_zyz_f64};
|
||||
matrix4_from_euler_angles_zxz :: proc{matrix4_from_euler_angles_zxz_f16, matrix4_from_euler_angles_zxz_f32, matrix4_from_euler_angles_zxz_f64};
|
||||
matrix4_from_euler_angles_xzy :: proc{matrix4_from_euler_angles_xzy_f16, matrix4_from_euler_angles_xzy_f32, matrix4_from_euler_angles_xzy_f64};
|
||||
matrix4_from_euler_angles_yzx :: proc{matrix4_from_euler_angles_yzx_f16, matrix4_from_euler_angles_yzx_f32, matrix4_from_euler_angles_yzx_f64};
|
||||
matrix4_from_euler_angles_zyx :: proc{matrix4_from_euler_angles_zyx_f16, matrix4_from_euler_angles_zyx_f32, matrix4_from_euler_angles_zyx_f64};
|
||||
matrix4_from_euler_angles_zxy :: proc{matrix4_from_euler_angles_zxy_f16, matrix4_from_euler_angles_zxy_f32, matrix4_from_euler_angles_zxy_f64};
|
||||
matrix4_from_yaw_pitch_roll :: proc{matrix4_from_yaw_pitch_roll_f16, matrix4_from_yaw_pitch_roll_f32, matrix4_from_yaw_pitch_roll_f64};
|
||||
matrix4_from_euler_angles :: proc{matrix4_from_euler_angles_f16, matrix4_from_euler_angles_f32, matrix4_from_euler_angles_f64}
|
||||
matrix4_from_euler_angle_x :: proc{matrix4_from_euler_angle_x_f16, matrix4_from_euler_angle_x_f32, matrix4_from_euler_angle_x_f64}
|
||||
matrix4_from_euler_angle_y :: proc{matrix4_from_euler_angle_y_f16, matrix4_from_euler_angle_y_f32, matrix4_from_euler_angle_y_f64}
|
||||
matrix4_from_euler_angle_z :: proc{matrix4_from_euler_angle_z_f16, matrix4_from_euler_angle_z_f32, matrix4_from_euler_angle_z_f64}
|
||||
matrix4_from_derived_euler_angle_x :: proc{matrix4_from_derived_euler_angle_x_f16, matrix4_from_derived_euler_angle_x_f32, matrix4_from_derived_euler_angle_x_f64}
|
||||
matrix4_from_derived_euler_angle_y :: proc{matrix4_from_derived_euler_angle_y_f16, matrix4_from_derived_euler_angle_y_f32, matrix4_from_derived_euler_angle_y_f64}
|
||||
matrix4_from_derived_euler_angle_z :: proc{matrix4_from_derived_euler_angle_z_f16, matrix4_from_derived_euler_angle_z_f32, matrix4_from_derived_euler_angle_z_f64}
|
||||
matrix4_from_euler_angles_xy :: proc{matrix4_from_euler_angles_xy_f16, matrix4_from_euler_angles_xy_f32, matrix4_from_euler_angles_xy_f64}
|
||||
matrix4_from_euler_angles_yx :: proc{matrix4_from_euler_angles_yx_f16, matrix4_from_euler_angles_yx_f32, matrix4_from_euler_angles_yx_f64}
|
||||
matrix4_from_euler_angles_xz :: proc{matrix4_from_euler_angles_xz_f16, matrix4_from_euler_angles_xz_f32, matrix4_from_euler_angles_xz_f64}
|
||||
matrix4_from_euler_angles_zx :: proc{matrix4_from_euler_angles_zx_f16, matrix4_from_euler_angles_zx_f32, matrix4_from_euler_angles_zx_f64}
|
||||
matrix4_from_euler_angles_yz :: proc{matrix4_from_euler_angles_yz_f16, matrix4_from_euler_angles_yz_f32, matrix4_from_euler_angles_yz_f64}
|
||||
matrix4_from_euler_angles_zy :: proc{matrix4_from_euler_angles_zy_f16, matrix4_from_euler_angles_zy_f32, matrix4_from_euler_angles_zy_f64}
|
||||
matrix4_from_euler_angles_xyz :: proc{matrix4_from_euler_angles_xyz_f16, matrix4_from_euler_angles_xyz_f32, matrix4_from_euler_angles_xyz_f64}
|
||||
matrix4_from_euler_angles_yxz :: proc{matrix4_from_euler_angles_yxz_f16, matrix4_from_euler_angles_yxz_f32, matrix4_from_euler_angles_yxz_f64}
|
||||
matrix4_from_euler_angles_xzx :: proc{matrix4_from_euler_angles_xzx_f16, matrix4_from_euler_angles_xzx_f32, matrix4_from_euler_angles_xzx_f64}
|
||||
matrix4_from_euler_angles_xyx :: proc{matrix4_from_euler_angles_xyx_f16, matrix4_from_euler_angles_xyx_f32, matrix4_from_euler_angles_xyx_f64}
|
||||
matrix4_from_euler_angles_yxy :: proc{matrix4_from_euler_angles_yxy_f16, matrix4_from_euler_angles_yxy_f32, matrix4_from_euler_angles_yxy_f64}
|
||||
matrix4_from_euler_angles_yzy :: proc{matrix4_from_euler_angles_yzy_f16, matrix4_from_euler_angles_yzy_f32, matrix4_from_euler_angles_yzy_f64}
|
||||
matrix4_from_euler_angles_zyz :: proc{matrix4_from_euler_angles_zyz_f16, matrix4_from_euler_angles_zyz_f32, matrix4_from_euler_angles_zyz_f64}
|
||||
matrix4_from_euler_angles_zxz :: proc{matrix4_from_euler_angles_zxz_f16, matrix4_from_euler_angles_zxz_f32, matrix4_from_euler_angles_zxz_f64}
|
||||
matrix4_from_euler_angles_xzy :: proc{matrix4_from_euler_angles_xzy_f16, matrix4_from_euler_angles_xzy_f32, matrix4_from_euler_angles_xzy_f64}
|
||||
matrix4_from_euler_angles_yzx :: proc{matrix4_from_euler_angles_yzx_f16, matrix4_from_euler_angles_yzx_f32, matrix4_from_euler_angles_yzx_f64}
|
||||
matrix4_from_euler_angles_zyx :: proc{matrix4_from_euler_angles_zyx_f16, matrix4_from_euler_angles_zyx_f32, matrix4_from_euler_angles_zyx_f64}
|
||||
matrix4_from_euler_angles_zxy :: proc{matrix4_from_euler_angles_zxy_f16, matrix4_from_euler_angles_zxy_f32, matrix4_from_euler_angles_zxy_f64}
|
||||
matrix4_from_yaw_pitch_roll :: proc{matrix4_from_yaw_pitch_roll_f16, matrix4_from_yaw_pitch_roll_f32, matrix4_from_yaw_pitch_roll_f64}
|
||||
|
||||
euler_angles_from_matrix4 :: proc{euler_angles_from_matrix4_f16, euler_angles_from_matrix4_f32, euler_angles_from_matrix4_f64};
|
||||
euler_angles_xyz_from_matrix4 :: proc{euler_angles_xyz_from_matrix4_f16, euler_angles_xyz_from_matrix4_f32, euler_angles_xyz_from_matrix4_f64};
|
||||
euler_angles_yxz_from_matrix4 :: proc{euler_angles_yxz_from_matrix4_f16, euler_angles_yxz_from_matrix4_f32, euler_angles_yxz_from_matrix4_f64};
|
||||
euler_angles_xzx_from_matrix4 :: proc{euler_angles_xzx_from_matrix4_f16, euler_angles_xzx_from_matrix4_f32, euler_angles_xzx_from_matrix4_f64};
|
||||
euler_angles_xyx_from_matrix4 :: proc{euler_angles_xyx_from_matrix4_f16, euler_angles_xyx_from_matrix4_f32, euler_angles_xyx_from_matrix4_f64};
|
||||
euler_angles_yxy_from_matrix4 :: proc{euler_angles_yxy_from_matrix4_f16, euler_angles_yxy_from_matrix4_f32, euler_angles_yxy_from_matrix4_f64};
|
||||
euler_angles_yzy_from_matrix4 :: proc{euler_angles_yzy_from_matrix4_f16, euler_angles_yzy_from_matrix4_f32, euler_angles_yzy_from_matrix4_f64};
|
||||
euler_angles_zyz_from_matrix4 :: proc{euler_angles_zyz_from_matrix4_f16, euler_angles_zyz_from_matrix4_f32, euler_angles_zyz_from_matrix4_f64};
|
||||
euler_angles_zxz_from_matrix4 :: proc{euler_angles_zxz_from_matrix4_f16, euler_angles_zxz_from_matrix4_f32, euler_angles_zxz_from_matrix4_f64};
|
||||
euler_angles_xzy_from_matrix4 :: proc{euler_angles_xzy_from_matrix4_f16, euler_angles_xzy_from_matrix4_f32, euler_angles_xzy_from_matrix4_f64};
|
||||
euler_angles_yzx_from_matrix4 :: proc{euler_angles_yzx_from_matrix4_f16, euler_angles_yzx_from_matrix4_f32, euler_angles_yzx_from_matrix4_f64};
|
||||
euler_angles_zyx_from_matrix4 :: proc{euler_angles_zyx_from_matrix4_f16, euler_angles_zyx_from_matrix4_f32, euler_angles_zyx_from_matrix4_f64};
|
||||
euler_angles_zxy_from_matrix4 :: proc{euler_angles_zxy_from_matrix4_f16, euler_angles_zxy_from_matrix4_f32, euler_angles_zxy_from_matrix4_f64};
|
||||
euler_angles_from_matrix4 :: proc{euler_angles_from_matrix4_f16, euler_angles_from_matrix4_f32, euler_angles_from_matrix4_f64}
|
||||
euler_angles_xyz_from_matrix4 :: proc{euler_angles_xyz_from_matrix4_f16, euler_angles_xyz_from_matrix4_f32, euler_angles_xyz_from_matrix4_f64}
|
||||
euler_angles_yxz_from_matrix4 :: proc{euler_angles_yxz_from_matrix4_f16, euler_angles_yxz_from_matrix4_f32, euler_angles_yxz_from_matrix4_f64}
|
||||
euler_angles_xzx_from_matrix4 :: proc{euler_angles_xzx_from_matrix4_f16, euler_angles_xzx_from_matrix4_f32, euler_angles_xzx_from_matrix4_f64}
|
||||
euler_angles_xyx_from_matrix4 :: proc{euler_angles_xyx_from_matrix4_f16, euler_angles_xyx_from_matrix4_f32, euler_angles_xyx_from_matrix4_f64}
|
||||
euler_angles_yxy_from_matrix4 :: proc{euler_angles_yxy_from_matrix4_f16, euler_angles_yxy_from_matrix4_f32, euler_angles_yxy_from_matrix4_f64}
|
||||
euler_angles_yzy_from_matrix4 :: proc{euler_angles_yzy_from_matrix4_f16, euler_angles_yzy_from_matrix4_f32, euler_angles_yzy_from_matrix4_f64}
|
||||
euler_angles_zyz_from_matrix4 :: proc{euler_angles_zyz_from_matrix4_f16, euler_angles_zyz_from_matrix4_f32, euler_angles_zyz_from_matrix4_f64}
|
||||
euler_angles_zxz_from_matrix4 :: proc{euler_angles_zxz_from_matrix4_f16, euler_angles_zxz_from_matrix4_f32, euler_angles_zxz_from_matrix4_f64}
|
||||
euler_angles_xzy_from_matrix4 :: proc{euler_angles_xzy_from_matrix4_f16, euler_angles_xzy_from_matrix4_f32, euler_angles_xzy_from_matrix4_f64}
|
||||
euler_angles_yzx_from_matrix4 :: proc{euler_angles_yzx_from_matrix4_f16, euler_angles_yzx_from_matrix4_f32, euler_angles_yzx_from_matrix4_f64}
|
||||
euler_angles_zyx_from_matrix4 :: proc{euler_angles_zyx_from_matrix4_f16, euler_angles_zyx_from_matrix4_f32, euler_angles_zyx_from_matrix4_f64}
|
||||
euler_angles_zxy_from_matrix4 :: proc{euler_angles_zxy_from_matrix4_f16, euler_angles_zxy_from_matrix4_f32, euler_angles_zxy_from_matrix4_f64}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -33,110 +33,110 @@ Vector4_Components :: enum u8 {
|
||||
}
|
||||
|
||||
scalar_f32_swizzle1 :: proc(f: f32, c0: Scalar_Components) -> f32 {
|
||||
return f;
|
||||
return f
|
||||
}
|
||||
scalar_f32_swizzle2 :: proc(f: f32, c0, c1: Scalar_Components) -> Vector2f32 {
|
||||
return {f, f};
|
||||
return {f, f}
|
||||
}
|
||||
scalar_f32_swizzle3 :: proc(f: f32, c0, c1, c2: Scalar_Components) -> Vector3f32 {
|
||||
return {f, f, f};
|
||||
return {f, f, f}
|
||||
}
|
||||
scalar_f32_swizzle4 :: proc(f: f32, c0, c1, c2, c3: Scalar_Components) -> Vector4f32 {
|
||||
return {f, f, f, f};
|
||||
return {f, f, f, f}
|
||||
}
|
||||
|
||||
vector2f32_swizzle1 :: proc(v: Vector2f32, c0: Vector2_Components) -> f32 {
|
||||
return v[c0];
|
||||
return v[c0]
|
||||
}
|
||||
vector2f32_swizzle2 :: proc(v: Vector2f32, c0, c1: Vector2_Components) -> Vector2f32 {
|
||||
return {v[c0], v[c1]};
|
||||
return {v[c0], v[c1]}
|
||||
}
|
||||
vector2f32_swizzle3 :: proc(v: Vector2f32, c0, c1, c2: Vector2_Components) -> Vector3f32 {
|
||||
return {v[c0], v[c1], v[c2]};
|
||||
return {v[c0], v[c1], v[c2]}
|
||||
}
|
||||
vector2f32_swizzle4 :: proc(v: Vector2f32, c0, c1, c2, c3: Vector2_Components) -> Vector4f32 {
|
||||
return {v[c0], v[c1], v[c2], v[c3]};
|
||||
return {v[c0], v[c1], v[c2], v[c3]}
|
||||
}
|
||||
|
||||
|
||||
vector3f32_swizzle1 :: proc(v: Vector3f32, c0: Vector3_Components) -> f32 {
|
||||
return v[c0];
|
||||
return v[c0]
|
||||
}
|
||||
vector3f32_swizzle2 :: proc(v: Vector3f32, c0, c1: Vector3_Components) -> Vector2f32 {
|
||||
return {v[c0], v[c1]};
|
||||
return {v[c0], v[c1]}
|
||||
}
|
||||
vector3f32_swizzle3 :: proc(v: Vector3f32, c0, c1, c2: Vector3_Components) -> Vector3f32 {
|
||||
return {v[c0], v[c1], v[c2]};
|
||||
return {v[c0], v[c1], v[c2]}
|
||||
}
|
||||
vector3f32_swizzle4 :: proc(v: Vector3f32, c0, c1, c2, c3: Vector3_Components) -> Vector4f32 {
|
||||
return {v[c0], v[c1], v[c2], v[c3]};
|
||||
return {v[c0], v[c1], v[c2], v[c3]}
|
||||
}
|
||||
|
||||
vector4f32_swizzle1 :: proc(v: Vector4f32, c0: Vector4_Components) -> f32 {
|
||||
return v[c0];
|
||||
return v[c0]
|
||||
}
|
||||
vector4f32_swizzle2 :: proc(v: Vector4f32, c0, c1: Vector4_Components) -> Vector2f32 {
|
||||
return {v[c0], v[c1]};
|
||||
return {v[c0], v[c1]}
|
||||
}
|
||||
vector4f32_swizzle3 :: proc(v: Vector4f32, c0, c1, c2: Vector4_Components) -> Vector3f32 {
|
||||
return {v[c0], v[c1], v[c2]};
|
||||
return {v[c0], v[c1], v[c2]}
|
||||
}
|
||||
vector4f32_swizzle4 :: proc(v: Vector4f32, c0, c1, c2, c3: Vector4_Components) -> Vector4f32 {
|
||||
return {v[c0], v[c1], v[c2], v[c3]};
|
||||
return {v[c0], v[c1], v[c2], v[c3]}
|
||||
}
|
||||
|
||||
|
||||
scalar_f64_swizzle1 :: proc(f: f64, c0: Scalar_Components) -> f64 {
|
||||
return f;
|
||||
return f
|
||||
}
|
||||
scalar_f64_swizzle2 :: proc(f: f64, c0, c1: Scalar_Components) -> Vector2f64 {
|
||||
return {f, f};
|
||||
return {f, f}
|
||||
}
|
||||
scalar_f64_swizzle3 :: proc(f: f64, c0, c1, c2: Scalar_Components) -> Vector3f64 {
|
||||
return {f, f, f};
|
||||
return {f, f, f}
|
||||
}
|
||||
scalar_f64_swizzle4 :: proc(f: f64, c0, c1, c2, c3: Scalar_Components) -> Vector4f64 {
|
||||
return {f, f, f, f};
|
||||
return {f, f, f, f}
|
||||
}
|
||||
|
||||
vector2f64_swizzle1 :: proc(v: Vector2f64, c0: Vector2_Components) -> f64 {
|
||||
return v[c0];
|
||||
return v[c0]
|
||||
}
|
||||
vector2f64_swizzle2 :: proc(v: Vector2f64, c0, c1: Vector2_Components) -> Vector2f64 {
|
||||
return {v[c0], v[c1]};
|
||||
return {v[c0], v[c1]}
|
||||
}
|
||||
vector2f64_swizzle3 :: proc(v: Vector2f64, c0, c1, c2: Vector2_Components) -> Vector3f64 {
|
||||
return {v[c0], v[c1], v[c2]};
|
||||
return {v[c0], v[c1], v[c2]}
|
||||
}
|
||||
vector2f64_swizzle4 :: proc(v: Vector2f64, c0, c1, c2, c3: Vector2_Components) -> Vector4f64 {
|
||||
return {v[c0], v[c1], v[c2], v[c3]};
|
||||
return {v[c0], v[c1], v[c2], v[c3]}
|
||||
}
|
||||
|
||||
|
||||
vector3f64_swizzle1 :: proc(v: Vector3f64, c0: Vector3_Components) -> f64 {
|
||||
return v[c0];
|
||||
return v[c0]
|
||||
}
|
||||
vector3f64_swizzle2 :: proc(v: Vector3f64, c0, c1: Vector3_Components) -> Vector2f64 {
|
||||
return {v[c0], v[c1]};
|
||||
return {v[c0], v[c1]}
|
||||
}
|
||||
vector3f64_swizzle3 :: proc(v: Vector3f64, c0, c1, c2: Vector3_Components) -> Vector3f64 {
|
||||
return {v[c0], v[c1], v[c2]};
|
||||
return {v[c0], v[c1], v[c2]}
|
||||
}
|
||||
vector3f64_swizzle4 :: proc(v: Vector3f64, c0, c1, c2, c3: Vector3_Components) -> Vector4f64 {
|
||||
return {v[c0], v[c1], v[c2], v[c3]};
|
||||
return {v[c0], v[c1], v[c2], v[c3]}
|
||||
}
|
||||
|
||||
vector4f64_swizzle1 :: proc(v: Vector4f64, c0: Vector4_Components) -> f64 {
|
||||
return v[c0];
|
||||
return v[c0]
|
||||
}
|
||||
vector4f64_swizzle2 :: proc(v: Vector4f64, c0, c1: Vector4_Components) -> Vector2f64 {
|
||||
return {v[c0], v[c1]};
|
||||
return {v[c0], v[c1]}
|
||||
}
|
||||
vector4f64_swizzle3 :: proc(v: Vector4f64, c0, c1, c2: Vector4_Components) -> Vector3f64 {
|
||||
return {v[c0], v[c1], v[c2]};
|
||||
return {v[c0], v[c1], v[c2]}
|
||||
}
|
||||
vector4f64_swizzle4 :: proc(v: Vector4f64, c0, c1, c2, c3: Vector4_Components) -> Vector4f64 {
|
||||
return {v[c0], v[c1], v[c2], v[c3]};
|
||||
return {v[c0], v[c1], v[c2], v[c3]}
|
||||
}
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ scalar_swizzle :: proc{
|
||||
scalar_f64_swizzle2,
|
||||
scalar_f64_swizzle3,
|
||||
scalar_f64_swizzle4,
|
||||
};
|
||||
}
|
||||
|
||||
vector2_swizzle :: proc{
|
||||
vector2f32_swizzle1,
|
||||
@@ -162,7 +162,7 @@ vector2_swizzle :: proc{
|
||||
vector2f64_swizzle2,
|
||||
vector2f64_swizzle3,
|
||||
vector2f64_swizzle4,
|
||||
};
|
||||
}
|
||||
|
||||
vector3_swizzle :: proc{
|
||||
vector3f32_swizzle1,
|
||||
@@ -173,7 +173,7 @@ vector3_swizzle :: proc{
|
||||
vector3f64_swizzle2,
|
||||
vector3f64_swizzle3,
|
||||
vector3f64_swizzle4,
|
||||
};
|
||||
}
|
||||
|
||||
vector4_swizzle :: proc{
|
||||
vector4f32_swizzle1,
|
||||
@@ -184,7 +184,7 @@ vector4_swizzle :: proc{
|
||||
vector4f64_swizzle2,
|
||||
vector4f64_swizzle3,
|
||||
vector4f64_swizzle4,
|
||||
};
|
||||
}
|
||||
|
||||
swizzle :: proc{
|
||||
scalar_f32_swizzle1,
|
||||
@@ -219,4 +219,4 @@ swizzle :: proc{
|
||||
vector4f64_swizzle2,
|
||||
vector4f64_swizzle3,
|
||||
vector4f64_swizzle4,
|
||||
};
|
||||
}
|
||||
|
||||
+460
-460
File diff suppressed because it is too large
Load Diff
+16
-16
@@ -18,7 +18,7 @@ import "core:math"
|
||||
// sample = norm_float64() * std_dev + mean
|
||||
//
|
||||
norm_float64 :: proc(r: ^Rand = nil) -> f64 {
|
||||
rn :: 3.442619855899;
|
||||
rn :: 3.442619855899
|
||||
|
||||
@(static)
|
||||
kn := [128]u32{
|
||||
@@ -48,7 +48,7 @@ norm_float64 :: proc(r: ^Rand = nil) -> f64 {
|
||||
0x7e3b737a, 0x7e268c2f, 0x7e0e3ff5, 0x7df1aa5d, 0x7dcf8c72,
|
||||
0x7da61a1e, 0x7d72a0fb, 0x7d30e097, 0x7cd9b4ab, 0x7c600f1a,
|
||||
0x7ba90bdc, 0x7a722176, 0x77d664e5,
|
||||
};
|
||||
}
|
||||
|
||||
@(static)
|
||||
wn := [128]f32{
|
||||
@@ -84,7 +84,7 @@ norm_float64 :: proc(r: ^Rand = nil) -> f64 {
|
||||
1.1781276e-09, 1.1962995e-09, 1.2158287e-09, 1.2369856e-09,
|
||||
1.2601323e-09, 1.2857697e-09, 1.3146202e-09, 1.347784e-09,
|
||||
1.3870636e-09, 1.4357403e-09, 1.5008659e-09, 1.6030948e-09,
|
||||
};
|
||||
}
|
||||
|
||||
@(static)
|
||||
fn := [128]f32{
|
||||
@@ -114,39 +114,39 @@ norm_float64 :: proc(r: ^Rand = nil) -> f64 {
|
||||
0.044660863, 0.040742867, 0.03688439, 0.033087887, 0.029356318,
|
||||
0.025693292, 0.022103304, 0.018592102, 0.015167298, 0.011839478,
|
||||
0.008624485, 0.005548995, 0.0026696292,
|
||||
};
|
||||
}
|
||||
|
||||
r := r;
|
||||
r := r
|
||||
if r == nil {
|
||||
// NOTE(bill, 2020-09-07): Do this so that people can
|
||||
// enforce the global random state if necessary with `nil`
|
||||
r = &global_rand;
|
||||
r = &global_rand
|
||||
}
|
||||
|
||||
for {
|
||||
j := i32(uint32(r));
|
||||
i := j & 0x7f;
|
||||
x := f64(j) * f64(wn[i]);
|
||||
j := i32(uint32(r))
|
||||
i := j & 0x7f
|
||||
x := f64(j) * f64(wn[i])
|
||||
if u32(abs(j)) < kn[i] {
|
||||
// 99% of the time this will be hit
|
||||
return x;
|
||||
return x
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
for {
|
||||
x = -math.ln(float64(r)) * (1.0/ rn);
|
||||
y := -math.ln(float64(r));
|
||||
x = -math.ln(float64(r)) * (1.0/ rn)
|
||||
y := -math.ln(float64(r))
|
||||
if y+y >= x*x {
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
return j > 0 ? rn + x : -rn - x;
|
||||
return j > 0 ? rn + x : -rn - x
|
||||
}
|
||||
if fn[i]+f32(float64(r))*(fn[i-1]-fn[i]) < f32(math.exp(-0.5*x*x)) {
|
||||
return x;
|
||||
return x
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // NOTE(bill): Will never be hit but this is here for sanity's sake
|
||||
return 0 // NOTE(bill): Will never be hit but this is here for sanity's sake
|
||||
}
|
||||
|
||||
|
||||
+64
-64
@@ -7,56 +7,56 @@ Rand :: struct {
|
||||
|
||||
|
||||
@(private)
|
||||
_GLOBAL_SEED_DATA := 1234567890;
|
||||
_GLOBAL_SEED_DATA := 1234567890
|
||||
@(private)
|
||||
global_rand := create(u64(uintptr(&_GLOBAL_SEED_DATA)));
|
||||
global_rand := create(u64(uintptr(&_GLOBAL_SEED_DATA)))
|
||||
|
||||
set_global_seed :: proc(seed: u64) {
|
||||
init(&global_rand, seed);
|
||||
init(&global_rand, seed)
|
||||
}
|
||||
|
||||
create :: proc(seed: u64) -> Rand {
|
||||
r: Rand;
|
||||
init(&r, seed);
|
||||
return r;
|
||||
r: Rand
|
||||
init(&r, seed)
|
||||
return r
|
||||
}
|
||||
|
||||
init :: proc(r: ^Rand, seed: u64) {
|
||||
r.state = 0;
|
||||
r.inc = (seed << 1) | 1;
|
||||
_random(r);
|
||||
r.state += seed;
|
||||
_random(r);
|
||||
r.state = 0
|
||||
r.inc = (seed << 1) | 1
|
||||
_random(r)
|
||||
r.state += seed
|
||||
_random(r)
|
||||
}
|
||||
|
||||
_random :: proc(r: ^Rand) -> u32 {
|
||||
r := r;
|
||||
r := r
|
||||
if r == nil {
|
||||
// NOTE(bill, 2020-09-07): Do this so that people can
|
||||
// enforce the global random state if necessary with `nil`
|
||||
r = &global_rand;
|
||||
r = &global_rand
|
||||
}
|
||||
old_state := r.state;
|
||||
r.state = old_state * 6364136223846793005 + (r.inc|1);
|
||||
xor_shifted := u32(((old_state>>18) ~ old_state) >> 27);
|
||||
rot := u32(old_state >> 59);
|
||||
return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 31));
|
||||
old_state := r.state
|
||||
r.state = old_state * 6364136223846793005 + (r.inc|1)
|
||||
xor_shifted := u32(((old_state>>18) ~ old_state) >> 27)
|
||||
rot := u32(old_state >> 59)
|
||||
return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 31))
|
||||
}
|
||||
|
||||
uint32 :: proc(r: ^Rand = nil) -> u32 { return _random(r); }
|
||||
|
||||
uint64 :: proc(r: ^Rand = nil) -> u64 {
|
||||
a := u64(_random(r));
|
||||
b := u64(_random(r));
|
||||
return (a<<32) | b;
|
||||
a := u64(_random(r))
|
||||
b := u64(_random(r))
|
||||
return (a<<32) | b
|
||||
}
|
||||
|
||||
uint128 :: proc(r: ^Rand = nil) -> u128 {
|
||||
a := u128(_random(r));
|
||||
b := u128(_random(r));
|
||||
c := u128(_random(r));
|
||||
d := u128(_random(r));
|
||||
return (a<<96) | (b<<64) | (c<<32) | d;
|
||||
a := u128(_random(r))
|
||||
b := u128(_random(r))
|
||||
c := u128(_random(r))
|
||||
d := u128(_random(r))
|
||||
return (a<<96) | (b<<64) | (c<<32) | d
|
||||
}
|
||||
|
||||
int31 :: proc(r: ^Rand = nil) -> i32 { return i32(uint32(r) << 1 >> 1); }
|
||||
@@ -65,57 +65,57 @@ int127 :: proc(r: ^Rand = nil) -> i128 { return i128(uint128(r) << 1 >> 1); }
|
||||
|
||||
int31_max :: proc(n: i32, r: ^Rand = nil) -> i32 {
|
||||
if n <= 0 {
|
||||
panic("Invalid argument to int31_max");
|
||||
panic("Invalid argument to int31_max")
|
||||
}
|
||||
if n&(n-1) == 0 {
|
||||
return int31(r) & (n-1);
|
||||
return int31(r) & (n-1)
|
||||
}
|
||||
max := i32((1<<31) - 1 - (1<<31)&u32(n));
|
||||
v := int31(r);
|
||||
max := i32((1<<31) - 1 - (1<<31)&u32(n))
|
||||
v := int31(r)
|
||||
for v > max {
|
||||
v = int31(r);
|
||||
v = int31(r)
|
||||
}
|
||||
return v % n;
|
||||
return v % n
|
||||
}
|
||||
|
||||
int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 {
|
||||
if n <= 0 {
|
||||
panic("Invalid argument to int63_max");
|
||||
panic("Invalid argument to int63_max")
|
||||
}
|
||||
if n&(n-1) == 0 {
|
||||
return int63(r) & (n-1);
|
||||
return int63(r) & (n-1)
|
||||
}
|
||||
max := i64((1<<63) - 1 - (1<<63)&u64(n));
|
||||
v := int63(r);
|
||||
max := i64((1<<63) - 1 - (1<<63)&u64(n))
|
||||
v := int63(r)
|
||||
for v > max {
|
||||
v = int63(r);
|
||||
v = int63(r)
|
||||
}
|
||||
return v % n;
|
||||
return v % n
|
||||
}
|
||||
|
||||
int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 {
|
||||
if n <= 0 {
|
||||
panic("Invalid argument to int127_max");
|
||||
panic("Invalid argument to int127_max")
|
||||
}
|
||||
if n&(n-1) == 0 {
|
||||
return int127(r) & (n-1);
|
||||
return int127(r) & (n-1)
|
||||
}
|
||||
max := i128((1<<63) - 1 - (1<<63)&u128(n));
|
||||
v := int127(r);
|
||||
max := i128((1<<63) - 1 - (1<<63)&u128(n))
|
||||
v := int127(r)
|
||||
for v > max {
|
||||
v = int127(r);
|
||||
v = int127(r)
|
||||
}
|
||||
return v % n;
|
||||
return v % n
|
||||
}
|
||||
|
||||
int_max :: proc(n: int, r: ^Rand = nil) -> int {
|
||||
if n <= 0 {
|
||||
panic("Invalid argument to int_max");
|
||||
panic("Invalid argument to int_max")
|
||||
}
|
||||
when size_of(int) == 4 {
|
||||
return int(int31_max(i32(n), r));
|
||||
return int(int31_max(i32(n), r))
|
||||
} else {
|
||||
return int(int63_max(i64(n), r));
|
||||
return int(int63_max(i64(n), r))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,40 +127,40 @@ float32_range :: proc(lo, hi: f32, r: ^Rand = nil) -> f32 { return (hi-lo)*float
|
||||
|
||||
|
||||
read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) {
|
||||
pos := i8(0);
|
||||
val := i64(0);
|
||||
pos := i8(0)
|
||||
val := i64(0)
|
||||
for n = 0; n < len(p); n += 1 {
|
||||
if pos == 0 {
|
||||
val = int63(r);
|
||||
pos = 7;
|
||||
val = int63(r)
|
||||
pos = 7
|
||||
}
|
||||
p[n] = byte(val);
|
||||
val >>= 8;
|
||||
pos -= 1;
|
||||
p[n] = byte(val)
|
||||
val >>= 8
|
||||
pos -= 1
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
// perm returns a slice of n ints in a pseudo-random permutation of integers in the range [0, n)
|
||||
perm :: proc(n: int, r: ^Rand = nil) -> []int {
|
||||
m := make([]int, n);
|
||||
m := make([]int, n)
|
||||
for i := 0; i < n; i += 1 {
|
||||
j := int_max(i+1, r);
|
||||
m[i] = m[j];
|
||||
m[j] = i;
|
||||
j := int_max(i+1, r)
|
||||
m[i] = m[j]
|
||||
m[j] = i
|
||||
}
|
||||
return m;
|
||||
return m
|
||||
}
|
||||
|
||||
|
||||
shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) {
|
||||
n := i64(len(array));
|
||||
n := i64(len(array))
|
||||
if n < 2 {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
for i := i64(0); i < n; i += 1 {
|
||||
j := int63_max(n, r);
|
||||
array[i], array[j] = array[j], array[i];
|
||||
j := int63_max(n, r)
|
||||
array[i], array[j] = array[j], array[i]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user