commit 6e22e78d4fd70b9e38542d7cd8c2ba931a571801
parent 7e2d2b95a17723ecb886d8acc1951fa32aebb96b
Author: NunoSempere <nuno.sempere@protonmail.com>
Date: Sat, 20 May 2023 22:38:38 -0400
add cool implementation of the logarithm
Diffstat:
2 files changed, 29 insertions(+), 14 deletions(-)
diff --git a/wip/nim/samples b/wip/nim/samples
Binary files differ.
diff --git a/wip/nim/samples.nim b/wip/nim/samples.nim
@@ -22,11 +22,24 @@ proc sine(x: float): float =
acc = acc + taylor
return acc
-# Helpers for calculating the log function
+## Log function
+
+## Old implementation using Taylor expansion
+proc log_slow(x: float): float =
+ var y = x - 1
+ let n = 100000000
+ var acc = 0.0
+ for i in 1..n:
+ let taylor = pow(-1.0, float(i+1)) * pow(y, i.float) / i.float
+ acc = acc + taylor
+ return acc
+
+## New implementation
+## <https://en.wikipedia.org/wiki/Natural_logarithm#High_precision>
## Arithmetic-geomtric mean
proc ag(x: float, y: float): float =
- let n = 100
+ let n = 128 # just some high number
var a = (x + y)/2.0
var b = sqrt(x * y)
for i in 0..n:
@@ -35,26 +48,28 @@ proc ag(x: float, y: float): float =
b = sqrt(b*temp)
return a
-## Find m such that x * 2^m > 2^100
-
-proc log_slow(x: float): float =
- # See: <https://en.wikipedia.org/wiki/Natural_logarithm#High_precision>
- var y = x - 1
- let n = 100000000
- var acc = 0.0
- for i in 1..n:
- let taylor = pow(-1.0, float(i+1)) * pow(y, i.float) / i.float
- acc = acc + taylor
- return acc
+## Find m such that x * 2^m > 2^precision/2
+proc find_m(x:float): float =
+ var m = 0.0;
+ let precision = 64 # bits
+ let c = pow(2.0, precision.float / 2.0)
+ while x * pow(2.0, m) < c:
+ m = m + 1
+ return m
proc log(x: float): float =
- return 1
+ let m = find_m(x)
+ let s = x * pow(2.0, m)
+ let ln2 = 0.6931471805599453
+ return ( PI / (2.0 * ag(1, 4.0/s)) ) - m * ln2
## Test these functions
echo factorial(5)
echo sine(1.0)
echo log(1.0)
echo log(2.0)
+echo log(3.0)
+echo pow(2.0, 32.float)
## Distribution functions
proc normal(): float =