big: Add get(a, type) and get_float.

This commit is contained in:
Jeroen van Rijn
2021-07-22 17:21:39 +02:00
parent 1d0b37c1d8
commit 78c0877994
3 changed files with 105 additions and 30 deletions

View File

@@ -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,

View File

@@ -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);

View File

@@ -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;
}
/*