mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-22 10:56:41 +00:00
big: Add another way to estimate radix size.
This commit is contained in:
@@ -37,7 +37,6 @@ int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator :
|
||||
if err = clear_if_uninitialized(dest); err != .None {
|
||||
return err;
|
||||
}
|
||||
|
||||
dest.used = 0;
|
||||
dest.sign = .Zero_or_Positive if src >= 0 else .Negative;
|
||||
src = abs(src);
|
||||
|
||||
@@ -210,7 +210,6 @@ int_log_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Internal implementation of log.
|
||||
*/
|
||||
|
||||
@@ -232,6 +232,8 @@ itoa :: proc{itoa_string, itoa_raw};
|
||||
int_to_string :: itoa;
|
||||
int_to_cstring :: itoa_cstring;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
We size for `string` by default.
|
||||
*/
|
||||
@@ -251,17 +253,39 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false) -> (size: int, e
|
||||
return 1, .None;
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate `log` on a temporary "copy" with its sign set to positive.
|
||||
*/
|
||||
t := &Int{
|
||||
used = a.used,
|
||||
sign = .Zero_or_Positive,
|
||||
digit = a.digit,
|
||||
};
|
||||
if pot, _ := is_power_of_two(a); pot {
|
||||
/*
|
||||
Calculate `log` on a temporary "copy" with its sign set to positive.
|
||||
*/
|
||||
t := &Int{
|
||||
used = a.used,
|
||||
sign = .Zero_or_Positive,
|
||||
digit = a.digit,
|
||||
};
|
||||
|
||||
if size, err = log(t, DIGIT(radix)); err != .None {
|
||||
return 0, err;
|
||||
if size, err = log(t, DIGIT(radix)); err != .None {
|
||||
return 0, err;
|
||||
}
|
||||
} else {
|
||||
la, k := &Int{}, &Int{};
|
||||
defer destroy(la, k);
|
||||
|
||||
/* la = floor(log_2(a)) + 1 */
|
||||
bit_count, _ := count_bits(a);
|
||||
err = set(la, bit_count);
|
||||
|
||||
/* k = floor(2^29/log_2(radix)) + 1 */
|
||||
lb := _log_bases;
|
||||
err = set(k, lb[radix]);
|
||||
|
||||
/* n = floor((la * k) / 2^29) + 1 */
|
||||
if err = mul(k, la, k); err != .None { return 0, err; }
|
||||
if err = shr(k, k, _RADIX_SIZE_SCALE); err != .None { return 0, err; }
|
||||
|
||||
/* The "+1" here is the "+1" in "floor((la * k) / 2^29) + 1" */
|
||||
/* n = n + 1 + EOS + sign */
|
||||
size_, _ := get(k, u128);
|
||||
size = int(size_);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -272,6 +296,37 @@ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false) -> (size: int, e
|
||||
return size, .None;
|
||||
}
|
||||
|
||||
/*
|
||||
Overestimate the size needed for the bigint to string conversion by a very small amount.
|
||||
The error is about 10^-8; it will overestimate the result by at most 11 elements for
|
||||
a number of the size 2^(2^31)-1 which is currently the largest possible in this library.
|
||||
Some short tests gave no results larger than 5 (plus 2 for sign and EOS).
|
||||
*/
|
||||
|
||||
/*
|
||||
Table of {0, INT(log_2([1..64])*2^p)+1 } where p is the scale
|
||||
factor defined in MP_RADIX_SIZE_SCALE and INT() extracts the integer part (truncating).
|
||||
Good for 32 bit "int". Set MP_RADIX_SIZE_SCALE = 61 and recompute values
|
||||
for 64 bit "int".
|
||||
*/
|
||||
|
||||
_RADIX_SIZE_SCALE :: 29;
|
||||
_log_bases :: [65]u32{
|
||||
0, 0, 0x20000001, 0x14309399, 0x10000001,
|
||||
0xdc81a35, 0xc611924, 0xb660c9e, 0xaaaaaab, 0xa1849cd,
|
||||
0x9a209a9, 0x94004e1, 0x8ed19c2, 0x8a5ca7d, 0x867a000,
|
||||
0x830cee3, 0x8000001, 0x7d42d60, 0x7ac8b32, 0x7887847,
|
||||
0x7677349, 0x749131f, 0x72d0163, 0x712f657, 0x6fab5db,
|
||||
0x6e40d1b, 0x6ced0d0, 0x6badbde, 0x6a80e3b, 0x6964c19,
|
||||
0x6857d31, 0x6758c38, 0x6666667, 0x657fb21, 0x64a3b9f,
|
||||
0x63d1ab4, 0x6308c92, 0x624869e, 0x618ff47, 0x60dedea,
|
||||
0x6034ab0, 0x5f90e7b, 0x5ef32cb, 0x5e5b1b2, 0x5dc85c3,
|
||||
0x5d3aa02, 0x5cb19d9, 0x5c2d10f, 0x5bacbbf, 0x5b3064f,
|
||||
0x5ab7d68, 0x5a42df0, 0x59d1506, 0x5962ffe, 0x58f7c57,
|
||||
0x588f7bc, 0x582a000, 0x57c7319, 0x5766f1d, 0x5709243,
|
||||
0x56adad9, 0x565474d, 0x55fd61f, 0x55a85e8, 0x5555556,
|
||||
};
|
||||
|
||||
/*
|
||||
Characters used in radix conversions.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user