mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 23:58:50 +00:00
big: Split up int_is_* comparison tests.
This commit is contained in:
+46
-152
@@ -9,199 +9,93 @@ package big
|
||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||
|
||||
This file contains various comparison routines.
|
||||
|
||||
We essentially just check if params are initialized before punting to the `internal_*` versions.
|
||||
This has the side benefit of being able to add additional characteristics to numbers, like NaN,
|
||||
and keep support for that contained.
|
||||
*/
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:mem"
|
||||
|
||||
int_is_initialized :: proc(a: ^Int) -> bool {
|
||||
if a == nil {
|
||||
return false;
|
||||
}
|
||||
raw := transmute(mem.Raw_Dynamic_Array)a.digit;
|
||||
return raw.cap >= _MIN_DIGIT_COUNT;
|
||||
if a == nil { return false; }
|
||||
|
||||
return #force_inline internal_int_is_initialized(a);
|
||||
}
|
||||
|
||||
int_is_zero :: proc(a: ^Int) -> (res: bool, err: Error) {
|
||||
if err = clear_if_uninitialized(a); err != nil {
|
||||
return false, err;
|
||||
}
|
||||
return a.used == 0, nil;
|
||||
int_is_zero :: proc(a: ^Int) -> (zero: bool, err: Error) {
|
||||
if a == nil { return false, .Invalid_Pointer; }
|
||||
if err = clear_if_uninitialized(a); err != nil { return false, err; }
|
||||
|
||||
return #force_inline internal_is_zero(a), nil;
|
||||
}
|
||||
|
||||
int_is_positive :: proc(a: ^Int) -> (res: bool, err: Error) {
|
||||
if err = clear_if_uninitialized(a); err != nil {
|
||||
return false, err;
|
||||
}
|
||||
return a.sign == .Zero_or_Positive, nil;
|
||||
int_is_positive :: proc(a: ^Int) -> (positive: bool, err: Error) {
|
||||
if a == nil { return false, .Invalid_Pointer; }
|
||||
if err = clear_if_uninitialized(a); err != nil { return false, err; }
|
||||
|
||||
return #force_inline internal_is_positive(a), nil;
|
||||
}
|
||||
|
||||
int_is_negative :: proc(a: ^Int) -> (res: bool, err: Error) {
|
||||
if err = clear_if_uninitialized(a); err != nil {
|
||||
return false, err;
|
||||
}
|
||||
return a.sign == .Negative, nil;
|
||||
int_is_negative :: proc(a: ^Int) -> (negative: bool, err: Error) {
|
||||
if a == nil { return false, .Invalid_Pointer; }
|
||||
if err = clear_if_uninitialized(a); err != nil { return false, err; }
|
||||
|
||||
return #force_inline internal_is_negative(a), nil;
|
||||
}
|
||||
|
||||
int_is_even :: proc(a: ^Int) -> (res: bool, err: Error) {
|
||||
if err = clear_if_uninitialized(a); err != nil {
|
||||
return false, err;
|
||||
}
|
||||
int_is_even :: proc(a: ^Int) -> (even: bool, err: Error) {
|
||||
if a == nil { return false, .Invalid_Pointer; }
|
||||
if err = clear_if_uninitialized(a); err != nil { return false, err; }
|
||||
|
||||
res, err = is_zero(a);
|
||||
if err != nil {
|
||||
return false, err;
|
||||
} else if res == true {
|
||||
return true, nil;
|
||||
}
|
||||
|
||||
res = false;
|
||||
if a.used > 0 && a.digit[0] & 1 == 0 {
|
||||
res = true;
|
||||
}
|
||||
return res, nil;
|
||||
return #force_inline internal_is_even(a), nil;
|
||||
}
|
||||
|
||||
int_is_odd :: proc(a: ^Int) -> (res: bool, err: Error) {
|
||||
if err = clear_if_uninitialized(a); err != nil {
|
||||
return false, err;
|
||||
}
|
||||
int_is_odd :: proc(a: ^Int) -> (odd: bool, err: Error) {
|
||||
if a == nil { return false, .Invalid_Pointer; }
|
||||
if err = clear_if_uninitialized(a); err != nil { return false, err; }
|
||||
|
||||
res, err = is_even(a);
|
||||
return !res, err;
|
||||
return #force_inline internal_is_odd(a), nil;
|
||||
}
|
||||
|
||||
platform_int_is_power_of_two :: proc(a: int) -> bool {
|
||||
platform_int_is_power_of_two :: #force_inline proc(a: int) -> bool {
|
||||
return ((a) != 0) && (((a) & ((a) - 1)) == 0);
|
||||
}
|
||||
|
||||
int_is_power_of_two :: proc(a: ^Int) -> (res: bool, err: Error) {
|
||||
if err = clear_if_uninitialized(a); err != nil {
|
||||
return false, err;
|
||||
}
|
||||
if a == nil { return false, .Invalid_Pointer; }
|
||||
if err = clear_if_uninitialized(a); err != nil { return false, err; }
|
||||
|
||||
/*
|
||||
Early out for Int == 0.
|
||||
*/
|
||||
if a.used == 0 {
|
||||
return false, nil;
|
||||
}
|
||||
|
||||
/*
|
||||
For an `Int` to be a power of two, its top limb has to be a power of two.
|
||||
*/
|
||||
if !platform_int_is_power_of_two(int(a.digit[a.used - 1])) {
|
||||
return false, nil;
|
||||
}
|
||||
|
||||
/*
|
||||
That was the only limb, so it's a power of two.
|
||||
*/
|
||||
if a.used == 1 {
|
||||
return true, nil;
|
||||
}
|
||||
|
||||
/*
|
||||
For an Int to be a power of two, all limbs except the top one have to be zero.
|
||||
*/
|
||||
for i := 1; i < a.used; i += 1 {
|
||||
if a.digit[i - 1] != 0 {
|
||||
return false, nil;
|
||||
}
|
||||
}
|
||||
return true, nil;
|
||||
return #force_inline internal_is_power_of_two(a), nil;
|
||||
}
|
||||
|
||||
/*
|
||||
Compare two `Int`s, signed.
|
||||
*/
|
||||
int_compare :: proc(a, b: ^Int) -> (res: int, err: Error) {
|
||||
if err = clear_if_uninitialized(a); err != nil {
|
||||
return 0, err;
|
||||
}
|
||||
if err = clear_if_uninitialized(b); err != nil {
|
||||
return 0, err;
|
||||
}
|
||||
int_compare :: proc(a, b: ^Int) -> (comparison: int, err: Error) {
|
||||
if a == nil || b == nil { return 0, .Invalid_Pointer; }
|
||||
if err = clear_if_uninitialized(a, b); err != nil { return 0, err; }
|
||||
|
||||
neg: bool;
|
||||
if neg, err = is_negative(a); err != nil {
|
||||
return 0, err;
|
||||
}
|
||||
|
||||
/* Compare based on sign */
|
||||
if a.sign != b.sign {
|
||||
res = -1 if neg else +1;
|
||||
return res, nil;
|
||||
}
|
||||
|
||||
/* If negative, compare in the opposite direction */
|
||||
if neg {
|
||||
return cmp_mag(b, a);
|
||||
}
|
||||
return cmp_mag(a, b);
|
||||
return #force_inline internal_cmp(a, b), nil;
|
||||
}
|
||||
int_cmp :: int_compare;
|
||||
|
||||
/*
|
||||
Compare an `Int` to an unsigned number upto the size of the backing type.
|
||||
*/
|
||||
int_compare_digit :: proc(a: ^Int, u: DIGIT) -> (res: int, err: Error) {
|
||||
if err = clear_if_uninitialized(a); err != nil {
|
||||
return 0, err;
|
||||
}
|
||||
int_compare_digit :: proc(a: ^Int, b: DIGIT) -> (comparison: int, err: Error) {
|
||||
if a == nil { return 0, .Invalid_Pointer; }
|
||||
if err = clear_if_uninitialized(a); err != nil { return 0, err; }
|
||||
|
||||
/* Compare based on sign */
|
||||
neg: bool;
|
||||
if neg, err = is_neg(a); err != nil {
|
||||
return 0, err;
|
||||
}
|
||||
if neg {
|
||||
return -1, nil;
|
||||
}
|
||||
|
||||
/* Compare based on magnitude */
|
||||
if a.used > 1 {
|
||||
return +1, nil;
|
||||
}
|
||||
|
||||
/* Compare the only digit in `a` to `u`. */
|
||||
if a.digit[0] != u {
|
||||
if a.digit[0] > u {
|
||||
return +1, nil;
|
||||
}
|
||||
return -1, nil;
|
||||
}
|
||||
|
||||
return 0, nil;
|
||||
return #force_inline internal_cmp_digit(a, b), nil;
|
||||
}
|
||||
|
||||
/*
|
||||
Compare the magnitude of two `Int`s, unsigned.
|
||||
*/
|
||||
int_compare_magnitude :: proc(a, b: ^Int) -> (res: int, err: Error) {
|
||||
if err = clear_if_uninitialized(a); err != nil {
|
||||
return 0, err;
|
||||
}
|
||||
if err = clear_if_uninitialized(b); err != nil {
|
||||
return 0, err;
|
||||
}
|
||||
if a == nil || b == nil { return 0, .Invalid_Pointer; }
|
||||
if err = clear_if_uninitialized(a, b); err != nil { return 0, err; }
|
||||
|
||||
/* Compare based on used digits */
|
||||
if a.used != b.used {
|
||||
if a.used > b.used {
|
||||
return +1, nil;
|
||||
}
|
||||
return -1, nil;
|
||||
}
|
||||
|
||||
/* Same number of used digits, compare based on their value */
|
||||
for n := a.used - 1; n >= 0; n -= 1 {
|
||||
if a.digit[n] != b.digit[n] {
|
||||
if a.digit[n] > b.digit[n] {
|
||||
return +1, nil;
|
||||
}
|
||||
return -1, nil;
|
||||
}
|
||||
}
|
||||
|
||||
return 0, nil;
|
||||
return #force_inline internal_cmp_mag(a, b), nil;
|
||||
}
|
||||
Reference in New Issue
Block a user