mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 23:28:48 +00:00
big: Some more work on constants.
This commit is contained in:
+18
-13
@@ -683,7 +683,11 @@ int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int) -> (err: E
|
|||||||
// err = _int_div_recursive(quotient, remainder, numerator, denominator);
|
// err = _int_div_recursive(quotient, remainder, numerator, denominator);
|
||||||
} else {
|
} else {
|
||||||
err = _int_div_school(quotient, remainder, numerator, denominator);
|
err = _int_div_school(quotient, remainder, numerator, denominator);
|
||||||
// err = _int_div_small(quotient, remainder, numerator, denominator);
|
/*
|
||||||
|
NOTE(Jeroen): We no longer need or use `_int_div_small`.
|
||||||
|
We'll keep it around for a bit.
|
||||||
|
err = _int_div_small(quotient, remainder, numerator, denominator);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@@ -792,7 +796,7 @@ _int_recursive_product :: proc(res: ^Int, start, stop: DIGIT, level := int(0)) -
|
|||||||
|
|
||||||
if num_factors == 1 { return set(res, start); }
|
if num_factors == 1 { return set(res, start); }
|
||||||
|
|
||||||
return one(res);
|
return set(res, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -804,8 +808,8 @@ int_factorial_binary_split :: proc(res: ^Int, n: DIGIT) -> (err: Error) {
|
|||||||
inner, outer, start, stop, temp := &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
inner, outer, start, stop, temp := &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
||||||
defer destroy(inner, outer, start, stop, temp);
|
defer destroy(inner, outer, start, stop, temp);
|
||||||
|
|
||||||
if err = one(inner); err != nil { return err; }
|
if err = set(inner, 1); err != nil { return err; }
|
||||||
if err = one(outer); err != nil { return err; }
|
if err = set(outer, 1); err != nil { return err; }
|
||||||
|
|
||||||
bits_used := int(_DIGIT_TYPE_BITS - intrinsics.count_leading_zeros(n));
|
bits_used := int(_DIGIT_TYPE_BITS - intrinsics.count_leading_zeros(n));
|
||||||
|
|
||||||
@@ -896,7 +900,7 @@ _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|||||||
/* Zero the carry */
|
/* Zero the carry */
|
||||||
carry := DIGIT(0);
|
carry := DIGIT(0);
|
||||||
|
|
||||||
for i = 0; i < min_used; i += 1 {
|
#no_bounds_check for i = 0; i < min_used; i += 1 {
|
||||||
/*
|
/*
|
||||||
Compute the sum one _DIGIT at a time.
|
Compute the sum one _DIGIT at a time.
|
||||||
dest[i] = a[i] + b[i] + carry;
|
dest[i] = a[i] + b[i] + carry;
|
||||||
@@ -918,7 +922,7 @@ _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|||||||
Now copy higher words, if any, in A+B.
|
Now copy higher words, if any, in A+B.
|
||||||
If A or B has more digits, add those in.
|
If A or B has more digits, add those in.
|
||||||
*/
|
*/
|
||||||
for ; i < max_used; i += 1 {
|
#no_bounds_check for ; i < max_used; i += 1 {
|
||||||
dest.digit[i] = x.digit[i] + carry;
|
dest.digit[i] = x.digit[i] + carry;
|
||||||
/*
|
/*
|
||||||
Compute carry
|
Compute carry
|
||||||
@@ -975,7 +979,7 @@ _int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
|
|||||||
|
|
||||||
borrow := DIGIT(0);
|
borrow := DIGIT(0);
|
||||||
|
|
||||||
for i = 0; i < min_used; i += 1 {
|
#no_bounds_check for i = 0; i < min_used; i += 1 {
|
||||||
dest.digit[i] = (x.digit[i] - y.digit[i] - borrow);
|
dest.digit[i] = (x.digit[i] - y.digit[i] - borrow);
|
||||||
/*
|
/*
|
||||||
borrow = carry bit of dest[i]
|
borrow = carry bit of dest[i]
|
||||||
@@ -993,7 +997,7 @@ _int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
Now copy higher words if any, e.g. if A has more digits than B
|
Now copy higher words if any, e.g. if A has more digits than B
|
||||||
*/
|
*/
|
||||||
for ; i < max_used; i += 1 {
|
#no_bounds_check for ; i < max_used; i += 1 {
|
||||||
dest.digit[i] = x.digit[i] - borrow;
|
dest.digit[i] = x.digit[i] - borrow;
|
||||||
/*
|
/*
|
||||||
borrow = carry bit of dest[i]
|
borrow = carry bit of dest[i]
|
||||||
@@ -1058,7 +1062,7 @@ _int_mul :: proc(dest, a, b: ^Int, digits: int) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
Compute the column of the output and propagate the carry.
|
Compute the column of the output and propagate the carry.
|
||||||
*/
|
*/
|
||||||
for iy = 0; iy < pb; iy += 1 {
|
#no_bounds_check for iy = 0; iy < pb; iy += 1 {
|
||||||
/*
|
/*
|
||||||
Compute the column as a _WORD.
|
Compute the column as a _WORD.
|
||||||
*/
|
*/
|
||||||
@@ -1144,7 +1148,7 @@ _int_mul_comba :: proc(dest, a, b: ^Int, digits: int) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
Execute loop.
|
Execute loop.
|
||||||
*/
|
*/
|
||||||
for iz = 0; iz < iy; iz += 1 {
|
#no_bounds_check for iz = 0; iz < iy; iz += 1 {
|
||||||
_W += _WORD(a.digit[tx + iz]) * _WORD(b.digit[ty - iz]);
|
_W += _WORD(a.digit[tx + iz]) * _WORD(b.digit[ty - iz]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1202,7 +1206,7 @@ _int_sqr :: proc(dest, src: ^Int) -> (err: Error) {
|
|||||||
if err = grow(t, max((2 * pa) + 1, _DEFAULT_DIGIT_COUNT)); err != nil { return err; }
|
if err = grow(t, max((2 * pa) + 1, _DEFAULT_DIGIT_COUNT)); err != nil { return err; }
|
||||||
t.used = (2 * pa) + 1;
|
t.used = (2 * pa) + 1;
|
||||||
|
|
||||||
for ix = 0; ix < pa; ix += 1 {
|
#no_bounds_check for ix = 0; ix < pa; ix += 1 {
|
||||||
carry := DIGIT(0);
|
carry := DIGIT(0);
|
||||||
/*
|
/*
|
||||||
First calculate the digit at 2*ix; calculate double precision result.
|
First calculate the digit at 2*ix; calculate double precision result.
|
||||||
@@ -1218,7 +1222,7 @@ _int_sqr :: proc(dest, src: ^Int) -> (err: Error) {
|
|||||||
*/
|
*/
|
||||||
carry = DIGIT(r >> _DIGIT_BITS);
|
carry = DIGIT(r >> _DIGIT_BITS);
|
||||||
|
|
||||||
for iy = ix + 1; iy < pa; iy += 1 {
|
#no_bounds_check for iy = ix + 1; iy < pa; iy += 1 {
|
||||||
/*
|
/*
|
||||||
First calculate the product.
|
First calculate the product.
|
||||||
*/
|
*/
|
||||||
@@ -1242,7 +1246,7 @@ _int_sqr :: proc(dest, src: ^Int) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
Propagate upwards.
|
Propagate upwards.
|
||||||
*/
|
*/
|
||||||
for carry != 0 {
|
#no_bounds_check for carry != 0 {
|
||||||
r = _WORD(t.digit[ix+iy]) + _WORD(carry);
|
r = _WORD(t.digit[ix+iy]) + _WORD(carry);
|
||||||
t.digit[ix+iy] = DIGIT(r & _WORD(_MASK));
|
t.digit[ix+iy] = DIGIT(r & _WORD(_MASK));
|
||||||
carry = DIGIT(r >> _WORD(_DIGIT_BITS));
|
carry = DIGIT(r >> _WORD(_DIGIT_BITS));
|
||||||
@@ -1483,6 +1487,7 @@ _int_div_school :: proc(quotient, remainder, numerator, denominator: ^Int) -> (e
|
|||||||
/*
|
/*
|
||||||
Slower bit-bang division... also smaller.
|
Slower bit-bang division... also smaller.
|
||||||
*/
|
*/
|
||||||
|
@(deprecated="Use `_int_div_school`, it's 3.5x faster.")
|
||||||
_int_div_small :: proc(quotient, remainder, numerator, denominator: ^Int) -> (err: Error) {
|
_int_div_small :: proc(quotient, remainder, numerator, denominator: ^Int) -> (err: Error) {
|
||||||
|
|
||||||
ta, tb, tq, q := &Int{}, &Int{}, &Int{}, &Int{};
|
ta, tb, tq, q := &Int{}, &Int{}, &Int{}, &Int{};
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
@echo off
|
@echo off
|
||||||
:odin run . -vet
|
odin run . -vet
|
||||||
: -o:size -no-bounds-check
|
: -o:size -no-bounds-check
|
||||||
:odin build . -build-mode:shared -show-timings -o:minimal -use-separate-modules
|
:odin build . -build-mode:shared -show-timings -o:minimal -use-separate-modules
|
||||||
:odin build . -build-mode:shared -show-timings -o:size -use-separate-modules -no-bounds-check
|
:odin build . -build-mode:shared -show-timings -o:size -use-separate-modules -no-bounds-check
|
||||||
:odin build . -build-mode:shared -show-timings -o:size -use-separate-modules
|
:odin build . -build-mode:shared -show-timings -o:size -use-separate-modules
|
||||||
odin build . -build-mode:shared -show-timings -o:speed -use-separate-modules -no-bounds-check
|
:odin build . -build-mode:shared -show-timings -o:speed -use-separate-modules -no-bounds-check
|
||||||
:odin build . -build-mode:shared -show-timings -o:speed -use-separate-modules
|
:odin build . -build-mode:shared -show-timings -o:speed -use-separate-modules
|
||||||
|
|
||||||
python test.py
|
:python test.py
|
||||||
@@ -88,7 +88,7 @@ Event :: struct {
|
|||||||
}
|
}
|
||||||
Timings := [Category]Event{};
|
Timings := [Category]Event{};
|
||||||
|
|
||||||
print :: proc(name: string, a: ^Int, base := i8(10), print_name := false, newline := true, print_extra_info := false) {
|
print :: proc(name: string, a: ^Int, base := i8(10), print_name := true, newline := true, print_extra_info := false) {
|
||||||
s := time.tick_now();
|
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;
|
Timings[.itoa].t += time.tick_since(s); Timings[.itoa].c += 1;
|
||||||
@@ -118,28 +118,16 @@ demo :: proc() {
|
|||||||
a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
||||||
defer destroy(a, b, c, d, e, f);
|
defer destroy(a, b, c, d, e, f);
|
||||||
|
|
||||||
fmt.println();
|
|
||||||
print(" ONE: ", ONE, 10, true, true, true);
|
|
||||||
fmt.println();
|
|
||||||
|
|
||||||
one(a);
|
|
||||||
print(" one: ", a, 10, true, true, true);
|
|
||||||
fmt.println();
|
|
||||||
|
|
||||||
minus_one(a);
|
|
||||||
print("-one: ", a, 10, true, true, true);
|
|
||||||
fmt.println();
|
|
||||||
|
|
||||||
nan(a);
|
nan(a);
|
||||||
print(" nan: ", a, 10, true, true, true);
|
print(" nan: ", a, 10, true, true, true);
|
||||||
fmt.println();
|
fmt.println();
|
||||||
|
|
||||||
inf(a);
|
inf(a);
|
||||||
print(" inf: ", a, 10, true, true, true);
|
print(" inf: ", a, 10, true, true, true);
|
||||||
fmt.println();
|
fmt.println();
|
||||||
|
|
||||||
minus_inf(a);
|
minus_inf(a);
|
||||||
print("-inf: ", a, 10, true, true, true);
|
print("-inf: ", a, 10, true, true, true);
|
||||||
fmt.println();
|
fmt.println();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ int_pow :: proc(dest, base: ^Int, power: int) -> (err: Error) {
|
|||||||
if err = zero(dest); err != nil { return err; }
|
if err = zero(dest); err != nil { return err; }
|
||||||
return .Math_Domain_Error;
|
return .Math_Domain_Error;
|
||||||
}
|
}
|
||||||
if power == 0 { return one(dest); }
|
if power == 0 { return set(dest, 1); }
|
||||||
if power > 0 { return zero(dest); }
|
if power > 0 { return zero(dest); }
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -429,7 +429,7 @@ _int_log :: proc(a: ^Int, base: DIGIT) -> (res: int, err: Error) {
|
|||||||
|
|
||||||
if err = set(bi_base, base); err != nil { return -1, err; }
|
if err = set(bi_base, base); err != nil { return -1, err; }
|
||||||
if err = init_multi(bracket_mid, t); err != nil { return -1, err; }
|
if err = init_multi(bracket_mid, t); err != nil { return -1, err; }
|
||||||
if err = one(bracket_low); err != nil { return -1, err; }
|
if err = set(bracket_low, 1); err != nil { return -1, err; }
|
||||||
if err = set(bracket_high, base); err != nil { return -1, err; }
|
if err = set(bracket_high, base); err != nil { return -1, err; }
|
||||||
|
|
||||||
low := 0; high := 1;
|
low := 0; high := 1;
|
||||||
|
|||||||
+38
-18
@@ -13,6 +13,10 @@ import "core:mem"
|
|||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
import rnd "core:math/rand"
|
import rnd "core:math/rand"
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO: Int.flags and Constants like ONE, NAN, etc, are not yet properly handled everywhere.
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Deallocates the backing memory of one or more `Int`s.
|
Deallocates the backing memory of one or more `Int`s.
|
||||||
*/
|
*/
|
||||||
@@ -35,10 +39,13 @@ int_destroy :: proc(integers: ..^Int) {
|
|||||||
int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator := context.allocator) -> (err: Error)
|
int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator := context.allocator) -> (err: Error)
|
||||||
where intrinsics.type_is_integer(T) {
|
where intrinsics.type_is_integer(T) {
|
||||||
src := src;
|
src := src;
|
||||||
if err = clear_if_uninitialized(dest); err != nil {
|
|
||||||
return err;
|
if err = error_if_immutable(dest); err != nil { return err; }
|
||||||
}
|
if err = clear_if_uninitialized(dest); err != nil { return err; }
|
||||||
dest.used = 0;
|
|
||||||
|
dest.flags = {}; // We're not -Inf, Inf, NaN or Immutable.
|
||||||
|
|
||||||
|
dest.used = 0;
|
||||||
dest.sign = .Zero_or_Positive if src >= 0 else .Negative;
|
dest.sign = .Zero_or_Positive if src >= 0 else .Negative;
|
||||||
src = abs(src);
|
src = abs(src);
|
||||||
|
|
||||||
@@ -57,19 +64,21 @@ set :: proc { int_set_from_integer, int_copy };
|
|||||||
Copy one `Int` to another.
|
Copy one `Int` to another.
|
||||||
*/
|
*/
|
||||||
int_copy :: proc(dest, src: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
int_copy :: proc(dest, src: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
||||||
if err = error_if_immutable(dest); err != nil { return err; }
|
|
||||||
if err = clear_if_uninitialized(src); err != nil { return err; }
|
|
||||||
/*
|
/*
|
||||||
If dest == src, do nothing
|
If dest == src, do nothing
|
||||||
*/
|
*/
|
||||||
if (dest == src) {
|
if (dest == src) { return nil; }
|
||||||
return nil;
|
|
||||||
}
|
if err = error_if_immutable(dest); err != nil { return err; }
|
||||||
|
if err = clear_if_uninitialized(src); err != nil { return err; }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Grow `dest` to fit `src`.
|
Grow `dest` to fit `src`.
|
||||||
If `dest` is not yet initialized, it will be using `allocator`.
|
If `dest` is not yet initialized, it will be using `allocator`.
|
||||||
*/
|
*/
|
||||||
if err = grow(dest, src.used, minimize, allocator); err != nil {
|
needed := src.used if minimize else max(src.used, _DEFAULT_DIGIT_COUNT);
|
||||||
|
|
||||||
|
if err = grow(dest, needed, minimize, allocator); err != nil {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +349,7 @@ zero :: clear;
|
|||||||
Set the `Int` to 1 and optionally shrink it to the minimum backing size.
|
Set the `Int` to 1 and optionally shrink it to the minimum backing size.
|
||||||
*/
|
*/
|
||||||
int_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
int_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
||||||
return set(a, 1);
|
return set(a, 1, minimize, allocator);
|
||||||
}
|
}
|
||||||
one :: proc { int_one, };
|
one :: proc { int_one, };
|
||||||
|
|
||||||
@@ -348,7 +357,7 @@ one :: proc { int_one, };
|
|||||||
Set the `Int` to -1 and optionally shrink it to the minimum backing size.
|
Set the `Int` to -1 and optionally shrink it to the minimum backing size.
|
||||||
*/
|
*/
|
||||||
int_minus_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
int_minus_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
||||||
return set(a, -1);
|
return set(a, -1, minimize, allocator);
|
||||||
}
|
}
|
||||||
minus_one :: proc { int_minus_one, };
|
minus_one :: proc { int_minus_one, };
|
||||||
|
|
||||||
@@ -356,7 +365,9 @@ minus_one :: proc { int_minus_one, };
|
|||||||
Set the `Int` to Inf and optionally shrink it to the minimum backing size.
|
Set the `Int` to Inf and optionally shrink it to the minimum backing size.
|
||||||
*/
|
*/
|
||||||
int_inf :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
int_inf :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
||||||
return copy(a, INF, minimize, allocator);
|
err = set(a, 1, minimize, allocator);
|
||||||
|
a.flags |= { .Inf, };
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
inf :: proc { int_inf, };
|
inf :: proc { int_inf, };
|
||||||
|
|
||||||
@@ -364,7 +375,9 @@ inf :: proc { int_inf, };
|
|||||||
Set the `Int` to -Inf and optionally shrink it to the minimum backing size.
|
Set the `Int` to -Inf and optionally shrink it to the minimum backing size.
|
||||||
*/
|
*/
|
||||||
int_minus_inf :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
int_minus_inf :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
||||||
return copy(a, MINUS_INF, minimize, allocator);
|
err = set(a, -1, minimize, allocator);
|
||||||
|
a.flags |= { .Inf, };
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
minus_inf :: proc { int_inf, };
|
minus_inf :: proc { int_inf, };
|
||||||
|
|
||||||
@@ -372,7 +385,9 @@ minus_inf :: proc { int_inf, };
|
|||||||
Set the `Int` to NaN and optionally shrink it to the minimum backing size.
|
Set the `Int` to NaN and optionally shrink it to the minimum backing size.
|
||||||
*/
|
*/
|
||||||
int_nan :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
int_nan :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
||||||
return copy(a, NAN, minimize, allocator);
|
err = set(a, 1, minimize, allocator);
|
||||||
|
a.flags |= { .NaN, };
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
nan :: proc { int_nan, };
|
nan :: proc { int_nan, };
|
||||||
|
|
||||||
@@ -691,9 +706,14 @@ initialize_constants :: proc() -> (res: int) {
|
|||||||
set( ZERO, 0); ZERO.flags = {.Immutable};
|
set( ZERO, 0); ZERO.flags = {.Immutable};
|
||||||
set( ONE, 1); ONE.flags = {.Immutable};
|
set( ONE, 1); ONE.flags = {.Immutable};
|
||||||
set(MINUS_ONE, -1); MINUS_ONE.flags = {.Immutable};
|
set(MINUS_ONE, -1); MINUS_ONE.flags = {.Immutable};
|
||||||
set( INF, 0); INF.flags = {.Immutable, .Inf};
|
|
||||||
set( INF, 0); MINUS_INF.flags = {.Immutable, .Inf}; MINUS_INF.sign = .Negative;
|
/*
|
||||||
set( NAN, 0); NAN.flags = {.Immutable, .NaN};
|
We set these special values to -1 or 1 so they don't get mistake for zero accidentally.
|
||||||
|
This allows for shortcut tests of is_zero as .used == 0.
|
||||||
|
*/
|
||||||
|
set( INF, 1); INF.flags = {.Immutable, .Inf};
|
||||||
|
set( INF, -1); MINUS_INF.flags = {.Immutable, .Inf};
|
||||||
|
set( NAN, 1); NAN.flags = {.Immutable, .NaN};
|
||||||
|
|
||||||
return #config(MUL_KARATSUBA_CUTOFF, _DEFAULT_MUL_KARATSUBA_CUTOFF);
|
return #config(MUL_KARATSUBA_CUTOFF, _DEFAULT_MUL_KARATSUBA_CUTOFF);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user