From 2f1e64438d9c530be7c2f2039dd447a51ccbae22 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Sun, 22 Dec 2024 20:44:32 -0500 Subject: [PATCH] AK: Add implementations of exp2() and exp() on non-x86 This is a pretty naive implementation of exp2() that can be improved a lot, but hey, it beats the sin() and cos() implementation on non-x86. It also implements exp(x) as exp2(x * log2(e)), with the same disclaimer. --- AK/Math.h | 52 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/AK/Math.h b/AK/Math.h index 9266e79e9ca0c0..4b11ac55dc3417 100644 --- a/AK/Math.h +++ b/AK/Math.h @@ -879,11 +879,46 @@ constexpr T exp2(T exponent) : "0"(exponent)); return res; #else -# if defined(AK_OS_SERENITY) - // TODO: Add implementation for this function. - TODO(); -# endif - return __builtin_exp2(exponent); + // TODO: Add better implementation of this function. + // This is just fast exponentiation for the integer part and + // the first couple terms of the taylor series for the fractional part. + + if (exponent < 0) + return 1 / exp2(-exponent); + + if (exponent >= log2(NumericLimits::max())) + return Infinity; + + // Integer exponentiation part. + int int_exponent = static_cast(exponent); + T exponent_fraction = exponent - int_exponent; + + T int_result = 1; + T base = 2; + for (;;) { + if (int_exponent & 1) + int_result *= base; + int_exponent >>= 1; + if (!int_exponent) + break; + base *= base; + } + + // Fractional part. + // Uses: + // exp(x) = sum(n, 0, \infty, x ** n / n!) + // 2**x = exp(log2(e) * x) + // FIXME: Pick better step size (and make it dependent on T). + T result = 0; + T power = 1; + T factorial = 1; + for (int i = 1; i < 16; ++i) { + result += power / factorial; + power *= exponent_fraction / L2_E; + factorial *= i; + } + + return int_result * result; #endif } @@ -907,11 +942,8 @@ constexpr T exp(T exponent) : "0"(exponent)); return res; #else -# if defined(AK_OS_SERENITY) - // TODO: Add implementation for this function. - TODO(); -# endif - return __builtin_exp(exponent); + // TODO: Add better implementation of this function. + return exp2(exponent * L2_E); #endif }