mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
bigint: refactor to big.Int instead of bigint.Int.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
package bigint
|
package big
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||||
@@ -13,7 +13,6 @@ package bigint
|
|||||||
|
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
import "core:fmt"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===========================
|
===========================
|
||||||
@@ -56,7 +55,7 @@ add_two_ints :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|||||||
dest = a + digit;
|
dest = a + digit;
|
||||||
*/
|
*/
|
||||||
add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
||||||
dest := dest; x := a; digit := digit;
|
dest := dest; digit := digit;
|
||||||
assert_initialized(dest); assert_initialized(a);
|
assert_initialized(dest); assert_initialized(a);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -212,7 +211,7 @@ sub_two_ints :: proc(dest, number, decrease: ^Int) -> (err: Error) {
|
|||||||
dest = a - digit;
|
dest = a - digit;
|
||||||
*/
|
*/
|
||||||
sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
||||||
dest := dest; x := a; digit := digit;
|
dest := dest; digit := digit;
|
||||||
assert_initialized(dest); assert_initialized(a);
|
assert_initialized(dest); assert_initialized(a);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package bigint
|
package big
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||||
@@ -35,7 +35,13 @@ _DEFAULT_SQR_KARATSUBA_CUTOFF :: 120;
|
|||||||
_DEFAULT_MUL_TOOM_CUTOFF :: 350;
|
_DEFAULT_MUL_TOOM_CUTOFF :: 350;
|
||||||
_DEFAULT_SQR_TOOM_CUTOFF :: 400;
|
_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 {
|
Sign :: enum u8 {
|
||||||
Zero_or_Positive = 0,
|
Zero_or_Positive = 0,
|
||||||
Negative = 1,
|
Negative = 1,
|
||||||
@@ -44,8 +50,8 @@ Sign :: enum u8 {
|
|||||||
Int :: struct {
|
Int :: struct {
|
||||||
used: int,
|
used: int,
|
||||||
allocated: int,
|
allocated: int,
|
||||||
sign: Sign,
|
|
||||||
digit: [dynamic]DIGIT,
|
digit: [dynamic]DIGIT,
|
||||||
|
sign: Sign,
|
||||||
};
|
};
|
||||||
|
|
||||||
Comparison_Flag :: enum i8 {
|
Comparison_Flag :: enum i8 {
|
||||||
@@ -72,7 +78,7 @@ Error :: enum i8 {
|
|||||||
Primality_Flag :: enum u8 {
|
Primality_Flag :: enum u8 {
|
||||||
Blum_Blum_Shub = 0, /* BBS style prime */
|
Blum_Blum_Shub = 0, /* BBS style prime */
|
||||||
Safe = 1, /* Safe prime (p-1)/2 == prime */
|
Safe = 1, /* Safe prime (p-1)/2 == prime */
|
||||||
Second_MSB_On = 3, /* force 2nd MSB to 1 */
|
Second_MSB_On = 3, /* force 2nd MSB to 1 */
|
||||||
};
|
};
|
||||||
Primality_Flags :: bit_set[Primality_Flag; u8];
|
Primality_Flags :: bit_set[Primality_Flag; u8];
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
@echo off
|
||||||
|
odin run . -vet
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package bigint
|
package big
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
//+ignore
|
//+ignore
|
||||||
package bigint
|
package big
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||||
@@ -60,9 +60,9 @@ demo :: proc() {
|
|||||||
defer destroy(b);
|
defer destroy(b);
|
||||||
defer destroy(c);
|
defer destroy(c);
|
||||||
|
|
||||||
a, err = init(1+4+16+64);
|
a, err = init(512);
|
||||||
|
|
||||||
b, err = init(1+2+8+32+128);
|
b, err = init(a);
|
||||||
|
|
||||||
c, err = init(-4);
|
c, err = init(-4);
|
||||||
|
|
||||||
@@ -108,4 +108,10 @@ main :: proc() {
|
|||||||
fmt.printf("Leaked %v bytes @ %v\n", v.size, v.location);
|
fmt.printf("Leaked %v bytes @ %v\n", v.size, v.location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(ta.bad_free_array) > 0 {
|
||||||
|
fmt.println("Bad frees:");
|
||||||
|
for v in ta.bad_free_array {
|
||||||
|
fmt.println(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package bigint
|
package big
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||||
@@ -11,7 +11,6 @@ package bigint
|
|||||||
|
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
import "core:fmt"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Deallocates the backing memory of an Int.
|
Deallocates the backing memory of an Int.
|
||||||
@@ -62,7 +61,7 @@ init_new :: proc(allocator_zeroes := true, allocator := context.allocator, size
|
|||||||
Initialize from a signed or unsigned integer.
|
Initialize from a signed or unsigned integer.
|
||||||
Inits a new `Int` and then calls the appropriate `set` routine.
|
Inits a new `Int` and then calls the appropriate `set` routine.
|
||||||
*/
|
*/
|
||||||
init_new_integer :: proc(u: $T, minimize := false, allocator_zeroes := true, allocator := context.allocator) -> (a: ^Int, err: Error) where intrinsics.type_is_integer(T) {
|
init_from_integer :: proc(src: $T, minimize := false, allocator_zeroes := true, allocator := context.allocator) -> (a: ^Int, err: Error) where intrinsics.type_is_integer(T) {
|
||||||
|
|
||||||
n := _DEFAULT_DIGIT_COUNT;
|
n := _DEFAULT_DIGIT_COUNT;
|
||||||
if minimize {
|
if minimize {
|
||||||
@@ -71,12 +70,27 @@ init_new_integer :: proc(u: $T, minimize := false, allocator_zeroes := true, all
|
|||||||
|
|
||||||
a, err = init_new(allocator_zeroes, allocator, n);
|
a, err = init_new(allocator_zeroes, allocator, n);
|
||||||
if err == .OK {
|
if err == .OK {
|
||||||
set(a, u, minimize);
|
set(a, src, minimize);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
init :: proc{init_new, init_new_integer};
|
/*
|
||||||
|
Initialize an `Int` as a copy from another `Int`.
|
||||||
|
*/
|
||||||
|
init_copy :: proc(src: ^Int, minimize := false, allocator_zeroes := true, allocator := context.allocator) -> (a: ^Int, err: Error) {
|
||||||
|
if !is_initialized(src) {
|
||||||
|
return nil, .Invalid_Input;
|
||||||
|
}
|
||||||
|
|
||||||
|
a, err = init_new(allocator_zeroes, allocator, src.used);
|
||||||
|
if err == .OK {
|
||||||
|
copy(a, src);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
init :: proc{init_new, init_from_integer, init_copy};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Helpers to set an `Int` to a specific value.
|
Helpers to set an `Int` to a specific value.
|
||||||
@@ -123,7 +137,7 @@ copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
Grow `dest` to fit `src`.
|
Grow `dest` to fit `src`.
|
||||||
*/
|
*/
|
||||||
if err = grow(dest, min(src.used, _DEFAULT_DIGIT_COUNT)); err != .OK {
|
if err = grow(dest, src.used); err != .OK {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,6 +240,9 @@ extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) {
|
|||||||
return 1 if ((a.digit[limb] & i) != 0) else 0, .OK;
|
return 1 if ((a.digit[limb] & i) != 0) else 0, .OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO: Optimize.
|
||||||
|
*/
|
||||||
extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
|
extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
|
||||||
if count > _WORD_BITS || count < 1 {
|
if count > _WORD_BITS || count < 1 {
|
||||||
return 0, .Invalid_Input;
|
return 0, .Invalid_Input;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package bigint
|
package big
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||||
@@ -9,8 +9,6 @@ package bigint
|
|||||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "core:fmt"
|
|
||||||
|
|
||||||
log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
|
log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
|
||||||
assert_initialized(a);
|
assert_initialized(a);
|
||||||
if is_neg(a) || is_zero(a) || base < 2 || DIGIT(base) > _DIGIT_MAX {
|
if is_neg(a) || is_zero(a) || base < 2 || DIGIT(base) > _DIGIT_MAX {
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
package big
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||||
|
Made available under Odin's BSD-2 license.
|
||||||
|
|
||||||
|
A BigInt implementation in Odin.
|
||||||
|
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
|
||||||
|
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||||
|
|
||||||
|
This file contains logical operations like `and`, `or` and `xor`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
The `and`, `or` and `xor` binops differ in two lines only.
|
||||||
|
We could handle those with a switch, but that adds overhead.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
2's complement `and`, returns `dest = a & b;`
|
||||||
|
*/
|
||||||
|
and :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||||
|
assert_initialized(dest); assert_initialized(a); assert_initialized(b);
|
||||||
|
|
||||||
|
used := max(a.used, b.used) + 1;
|
||||||
|
neg: bool;
|
||||||
|
|
||||||
|
neg = is_neg(a) && is_neg(b);
|
||||||
|
|
||||||
|
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Grow the destination to accomodate the result.
|
||||||
|
*/
|
||||||
|
if err = grow(dest, used); err != .OK {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < used; i += 1 {
|
||||||
|
x, y: DIGIT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Convert to 2's complement if negative.
|
||||||
|
*/
|
||||||
|
if is_neg(a) {
|
||||||
|
ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
|
||||||
|
x = ac & _MASK;
|
||||||
|
ac >>= _DIGIT_BITS;
|
||||||
|
} else {
|
||||||
|
x = 0 if i >= a.used else a.digit[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Convert to 2's complement if negative.
|
||||||
|
*/
|
||||||
|
if is_neg(a) {
|
||||||
|
bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
|
||||||
|
y = bc & _MASK;
|
||||||
|
bc >>= _DIGIT_BITS;
|
||||||
|
} else {
|
||||||
|
y = 0 if i >= b.used else b.digit[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.digit[i] = x & y;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Convert to to sign-magnitude if negative.
|
||||||
|
*/
|
||||||
|
if neg {
|
||||||
|
cc += ~dest.digit[i] & _MASK;
|
||||||
|
dest.digit[i] = cc & _MASK;
|
||||||
|
cc >>= _DIGIT_BITS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.used = used;
|
||||||
|
dest.sign = .Negative if neg else .Zero_or_Positive;
|
||||||
|
clamp(dest);
|
||||||
|
return .OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
2's complement `or`, returns `dest = a | b;`
|
||||||
|
*/
|
||||||
|
or :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||||
|
assert_initialized(dest); assert_initialized(a); assert_initialized(b);
|
||||||
|
|
||||||
|
used := max(a.used, b.used) + 1;
|
||||||
|
neg: bool;
|
||||||
|
|
||||||
|
neg = is_neg(a) || is_neg(b);
|
||||||
|
|
||||||
|
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Grow the destination to accomodate the result.
|
||||||
|
*/
|
||||||
|
if err = grow(dest, used); err != .OK {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < used; i += 1 {
|
||||||
|
x, y: DIGIT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Convert to 2's complement if negative.
|
||||||
|
*/
|
||||||
|
if is_neg(a) {
|
||||||
|
ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
|
||||||
|
x = ac & _MASK;
|
||||||
|
ac >>= _DIGIT_BITS;
|
||||||
|
} else {
|
||||||
|
x = 0 if i >= a.used else a.digit[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Convert to 2's complement if negative.
|
||||||
|
*/
|
||||||
|
if is_neg(a) {
|
||||||
|
bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
|
||||||
|
y = bc & _MASK;
|
||||||
|
bc >>= _DIGIT_BITS;
|
||||||
|
} else {
|
||||||
|
y = 0 if i >= b.used else b.digit[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.digit[i] = x | y;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Convert to to sign-magnitude if negative.
|
||||||
|
*/
|
||||||
|
if neg {
|
||||||
|
cc += ~dest.digit[i] & _MASK;
|
||||||
|
dest.digit[i] = cc & _MASK;
|
||||||
|
cc >>= _DIGIT_BITS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.used = used;
|
||||||
|
dest.sign = .Negative if neg else .Zero_or_Positive;
|
||||||
|
clamp(dest);
|
||||||
|
return .OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
2's complement `xor`, returns `dest = a ~ b;`
|
||||||
|
*/
|
||||||
|
xor :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||||
|
assert_initialized(dest); assert_initialized(a); assert_initialized(b);
|
||||||
|
|
||||||
|
used := max(a.used, b.used) + 1;
|
||||||
|
neg: bool;
|
||||||
|
|
||||||
|
neg = is_neg(a) != is_neg(b);
|
||||||
|
|
||||||
|
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Grow the destination to accomodate the result.
|
||||||
|
*/
|
||||||
|
if err = grow(dest, used); err != .OK {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < used; i += 1 {
|
||||||
|
x, y: DIGIT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Convert to 2's complement if negative.
|
||||||
|
*/
|
||||||
|
if is_neg(a) {
|
||||||
|
ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
|
||||||
|
x = ac & _MASK;
|
||||||
|
ac >>= _DIGIT_BITS;
|
||||||
|
} else {
|
||||||
|
x = 0 if i >= a.used else a.digit[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Convert to 2's complement if negative.
|
||||||
|
*/
|
||||||
|
if is_neg(a) {
|
||||||
|
bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
|
||||||
|
y = bc & _MASK;
|
||||||
|
bc >>= _DIGIT_BITS;
|
||||||
|
} else {
|
||||||
|
y = 0 if i >= b.used else b.digit[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.digit[i] = x ~ y;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Convert to to sign-magnitude if negative.
|
||||||
|
*/
|
||||||
|
if neg {
|
||||||
|
cc += ~dest.digit[i] & _MASK;
|
||||||
|
dest.digit[i] = cc & _MASK;
|
||||||
|
cc >>= _DIGIT_BITS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.used = used;
|
||||||
|
dest.sign = .Negative if neg else .Zero_or_Positive;
|
||||||
|
clamp(dest);
|
||||||
|
return .OK;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package bigint
|
package big
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||||
@@ -11,21 +11,20 @@ package bigint
|
|||||||
This file contains radix conversions, `string_to_int` (atoi) and `int_to_string` (itoa).
|
This file contains radix conversions, `string_to_int` (atoi) and `int_to_string` (itoa).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "core:mem"
|
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:slice"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This version of `itoa` allocates one behalf of the caller. The caller must free the string.
|
This version of `itoa` allocates one behalf of the caller. The caller must free the string.
|
||||||
*/
|
*/
|
||||||
itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator := context.allocator) -> (res: string, err: Error) {
|
itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator := context.allocator) -> (res: string, err: Error) {
|
||||||
|
radix := radix;
|
||||||
assert_initialized(a);
|
assert_initialized(a);
|
||||||
/*
|
/*
|
||||||
Radix defaults to 10.
|
Radix defaults to 10.
|
||||||
*/
|
*/
|
||||||
radix := radix if radix > 0 else 10;
|
radix = radix if radix > 0 else 10;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: If we want to write a prefix for some of the radixes, we can oversize the buffer.
|
TODO: If we want to write a prefix for some of the radixes, we can oversize the buffer.
|
||||||
@@ -87,11 +86,12 @@ itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator
|
|||||||
This version of `itoa` allocates one behalf of the caller. The caller must free the string.
|
This version of `itoa` allocates one behalf of the caller. The caller must free the string.
|
||||||
*/
|
*/
|
||||||
itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -> (res: cstring, err: Error) {
|
itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -> (res: cstring, err: Error) {
|
||||||
|
radix := radix;
|
||||||
assert_initialized(a);
|
assert_initialized(a);
|
||||||
/*
|
/*
|
||||||
Radix defaults to 10.
|
Radix defaults to 10.
|
||||||
*/
|
*/
|
||||||
radix := radix if radix > 0 else 10;
|
radix = radix if radix > 0 else 10;
|
||||||
|
|
||||||
s: string;
|
s: string;
|
||||||
s, err = itoa_string(a, radix, true, allocator);
|
s, err = itoa_string(a, radix, true, allocator);
|
||||||
@@ -119,11 +119,12 @@ itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -
|
|||||||
and having to perform a buffer overflow check each character.
|
and having to perform a buffer overflow check each character.
|
||||||
*/
|
*/
|
||||||
itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
|
itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
|
||||||
|
radix := radix;
|
||||||
assert_initialized(a); size := size;
|
assert_initialized(a); size := size;
|
||||||
/*
|
/*
|
||||||
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 {
|
if radix < 2 || radix > 64 {
|
||||||
return 0, .Invalid_Input;
|
return 0, .Invalid_Input;
|
||||||
}
|
}
|
||||||
@@ -197,10 +198,10 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
|
|||||||
buffer[available] = 0;
|
buffer[available] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mask := _WORD(radix - 1);
|
// mask := _WORD(radix - 1);
|
||||||
shift := int(log_n(DIGIT(radix), 2));
|
shift := int(log_n(DIGIT(radix), 2));
|
||||||
count := int(count_bits(a));
|
count := int(count_bits(a));
|
||||||
digit: _WORD;
|
// digit: _WORD;
|
||||||
|
|
||||||
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));
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
@echo off
|
|
||||||
odin run .
|
|
||||||
rem -vet
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
package bigint
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
|
||||||
Made available under Odin's BSD-2 license.
|
|
||||||
|
|
||||||
A BigInt implementation in Odin.
|
|
||||||
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
|
|
||||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
|
||||||
|
|
||||||
This file contains logical operations like `and`, `or` and `xor`.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import "core:fmt"
|
|
||||||
|
|
||||||
@private
|
|
||||||
Operator :: enum u8 {
|
|
||||||
And = 1,
|
|
||||||
Or = 2,
|
|
||||||
Xor = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
2's complement `and`, returns `dest = a & b;`
|
|
||||||
*/
|
|
||||||
|
|
||||||
_binary_op :: proc(dest, a, b: ^Int, op: Operator) -> (err: Error) {
|
|
||||||
assert_initialized(dest); assert_initialized(a); assert_initialized(b);
|
|
||||||
|
|
||||||
used := max(a.used, b.used) + 1;
|
|
||||||
neg: bool;
|
|
||||||
|
|
||||||
switch(op) {
|
|
||||||
case .And:
|
|
||||||
neg = is_neg(a) && is_neg(b);
|
|
||||||
case .Or:
|
|
||||||
neg = is_neg(a) || is_neg(b);
|
|
||||||
case .Xor:
|
|
||||||
neg = is_neg(a) != is_neg(b);
|
|
||||||
case:
|
|
||||||
return .Invalid_Input;
|
|
||||||
}
|
|
||||||
|
|
||||||
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
|
||||||
|
|
||||||
/*
|
|
||||||
Grow the destination to accomodate the result.
|
|
||||||
*/
|
|
||||||
if err = grow(dest, used); err != .OK {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < used; i += 1 {
|
|
||||||
x, y: DIGIT;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Convert to 2's complement if negative.
|
|
||||||
*/
|
|
||||||
if is_neg(a) {
|
|
||||||
ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
|
|
||||||
x = ac & _MASK;
|
|
||||||
ac >>= _DIGIT_BITS;
|
|
||||||
} else {
|
|
||||||
x = 0 if i >= a.used else a.digit[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Convert to 2's complement if negative.
|
|
||||||
*/
|
|
||||||
if is_neg(a) {
|
|
||||||
bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
|
|
||||||
y = bc & _MASK;
|
|
||||||
bc >>= _DIGIT_BITS;
|
|
||||||
} else {
|
|
||||||
y = 0 if i >= b.used else b.digit[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(op) {
|
|
||||||
case .And:
|
|
||||||
dest.digit[i] = x & y;
|
|
||||||
case .Or:
|
|
||||||
dest.digit[i] = x | y;
|
|
||||||
case .Xor:
|
|
||||||
dest.digit[i] = x ~ y;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Convert to to sign-magnitude if negative.
|
|
||||||
*/
|
|
||||||
if neg {
|
|
||||||
cc += ~dest.digit[i] & _MASK;
|
|
||||||
dest.digit[i] = cc & _MASK;
|
|
||||||
cc >>= _DIGIT_BITS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dest.used = used;
|
|
||||||
dest.sign = .Negative if neg else .Zero_or_Positive;
|
|
||||||
clamp(dest);
|
|
||||||
return .OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
and :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|
||||||
return _binary_op(dest, a, b, .And);
|
|
||||||
}
|
|
||||||
|
|
||||||
or :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|
||||||
return _binary_op(dest, a, b, .Or);
|
|
||||||
}
|
|
||||||
|
|
||||||
xor :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|
||||||
return _binary_op(dest, a, b, .Xor);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user