Remove unneeded semicolons from the core library

This commit is contained in:
gingerBill
2021-08-31 22:21:13 +01:00
parent b176af2742
commit 251da264ed
187 changed files with 27227 additions and 27227 deletions
+16 -16
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
}
}
File diff suppressed because it is too large Load Diff
+45 -45
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+175 -175
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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); }
File diff suppressed because it is too large Load Diff
+100 -100
View File
@@ -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
+37 -37
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -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
View File
@@ -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]
}
}