mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
big: Improve int_bitfield_extract.
This commit is contained in:
@@ -12,6 +12,8 @@ package big
|
|||||||
|
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
|
import "core:time"
|
||||||
|
import rnd "core:math/rand"
|
||||||
|
|
||||||
print_configation :: proc() {
|
print_configation :: proc() {
|
||||||
fmt.printf(
|
fmt.printf(
|
||||||
@@ -40,32 +42,51 @@ _SQR_TOOM_CUTOFF,
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Category :: enum {
|
||||||
|
itoa,
|
||||||
|
atoi,
|
||||||
|
};
|
||||||
|
Event :: struct {
|
||||||
|
t: time.Duration,
|
||||||
|
c: int,
|
||||||
|
}
|
||||||
|
Timings := [Category]Event{};
|
||||||
|
|
||||||
print :: proc(name: string, a: ^Int, base := i8(10)) {
|
print :: proc(name: string, a: ^Int, base := i8(10)) {
|
||||||
|
s := time.tick_now();
|
||||||
as, err := itoa(a, base);
|
as, err := itoa(a, base);
|
||||||
|
Timings[.itoa].t += time.tick_since(s); Timings[.itoa].c += 1;
|
||||||
|
|
||||||
defer delete(as);
|
defer delete(as);
|
||||||
cb, _ := count_bits(a);
|
cb, _ := count_bits(a);
|
||||||
fmt.printf("%v (base: %v, bits used: %v): %v\n", name, base, cb, as);
|
fmt.printf("%v (base: %v, bits used: %v): %v\n", name, base, cb, as);
|
||||||
if err != .None {
|
if err != .None {
|
||||||
fmt.printf("%v (error: %v | %v)\n", name, err, a);
|
fmt.printf("%v (error: %v | %v)\n", name, err, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@thread_local string_buffer: [1024]u8;
|
|
||||||
|
|
||||||
demo :: proc() {
|
demo :: proc() {
|
||||||
err: Error;
|
err: Error;
|
||||||
|
as: string;
|
||||||
|
|
||||||
|
r := &rnd.Rand{};
|
||||||
|
rnd.init(r, 12345);
|
||||||
|
|
||||||
destination, source, quotient, remainder, numerator, denominator := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
destination, source, quotient, remainder, numerator, denominator := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
||||||
defer destroy(destination, source, quotient, remainder, numerator, denominator);
|
defer destroy(destination, source, quotient, remainder, numerator, denominator);
|
||||||
|
|
||||||
for i in 1..=10 {
|
err = rand(destination, 120, r);
|
||||||
err = rand(destination, 1200); // 1200 random bits
|
// print("destination", destination, 10);
|
||||||
|
for _ in 0 ..< 10_000 {
|
||||||
if err != .None {
|
if err != .None {
|
||||||
fmt.printf("rand error: %v\n", err);
|
fmt.printf("set error: %v\n", err);
|
||||||
} else {
|
} else {
|
||||||
fmt.printf("#%3d: ", i);
|
s := time.tick_now();
|
||||||
print("", destination);
|
as, err = itoa(destination, 16);
|
||||||
|
e := time.tick_since(s);
|
||||||
|
Timings[.itoa].t += e; Timings[.itoa].c += 1;
|
||||||
|
assert(as == "B38677A01B8EF75CF434CA68677495", as);
|
||||||
|
delete(as);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,9 +96,18 @@ main :: proc() {
|
|||||||
mem.tracking_allocator_init(&ta, context.allocator);
|
mem.tracking_allocator_init(&ta, context.allocator);
|
||||||
context.allocator = mem.tracking_allocator(&ta);
|
context.allocator = mem.tracking_allocator(&ta);
|
||||||
|
|
||||||
print_configation();
|
// print_configation();
|
||||||
demo();
|
demo();
|
||||||
|
|
||||||
|
fmt.printf("\nTimings:\n");
|
||||||
|
for v, i in Timings {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(ta.allocation_map) > 0 {
|
if len(ta.allocation_map) > 0 {
|
||||||
for _, v in ta.allocation_map {
|
for _, v in ta.allocation_map {
|
||||||
fmt.printf("Leaked %v bytes @ %v\n", v.size, v.location);
|
fmt.printf("Leaked %v bytes @ %v\n", v.size, v.location);
|
||||||
|
|||||||
+38
-19
@@ -11,7 +11,7 @@ package big
|
|||||||
|
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
import "core:math/rand"
|
import rnd "core:math/rand"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Deallocates the backing memory of one or more `Int`s.
|
Deallocates the backing memory of one or more `Int`s.
|
||||||
@@ -177,7 +177,7 @@ neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
Helpers to extract values from the `Int`.
|
Helpers to extract values from the `Int`.
|
||||||
*/
|
*/
|
||||||
extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) {
|
int_extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) {
|
||||||
/*
|
/*
|
||||||
Check that `a`is usable.
|
Check that `a`is usable.
|
||||||
*/
|
*/
|
||||||
@@ -195,10 +195,7 @@ extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) {
|
|||||||
return 1 if ((a.digit[limb] & i) != 0) else 0, .None;
|
return 1 if ((a.digit[limb] & i) != 0) else 0, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
int_bitfield_extract :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
|
||||||
TODO: Optimize.
|
|
||||||
*/
|
|
||||||
extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
|
|
||||||
/*
|
/*
|
||||||
Check that `a`is usable.
|
Check that `a`is usable.
|
||||||
*/
|
*/
|
||||||
@@ -210,18 +207,40 @@ extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
|
|||||||
return 0, .Invalid_Argument;
|
return 0, .Invalid_Argument;
|
||||||
}
|
}
|
||||||
|
|
||||||
v: DIGIT;
|
limb_lo := offset / _DIGIT_BITS;
|
||||||
e: Error;
|
bits_lo := offset % _DIGIT_BITS;
|
||||||
for shift := 0; shift < count; shift += 1 {
|
limb_hi := (offset + count) / _DIGIT_BITS;
|
||||||
o := offset + shift;
|
bits_hi := (offset + count) % _DIGIT_BITS;
|
||||||
v, e = extract_bit(a, o);
|
|
||||||
if e != .None {
|
if limb_lo < 0 || limb_lo >= a.used || limb_hi < 0 || limb_hi >= a.used {
|
||||||
break;
|
return 0, .Invalid_Argument;
|
||||||
}
|
|
||||||
res = res + _WORD(v) << uint(shift);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, e;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -507,9 +526,9 @@ count_lsb :: proc(a: ^Int) -> (count: int, err: Error) {
|
|||||||
return count, .None;
|
return count, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
int_random_digit :: proc(r: ^rand.Rand = nil) -> (res: DIGIT) {
|
int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) {
|
||||||
when _DIGIT_BITS == 60 { // DIGIT = u64
|
when _DIGIT_BITS == 60 { // DIGIT = u64
|
||||||
return DIGIT(rand.uint64(r)) & _MASK;
|
return DIGIT(rnd.uint64(r)) & _MASK;
|
||||||
} else when _DIGIT_BITS == 28 { // DIGIT = u32
|
} else when _DIGIT_BITS == 28 { // DIGIT = u32
|
||||||
return DIGIT(rand.uint32(r)) & _MASK;
|
return DIGIT(rand.uint32(r)) & _MASK;
|
||||||
} else {
|
} else {
|
||||||
@@ -519,7 +538,7 @@ int_random_digit :: proc(r: ^rand.Rand = nil) -> (res: DIGIT) {
|
|||||||
return 0; // We shouldn't get here.
|
return 0; // We shouldn't get here.
|
||||||
}
|
}
|
||||||
|
|
||||||
int_rand :: proc(dest: ^Int, bits: int, r: ^rand.Rand = nil) -> (err: Error) {
|
int_rand :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil) -> (err: Error) {
|
||||||
bits := bits;
|
bits := bits;
|
||||||
|
|
||||||
if bits <= 0 { return .Invalid_Argument; }
|
if bits <= 0 { return .Invalid_Argument; }
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_ter
|
|||||||
|
|
||||||
for offset := 0; offset < count; offset += 4 {
|
for offset := 0; offset < count; offset += 4 {
|
||||||
bits_to_get := int(min(count - offset, shift));
|
bits_to_get := int(min(count - offset, shift));
|
||||||
if digit, err = extract_bits(a, offset, bits_to_get); err != .None {
|
if digit, err = int_bitfield_extract(a, offset, bits_to_get); err != .None {
|
||||||
return len(buffer) - available, .Invalid_Argument;
|
return len(buffer) - available, .Invalid_Argument;
|
||||||
}
|
}
|
||||||
available -= 1;
|
available -= 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user