mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-03 22:28:46 +00:00
bigint: itoa works for numbers <= 120 bits.
This commit is contained in:
@@ -46,13 +46,13 @@ demo :: proc() {
|
|||||||
as, bs, cs: string;
|
as, bs, cs: string;
|
||||||
err: Error;
|
err: Error;
|
||||||
|
|
||||||
a, err = init(4);
|
a, err = init(-512);
|
||||||
defer destroy(a);
|
defer destroy(a);
|
||||||
as, err = itoa(a);
|
as, err = itoa(a);
|
||||||
fmt.printf("a: %v, err: %v\n\n", as, err);
|
fmt.printf("a: %v, err: %v\n\n", as, err);
|
||||||
delete(as);
|
delete(as);
|
||||||
|
|
||||||
b, err = init(4);
|
b, err = init(42);
|
||||||
defer destroy(b);
|
defer destroy(b);
|
||||||
bs, err = itoa(b);
|
bs, err = itoa(b);
|
||||||
fmt.printf("b: %s, err: %v\n\n", bs, err);
|
fmt.printf("b: %s, err: %v\n\n", bs, err);
|
||||||
@@ -68,7 +68,7 @@ demo :: proc() {
|
|||||||
err = sub(c, a, b);
|
err = sub(c, a, b);
|
||||||
|
|
||||||
fmt.printf("Error: %v\n", err);
|
fmt.printf("Error: %v\n", err);
|
||||||
as, err = itoa(a);
|
as, err = itoa(a, 8);
|
||||||
bs, err = itoa(b);
|
bs, err = itoa(b);
|
||||||
cs, err = itoa(c);
|
cs, err = itoa(c);
|
||||||
fmt.printf("a: %v, bits: %v\n", as, count_bits(a));
|
fmt.printf("a: %v, bits: %v\n", as, count_bits(a));
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ set_integer :: proc(a: ^Int, n: $T, minimize := false, loc := #caller_location)
|
|||||||
a.used = 0;
|
a.used = 0;
|
||||||
a.sign = .Zero_or_Positive if n >= 0 else .Negative;
|
a.sign = .Zero_or_Positive if n >= 0 else .Negative;
|
||||||
n = abs(n);
|
n = abs(n);
|
||||||
|
|
||||||
for n != 0 {
|
for n != 0 {
|
||||||
a.digit[a.used] = DIGIT(n) & _MASK;
|
a.digit[a.used] = DIGIT(n) & _MASK;
|
||||||
a.used += 1;
|
a.used += 1;
|
||||||
@@ -96,7 +97,6 @@ set_integer :: proc(a: ^Int, n: $T, minimize := false, loc := #caller_location)
|
|||||||
if minimize {
|
if minimize {
|
||||||
shrink(a);
|
shrink(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
_zero_unused(a);
|
_zero_unused(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+56
-15
@@ -114,6 +114,9 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, zero_terminate := false) -> (
|
|||||||
Radix defaults to 10.
|
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_Input;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Early exit if we were given an empty buffer.
|
Early exit if we were given an empty buffer.
|
||||||
@@ -123,7 +126,7 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, zero_terminate := false) -> (
|
|||||||
return 0, .Buffer_Overflow;
|
return 0, .Buffer_Overflow;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Early exit if `Int` == 0 or the entire `Int` fits in a single radix digit.
|
Fast path for when `Int` == 0 or the entire `Int` fits in a single radix digit.
|
||||||
*/
|
*/
|
||||||
if is_zero(a) || (a.used == 1 && a.digit[0] < DIGIT(radix)) {
|
if is_zero(a) || (a.used == 1 && a.digit[0] < DIGIT(radix)) {
|
||||||
needed := 2 if is_neg(a) else 1;
|
needed := 2 if is_neg(a) else 1;
|
||||||
@@ -148,15 +151,51 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, zero_terminate := false) -> (
|
|||||||
return written, .OK;
|
return written, .OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Fast path for when `Int` fits within a `_WORD`.
|
||||||
|
*/
|
||||||
|
if a.used == 1 || a.used == 2 {
|
||||||
|
val := _WORD(a.digit[1]) << _DIGIT_BITS + _WORD(a.digit[0]);
|
||||||
|
for val > 0 {
|
||||||
|
if available == 0 {
|
||||||
|
return written, .Buffer_Overflow;
|
||||||
|
}
|
||||||
|
|
||||||
|
q := val / _WORD(radix);
|
||||||
|
buffer[written] = RADIX_TABLE[val - (q * _WORD(radix))];
|
||||||
|
available -= 1;
|
||||||
|
written += 1;
|
||||||
|
|
||||||
|
val = q;
|
||||||
|
}
|
||||||
|
if is_neg(a) {
|
||||||
|
if available == 0 {
|
||||||
|
return written, .Buffer_Overflow;
|
||||||
|
}
|
||||||
|
buffer[written] = '-';
|
||||||
|
available -= 1;
|
||||||
|
written += 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Reverse output.
|
||||||
|
*/
|
||||||
|
slice.reverse(buffer[:written]);
|
||||||
|
if zero_terminate {
|
||||||
|
if available == 0 {
|
||||||
|
return written, .Buffer_Overflow;
|
||||||
|
}
|
||||||
|
buffer[written] = 0;
|
||||||
|
written += 1;
|
||||||
|
}
|
||||||
|
return written, .OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Fast path for radixes that are a power of two.
|
Fast path for radixes that are a power of two.
|
||||||
*/
|
*/
|
||||||
if is_power_of_two(int(radix)) {
|
if is_power_of_two(int(radix)) {
|
||||||
|
|
||||||
|
// return len(buffer), .OK;
|
||||||
|
|
||||||
return len(buffer), .OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1, .Unimplemented;
|
return -1, .Unimplemented;
|
||||||
@@ -170,8 +209,6 @@ int_to_cstring :: itoa_cstring;
|
|||||||
We size for `string`, not `cstring`.
|
We size for `string`, not `cstring`.
|
||||||
*/
|
*/
|
||||||
radix_size :: proc(a: ^Int, radix: i8) -> (size: int, err: Error) {
|
radix_size :: proc(a: ^Int, radix: i8) -> (size: int, err: Error) {
|
||||||
t := a;
|
|
||||||
|
|
||||||
if radix < 2 || radix > 64 {
|
if radix < 2 || radix > 64 {
|
||||||
return -1, .Invalid_Input;
|
return -1, .Invalid_Input;
|
||||||
}
|
}
|
||||||
@@ -180,22 +217,26 @@ radix_size :: proc(a: ^Int, radix: i8) -> (size: int, err: Error) {
|
|||||||
return 1, .OK;
|
return 1, .OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
t.sign = .Zero_or_Positive;
|
/*
|
||||||
log: int;
|
Calculate `log` on a temporary "copy" with its sign set to positive.
|
||||||
|
*/
|
||||||
|
t := &Int{
|
||||||
|
used = a.used,
|
||||||
|
allocated = a.allocated,
|
||||||
|
sign = .Zero_or_Positive,
|
||||||
|
digit = a.digit,
|
||||||
|
};
|
||||||
|
|
||||||
log, err = log_n(t, DIGIT(radix));
|
size, err = log_n(t, DIGIT(radix));
|
||||||
if err != .OK {
|
if err != .OK {
|
||||||
return log, err;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
log truncates to zero, so we need to add one more, and one for `-` if negative.
|
log truncates to zero, so we need to add one more, and one for `-` if negative.
|
||||||
*/
|
*/
|
||||||
if is_neg(a) {
|
size += 2 if is_neg(a) else 1;
|
||||||
return log + 2, .OK;
|
return size, .OK;
|
||||||
} else {
|
|
||||||
return log + 1, .OK;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user