From 78c0877994427d1c215c00a0623ce4d9a0bfb542 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 22 Jul 2021 17:21:39 +0200 Subject: [PATCH] big: Add `get(a, type)` and `get_float`. --- core/math/big/common.odin | 7 --- core/math/big/example.odin | 14 ++--- core/math/big/helpers.odin | 114 +++++++++++++++++++++++++++++++------ 3 files changed, 105 insertions(+), 30 deletions(-) diff --git a/core/math/big/common.odin b/core/math/big/common.odin index bcbfafaef..c8e219927 100644 --- a/core/math/big/common.odin +++ b/core/math/big/common.odin @@ -35,13 +35,6 @@ _DEFAULT_SQR_KARATSUBA_CUTOFF :: 120; _DEFAULT_MUL_TOOM_CUTOFF :: 350; _DEFAULT_SQR_TOOM_CUTOFF :: 400; -/* - TODO(Jeroen): Decide whether to turn `Sign` into `Flags :: bit_set{Flag; u8}`. - This would hold the sign and float class, as appropriate, and would allow us - to set an `Int` to +/- Inf, or NaN. - - The operations would need to be updated to propagate these as expected. -*/ Sign :: enum u8 { Zero_or_Positive = 0, Negative = 1, diff --git a/core/math/big/example.odin b/core/math/big/example.odin index 380d1423b..014e19af6 100644 --- a/core/math/big/example.odin +++ b/core/math/big/example.odin @@ -57,16 +57,16 @@ demo :: proc() { a, b, c := &Int{}, &Int{}, &Int{}; defer destroy(a, b, c); - err = set(a, 512); + err = set(a, 0); + a.used = 2; + a.digit[1] = 1; err = set(b, 1); - for x := 0; x < 11; x += 1 { - err = shl1(b, b); - print("b", b, 16); - } - fmt.println(); err = set(c, -4); - print("a", a, 10); + fmt.printf("%v (%v)\n", int_get_float(a)); + + + print("a", a, 16); print("b", b, 10); print("c", c, 10); diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index 471c501b2..a991ec9b0 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -309,8 +309,6 @@ int_minus_one :: proc(a: ^Int, minimize := false, allocator := context.allocator } minus_one :: proc { int_minus_one, }; - - power_of_two :: proc(a: ^Int, power: int) -> (err: Error) { /* Check that `a` is usable. @@ -339,7 +337,91 @@ power_of_two :: proc(a: ^Int, power: int) -> (err: Error) { Set the bit. */ a.digit[power / _DIGIT_BITS] = 1 << uint((power % _DIGIT_BITS)); - return .None; + return .None; +} + +int_get_u128 :: proc(a: ^Int) -> (res: u128, err: Error) { + return int_get(a, u128); +} +get_u128 :: proc { int_get_u128, }; + +int_get_i128 :: proc(a: ^Int) -> (res: i128, err: Error) { + return int_get(a, i128); +} +get_i128 :: proc { int_get_i128, }; + +int_get_u64 :: proc(a: ^Int) -> (res: u64, err: Error) { + return int_get(a, u64); +} +get_u64 :: proc { int_get_u64, }; + +int_get_i64 :: proc(a: ^Int) -> (res: i64, err: Error) { + return int_get(a, i64); +} +get_i64 :: proc { int_get_i64, }; + +int_get_u32 :: proc(a: ^Int) -> (res: u32, err: Error) { + return int_get(a, u32); +} +get_u32 :: proc { int_get_u32, }; + +int_get_i32 :: proc(a: ^Int) -> (res: i32, err: Error) { + return int_get(a, i32); +} +get_i32 :: proc { int_get_i32, }; + +/* + TODO: Think about using `count_bits` to check if the value could be returned completely, + and maybe return max(T), .Integer_Overflow if not? +*/ +int_get :: proc(a: ^Int, $T: typeid) -> (res: T, err: Error) where intrinsics.type_is_integer(T) { + if err = clear_if_uninitialized(a); err != .None { + return 0, err; + } + + size_in_bits := int(size_of(T) * 8); + i := int((size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS); + i = min(int(a.used), i); + + for ; i >= 0; i -= 1 { + res <<= uint(0) if size_in_bits <= _DIGIT_BITS else _DIGIT_BITS; + res |= T(a.digit[i]); + if size_in_bits <= _DIGIT_BITS { + break; + }; + } + + when !intrinsics.type_is_unsigned(T) { + /* + Mask off sign bit. + */ + res ~= 1 << uint(size_in_bits - 1); + /* + Set the sign. + */ + if a.sign == .Negative { + res = -res; + } + } + return; +} +get :: proc { int_get, }; + +int_get_float :: proc(a: ^Int) -> (res: f64, err: Error) { + if err = clear_if_uninitialized(a); err != .None { + return 0, err; + } + + l := min(a.used, 17); // log2(max(f64)) is approximately 1020, or 17 legs. + fac := f64(1 << _DIGIT_BITS); + d := 0.0; + + for i := l; i >= 0; i -= 1 { + d = (d * fac) + f64(a.digit[i]); + } + + res = -d if a.sign == .Negative else d; + return; } /* @@ -393,21 +475,21 @@ count_lsb :: proc(a: ^Int) -> (count: int, err: Error) { q = a.digit[count]; count *= _DIGIT_BITS; - /* - Now scan this digit until a 1 is found. - */ - if q & 1 == 0 { - p: DIGIT; - for { - p = q & 15; - count += int(lnz[p]); - q >>= 4; - if p != 0 { - break; - } + /* + Now scan this digit until a 1 is found. + */ + if q & 1 == 0 { + p: DIGIT; + for { + p = q & 15; + count += int(lnz[p]); + q >>= 4; + if p != 0 { + break; + } } } - return count, .None; + return count, .None; } /*