From 320387c4ee07a3e38c4d2b80c37a57e8b1436e12 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 2 Aug 2021 01:11:44 +0200 Subject: [PATCH] big: Add `gcd_lcm` fast path in wrapper. --- core/math/big/basic.odin | 58 +++++++++++++++++++++++--------------- core/math/big/build.bat | 5 ++-- core/math/big/example.odin | 4 +-- core/math/big/test.odin | 4 +-- 4 files changed, 40 insertions(+), 31 deletions(-) diff --git a/core/math/big/basic.odin b/core/math/big/basic.odin index c501dd72e..5d0a50218 100644 --- a/core/math/big/basic.odin +++ b/core/math/big/basic.odin @@ -1271,26 +1271,45 @@ _int_div_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT) -> (remain */ int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int) -> (err: Error) { if err = clear_if_uninitialized(res_gcd, res_lcm, a, b); err != .None { return err; } + + az, _ := is_zero(a); bz, _ := is_zero(b); + if az && bz { + if res_gcd != nil { + if err = zero(res_gcd); err != .None { return err; } + } + if res_lcm != nil { + if err = zero(res_lcm); err != .None { return err; } + } + return .None; + } + else if az { + if res_gcd != nil { + if err = abs(res_gcd, b); err != .None { return err; } + } + if res_lcm != nil { + if err = zero(res_lcm); err != .None { return err; } + } + return .None; + } + else if bz { + if res_gcd != nil { + if err = abs(res_gcd, a); err != .None { return err; } + } + if res_lcm != nil { + if err = zero(res_lcm); err != .None { return err; } + } + return .None; + } + return #force_inline _int_gcd_lcm(res_gcd, res_lcm, a, b); } gcd_lcm :: proc { int_gcd_lcm, }; /* - Greatest Common Divisor using the binary method. + Greatest Common Divisor. */ int_gcd :: proc(res, a, b: ^Int) -> (err: Error) { - if err = clear_if_uninitialized(res, a, b); err != .None { return err; } - - /* - If both `a` and `b` are zero, return zero. - If either `a` or `b`, return the other one. - */ - az, _ := is_zero(a); bz, _ := is_zero(b); - if az && bz { return zero(res); } - else if az { return abs(res, b); } - else if bz { return abs(res, a); } - - return #force_inline _int_gcd_lcm(res, nil, a, b); + return #force_inline int_gcd_lcm(res, nil, a, b); } gcd :: proc { int_gcd, }; @@ -1298,20 +1317,13 @@ gcd :: proc { int_gcd, }; Least Common Multiple. */ int_lcm :: proc(res, a, b: ^Int) -> (err: Error) { - if err = clear_if_uninitialized(res, a, b); err != .None { return err; } - - /* - If both `a` and `b` are zero, return zero. - */ - az, _ := is_zero(a); bz, _ := is_zero(b); - if az || bz { return zero(res); } - - return #force_inline _int_gcd_lcm(nil, res, a, b); + return #force_inline int_gcd_lcm(nil, res, a, b); } lcm :: proc { int_lcm, }; /* - Internal function computing both GCD and (if target isn't `nil`) also LCM. + Internal function computing both GCD using the binary method, + and, if target isn't `nil`, also LCM. Expects the arguments to have been initialized. */ _int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int) -> (err: Error) { diff --git a/core/math/big/build.bat b/core/math/big/build.bat index 6a067018e..8e69389e9 100644 --- a/core/math/big/build.bat +++ b/core/math/big/build.bat @@ -1,10 +1,9 @@ @echo off -:odin run . -vet +odin run . -vet :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 -python test.py -:del big.* \ No newline at end of file +:python test.py \ No newline at end of file diff --git a/core/math/big/example.odin b/core/math/big/example.odin index ba7190c59..5452dd711 100644 --- a/core/math/big/example.odin +++ b/core/math/big/example.odin @@ -115,7 +115,7 @@ demo :: proc() { defer destroy(a, b, c, d, e, f); set(a, 125); - set(b, 0); + set(b, 75); err = gcd_lcm(c, d, a, b); fmt.printf("gcd_lcm("); @@ -138,8 +138,6 @@ demo :: proc() { print(", b =", b, 10, false, true, false); print(") =", c, 10, false, true, false); fmt.printf(" (err = %v)\n", err); - - } main :: proc() { diff --git a/core/math/big/test.odin b/core/math/big/test.odin index bbe045912..52c9eaa3e 100644 --- a/core/math/big/test.odin +++ b/core/math/big/test.odin @@ -324,8 +324,8 @@ PyRes :: struct { ai, bi, dest := &Int{}, &Int{}, &Int{}; defer destroy(ai, bi, dest); - if err = atoi(ai, string(a), 16); err != .None { return PyRes{res=":gcd:atoi(a):", err=err}; } - if err = atoi(bi, string(b), 16); err != .None { return PyRes{res=":gcd:atoi(b):", err=err}; } + if err = atoi(ai, string(a), 16); err != .None { return PyRes{res=":lcm:atoi(a):", err=err}; } + if err = atoi(bi, string(b), 16); err != .None { return PyRes{res=":lcm:atoi(b):", err=err}; } if err = lcm(dest, ai, bi); err != .None { return PyRes{res=":lcm:lcm(a, b):", err=err}; } r: cstring;