From 74258a170a20fd5a8fb6afe420b7d877d674c100 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 28 Jul 2021 15:59:39 +0200 Subject: [PATCH] big: fix `itoa` base PoT other than 16. --- core/math/big/example.odin | 5 +-- core/math/big/helpers.odin | 78 ++++++++++++++++++++++++-------------- core/math/big/radix.odin | 2 +- 3 files changed, 52 insertions(+), 33 deletions(-) diff --git a/core/math/big/example.odin b/core/math/big/example.odin index 60e2a4447..f6b7236c6 100644 --- a/core/math/big/example.odin +++ b/core/math/big/example.odin @@ -76,7 +76,6 @@ demo :: proc() { defer destroy(destination, source, quotient, remainder, numerator, denominator); err = rand(destination, 120, r); - // print("destination", destination, 10); for _ in 0 ..< 10_000 { if err != .None { fmt.printf("set error: %v\n", err); @@ -85,7 +84,7 @@ demo :: proc() { as, err = itoa(destination, 16); e := time.tick_since(s); Timings[.itoa].t += e; Timings[.itoa].c += 1; - assert(as == "B38677A01B8EF75CF434CA68677495", as); + //assert(as == "ADCC737B67B0FCD7F189074CBE088B718141A383F9CF09B4D3824A09A3AEBAC155B810C29D62385F8F85616794C25393A757CEDEEBE3B0FE24573894DF7842A76F543D64A78FFD24D325CE044E9A0F69DE00CFFCC41427170096BC6D3537C856CD930A3794F03DB558CD5DB6A65971E618C5D0DBAE1E7AF52DDB8F5F84CD5BFC0B2EEEDBFB70E6B38677A01B8EF75CF434CA68677495", as); delete(as); } } @@ -104,7 +103,7 @@ main :: proc() { if v.c > 0 { avg := time.duration_milliseconds(time.Duration(f64(v.t) / f64(v.c))); total := time.duration_milliseconds(time.Duration(v.t)); - fmt.printf("%v: %.3f ms (avg), %.3f (total, %v calls)\n", i, avg, total, v.c); + fmt.printf("%v: %.3f ms (avg), %.3f ms (total, %v calls)\n", i, avg, total, v.c); } } diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index dc4fc697d..d5cf16b33 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -177,7 +177,7 @@ neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) { /* Helpers to extract values from the `Int`. */ -int_extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) { +extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) { /* Check that `a`is usable. */ @@ -195,6 +195,9 @@ int_extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) { return 1 if ((a.digit[limb] & i) != 0) else 0, .None; } +/* + TODO: Optimize. +*/ int_bitfield_extract :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) { /* Check that `a`is usable. @@ -207,40 +210,57 @@ int_bitfield_extract :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: E return 0, .Invalid_Argument; } - limb_lo := offset / _DIGIT_BITS; - bits_lo := offset % _DIGIT_BITS; - limb_hi := (offset + count) / _DIGIT_BITS; - bits_hi := (offset + count) % _DIGIT_BITS; + when true { + v: DIGIT; + e: Error; - if limb_lo < 0 || limb_lo >= a.used || limb_hi < 0 || limb_hi >= a.used { - return 0, .Invalid_Argument; - } - - for i := limb_hi; i >= limb_lo; i -= 1 { - res <<= _DIGIT_BITS; - - /* - Determine which bits to extract from each DIGIT. The whole DIGIT's worth by default. - */ - bit_count := _DIGIT_BITS; - bit_offset := 0; - if i == limb_lo { - bit_count -= bits_lo; - bit_offset = _DIGIT_BITS - bit_count; - } else if i == limb_hi { - bit_count = bits_hi; - bit_offset = 0; + for shift := 0; shift < count; shift += 1 { + o := offset + shift; + v, e = extract_bit(a, o); + if e != .None { + break; + } + res = res + _WORD(v) << uint(shift); } - d := a.digit[i]; + return res, e; + } else { + limb_lo := offset / _DIGIT_BITS; + bits_lo := offset % _DIGIT_BITS; + limb_hi := (offset + count) / _DIGIT_BITS; + bits_hi := (offset + count) % _DIGIT_BITS; - v := (d >> uint(bit_offset)) & DIGIT(1 << uint(bit_count - 1)); - m := DIGIT(1 << uint(bit_count-1)); - r := v & m; + if limb_lo < 0 || limb_lo >= a.used || limb_hi < 0 || limb_hi >= a.used { + return 0, .Invalid_Argument; + } + + for i := limb_hi; i >= limb_lo; i -= 1 { + res <<= _DIGIT_BITS; + + /* + Determine which bits to extract from each DIGIT. The whole DIGIT's worth by default. + */ + bit_count := _DIGIT_BITS; + bit_offset := 0; + if i == limb_lo { + bit_count -= bits_lo; + bit_offset = _DIGIT_BITS - bit_count; + } else if i == limb_hi { + bit_count = bits_hi; + bit_offset = 0; + } + + d := a.digit[i]; + + v := (d >> uint(bit_offset)) & DIGIT(1 << uint(bit_count - 1)); + m := DIGIT(1 << uint(bit_count-1)); + r := v & m; + + res |= _WORD(r); + } + return res, .None; - res |= _WORD(r); } - return res, .None; } /* diff --git a/core/math/big/radix.odin b/core/math/big/radix.odin index 06066af18..572adec6a 100644 --- a/core/math/big/radix.odin +++ b/core/math/big/radix.odin @@ -200,7 +200,7 @@ int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_ter count, err = count_bits(a); digit: _WORD; - for offset := 0; offset < count; offset += 4 { + for offset := 0; offset < count; offset += shift { bits_to_get := int(min(count - offset, shift)); if digit, err = int_bitfield_extract(a, offset, bits_to_get); err != .None { return len(buffer) - available, .Invalid_Argument;