From 43931be451606e13f8688bb8032c7bd449f4f285 Mon Sep 17 00:00:00 2001 From: 05st <60903484+05st@users.noreply.github.com> Date: Fri, 8 Oct 2021 14:07:44 -0500 Subject: [PATCH] math: sqrti, powi, factoriali (#12072) --- vlib/math/factorial.v | 13 +++++++++++++ vlib/math/factorial_test.v | 9 +++++++++ vlib/math/math_test.v | 12 ++++++++++++ vlib/math/pow.v | 35 +++++++++++++++++++++++++++++++++++ vlib/math/sqrt.v | 19 +++++++++++++++++++ 5 files changed, 88 insertions(+) diff --git a/vlib/math/factorial.v b/vlib/math/factorial.v index 116e08398..820f5fef2 100644 --- a/vlib/math/factorial.v +++ b/vlib/math/factorial.v @@ -53,3 +53,16 @@ fn log_factorial_asymptotic_expansion(n int) f64 { } return log_factorial + sum } + +// factoriali returns 1 for n <= 0 and -1 if the result is too large for a 64 bit integer +pub fn factoriali(n int) i64 { + if n <= 0 { + return i64(1) + } + + if n < 21 { + return i64(factorials_table[n]) + } + + return i64(-1) +} diff --git a/vlib/math/factorial_test.v b/vlib/math/factorial_test.v index 77c204364..4f10de42c 100644 --- a/vlib/math/factorial_test.v +++ b/vlib/math/factorial_test.v @@ -11,3 +11,12 @@ fn test_log_factorial() { assert log_factorial(5) == log(120) assert log_factorial(0) == log(1) } + +fn test_factoriali() { + assert factoriali(20) == 2432902008176640000 + assert factoriali(1) == 1 + assert factoriali(2) == 2 + assert factoriali(0) == 1 + assert factoriali(-2) == 1 + assert factoriali(1000) == -1 +} diff --git a/vlib/math/math_test.v b/vlib/math/math_test.v index 02eb90009..115a8c457 100644 --- a/vlib/math/math_test.v +++ b/vlib/math/math_test.v @@ -946,3 +946,15 @@ fn test_large_tan() { assert soclose(f1, f2, 4e-8) } } + +fn test_sqrti() { + assert sqrti(i64(123456789) * i64(123456789)) == 123456789 + assert sqrti(144) == 12 + assert sqrti(0) == 0 +} + +fn test_powi() { + assert powi(2, 62) == i64(4611686018427387904) + assert powi(0, -2) == -1 // div by 0 + assert powi(2, -1) == 0 +} diff --git a/vlib/math/pow.v b/vlib/math/pow.v index ff475c29a..007ebdd4a 100644 --- a/vlib/math/pow.v +++ b/vlib/math/pow.v @@ -35,6 +35,41 @@ pub fn pow10(n int) f64 { return 0.0 } +// powi returns base raised to power (a**b) as an integer (i64) +// +// special case: +// powi(a, b) = -1 for a = 0 and b < 0 +pub fn powi(a i64, b i64) i64 { + mut b_ := b + mut p := a + mut v := i64(1) + + if b_ < 0 { // exponent < 0 + if a == 0 { + return -1 // division by 0 + } + return if a * a != 1 { + 0 + } else { + if (b_ & 1) > 0 { + a + } else { + 1 + } + } + } + + for ; b_ > 0; { + if b_ & 1 > 0 { + v *= p + } + p *= p + b_ >>= 1 + } + + return v +} + // pow returns base raised to the provided power. // // todo(playXE): make this function work on JS backend, probably problem of JS codegen that it does not work. diff --git a/vlib/math/sqrt.v b/vlib/math/sqrt.v index 6513b79ec..8b11e2953 100644 --- a/vlib/math/sqrt.v +++ b/vlib/math/sqrt.v @@ -35,3 +35,22 @@ pub fn sqrt(a f64) f64 { pub fn sqrtf(a f32) f32 { return f32(sqrt(a)) } + +// sqrti calculates the integer square-root of the provided value. (i64) +pub fn sqrti(a i64) i64 { + mut x := a + mut q, mut r := i64(1), i64(0) + for ; q <= x; { + q <<= 2 + } + for ; q > 1; { + q >>= 2 + t := x - r - q + r >>= 1 + if t >= 0 { + x = t + r += q + } + } + return r +} -- 2.30.2