RS: Tcl's expr has logarithm to base e built-in:
% expr exp(1) ;# Euler's number, or e for short 2.71828182846 8 % expr log(exp(1)) 1.0
Logarithms to most any other base can be had by division -- e.g for log10 of 1000:
% expr log(1000)/log(10) 3.0
Feynman apparently is in the domain literature for numerical analysis of an algorithm which computes the logarithm of a number between 1 and 2. Any such number is a unique product of factors of the form (1 + 2 ** -k) for integral k. Logarithms of all such factors fit in a table of modest size. Determination of the sequence of k-s can be done with shifts and subtracts.
Here's a Tcl coding that illustrates the algorithm:
...
See math::bigfloat::log for another algorithm. (with arbitrary precision) It uses this development:
log(1+x)=x + x^2/2 + x^3/3 ...
and does not require sqrt() to be present. It only needs arithmetics.
proc logarithm x { set eps 1e-[set ::tcl_precision] if {$x<=-1} {error {logarithm requires a positive argument}} set log $x set pow [expr {-$x*$x}] set i 2 set add [expr {$pow/$i}] while {abs($add)>$eps*abs($log)} { set log [expr {$log+$add}] incr i set pow [expr {-$pow*$x}] set add [expr {$pow/$i}] } incr i -2 #puts "$i iterations" return $log } proc log x { set doubles 0 if {$x<=0} {error {logarithm requires a positive argument}} if {$x<1} { while {$x<=0.5} { # iterate : x=x*2 until 1/2<x<1 incr doubles -1 set x [expr {$x*2}] } } else { while {$x>=2} { # iterate : x=x/2 until 1<x<2 incr doubles set x [expr {$x/2}] } } set x [expr {double($x-1)}] global log2 #puts x=$x return [expr {[logarithm $x]+$doubles*$log2}] } # compute log(2) set log2 [expr {-[logarithm -0.2]*3-[logarithm [expr {-3./128.}]]}] # for debugging purpose proc close x { set eps 1e-[set ::tcl_precision] set my [log $x] set system [expr {log($x)}] if {abs($my-$system)>$eps*abs($system)} { puts "my log $x : $my" puts "system log($x) : $system" error "$x runs odd" } return $my }
-- Sarnold
GS 2016-01-14: Until we have the solution for above, here is an algorithm which computes the logarithm of a number between 0 and 1.
# Description: Log evaluation between 0 and 1 with a recursion formula # # / 2*u(i) \ # u(i+1) = u(i)*sqrt|-----------------| # \ u(i) + u(i-1) / # Arguments: # . x : the value to be computed # Results: # . y: the value of log(x) # . n: then number of iterations proc Log01 x { if {$x <= 0 || $x > 1} return set eps .000000001 set n 0 set y 0 set du 10000 set x2 [expr {$x*$x}] set u0 [expr {($x2 - 1.0/$x2)/4}] set u1 [expr {($x-1.0/$x)/2}] while {$du > $eps} { set u2 [expr {$u1*sqrt(2*$u1/($u1+$u0))}] set y $u2 incr n set du [expr {abs($u2-$u1)}] set u0 $u1 set u1 $u2 } return [list $y $n] } # Test for {set i 2} {$i < 10} {incr i} { set x [expr {1.0/$i}] set r [Log01 $x] puts "Log($x) = [format "%.8f" [lindex $r 0]] in [lindex $r 1] iterations" }
Test results:
Log(0.5) = -0.69314718 in 14 iterations Log(0.333333333333) = -1.09861229 in 15 iterations Log(0.25) = -1.38629436 in 16 iterations Log(0.2) = -1.60943791 in 16 iterations Log(0.166666666667) = -1.79175947 in 16 iterations Log(0.142857142857) = -1.94591015 in 16 iterations Log(0.125) = -2.07944154 in 17 iterations Log(0.111111111111) = -2.19722458 in 17 iterations