mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-06 02:34:05 +00:00
big: Some more work on constants.
This commit is contained in:
@@ -683,7 +683,11 @@ int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int) -> (err: E
|
||||
// err = _int_div_recursive(quotient, remainder, numerator, denominator);
|
||||
} else {
|
||||
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;
|
||||
@@ -792,7 +796,7 @@ _int_recursive_product :: proc(res: ^Int, start, stop: DIGIT, level := int(0)) -
|
||||
|
||||
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{};
|
||||
defer destroy(inner, outer, start, stop, temp);
|
||||
|
||||
if err = one(inner); err != nil { return err; }
|
||||
if err = one(outer); err != nil { return err; }
|
||||
if err = set(inner, 1); err != nil { return err; }
|
||||
if err = set(outer, 1); err != nil { return err; }
|
||||
|
||||
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 */
|
||||
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.
|
||||
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.
|
||||
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;
|
||||
/*
|
||||
Compute carry
|
||||
@@ -975,7 +979,7 @@ _int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
|
||||
|
||||
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);
|
||||
/*
|
||||
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
|
||||
*/
|
||||
for ; i < max_used; i += 1 {
|
||||
#no_bounds_check for ; i < max_used; i += 1 {
|
||||
dest.digit[i] = x.digit[i] - borrow;
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
for iy = 0; iy < pb; iy += 1 {
|
||||
#no_bounds_check for iy = 0; iy < pb; iy += 1 {
|
||||
/*
|
||||
Compute the column as a _WORD.
|
||||
*/
|
||||
@@ -1144,7 +1148,7 @@ _int_mul_comba :: proc(dest, a, b: ^Int, digits: int) -> (err: Error) {
|
||||
/*
|
||||
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]);
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
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);
|
||||
/*
|
||||
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);
|
||||
|
||||
for iy = ix + 1; iy < pa; iy += 1 {
|
||||
#no_bounds_check for iy = ix + 1; iy < pa; iy += 1 {
|
||||
/*
|
||||
First calculate the product.
|
||||
*/
|
||||
@@ -1242,7 +1246,7 @@ _int_sqr :: proc(dest, src: ^Int) -> (err: Error) {
|
||||
/*
|
||||
Propagate upwards.
|
||||
*/
|
||||
for carry != 0 {
|
||||
#no_bounds_check for carry != 0 {
|
||||
r = _WORD(t.digit[ix+iy]) + _WORD(carry);
|
||||
t.digit[ix+iy] = DIGIT(r & _WORD(_MASK));
|
||||
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.
|
||||
*/
|
||||
@(deprecated="Use `_int_div_school`, it's 3.5x faster.")
|
||||
_int_div_small :: proc(quotient, remainder, numerator, denominator: ^Int) -> (err: Error) {
|
||||
|
||||
ta, tb, tq, q := &Int{}, &Int{}, &Int{}, &Int{};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
@echo off
|
||||
:odin run . -vet
|
||||
odin run . -vet
|
||||
: -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: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: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
|
||||
|
||||
python test.py
|
||||
:python test.py
|
||||
@@ -88,7 +88,7 @@ Event :: struct {
|
||||
}
|
||||
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();
|
||||
as, err := itoa(a, base);
|
||||
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{};
|
||||
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);
|
||||
print(" nan: ", a, 10, true, true, true);
|
||||
print(" nan: ", a, 10, true, true, true);
|
||||
fmt.println();
|
||||
|
||||
inf(a);
|
||||
print(" inf: ", a, 10, true, true, true);
|
||||
print(" inf: ", a, 10, true, true, true);
|
||||
fmt.println();
|
||||
|
||||
minus_inf(a);
|
||||
print("-inf: ", a, 10, true, true, true);
|
||||
print("-inf: ", a, 10, true, true, true);
|
||||
fmt.println();
|
||||
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ int_pow :: proc(dest, base: ^Int, power: int) -> (err: Error) {
|
||||
if err = zero(dest); err != nil { return err; }
|
||||
return .Math_Domain_Error;
|
||||
}
|
||||
if power == 0 { return one(dest); }
|
||||
if power == 0 { return set(dest, 1); }
|
||||
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 = 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; }
|
||||
|
||||
low := 0; high := 1;
|
||||
|
||||
@@ -13,6 +13,10 @@ import "core:mem"
|
||||
import "core:intrinsics"
|
||||
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.
|
||||
*/
|
||||
@@ -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)
|
||||
where intrinsics.type_is_integer(T) {
|
||||
src := src;
|
||||
if err = clear_if_uninitialized(dest); err != nil {
|
||||
return err;
|
||||
}
|
||||
dest.used = 0;
|
||||
|
||||
if err = error_if_immutable(dest); err != nil { return err; }
|
||||
if err = clear_if_uninitialized(dest); err != nil { return err; }
|
||||
|
||||
dest.flags = {}; // We're not -Inf, Inf, NaN or Immutable.
|
||||
|
||||
dest.used = 0;
|
||||
dest.sign = .Zero_or_Positive if src >= 0 else .Negative;
|
||||
src = abs(src);
|
||||
|
||||
@@ -57,19 +64,21 @@ set :: proc { int_set_from_integer, int_copy };
|
||||
Copy one `Int` to another.
|
||||
*/
|
||||
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) {
|
||||
return nil;
|
||||
}
|
||||
if (dest == src) { 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`.
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -340,7 +349,7 @@ zero :: clear;
|
||||
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) {
|
||||
return set(a, 1);
|
||||
return set(a, 1, minimize, allocator);
|
||||
}
|
||||
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.
|
||||
*/
|
||||
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, };
|
||||
|
||||
@@ -356,7 +365,9 @@ minus_one :: proc { int_minus_one, };
|
||||
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) {
|
||||
return copy(a, INF, minimize, allocator);
|
||||
err = set(a, 1, minimize, allocator);
|
||||
a.flags |= { .Inf, };
|
||||
return err;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
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, };
|
||||
|
||||
@@ -372,7 +385,9 @@ minus_inf :: proc { int_inf, };
|
||||
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) {
|
||||
return copy(a, NAN, minimize, allocator);
|
||||
err = set(a, 1, minimize, allocator);
|
||||
a.flags |= { .NaN, };
|
||||
return err;
|
||||
}
|
||||
nan :: proc { int_nan, };
|
||||
|
||||
@@ -691,9 +706,14 @@ initialize_constants :: proc() -> (res: int) {
|
||||
set( ZERO, 0); ZERO.flags = {.Immutable};
|
||||
set( ONE, 1); 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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user