# Calculate e^x and ln(x)

Given a floating point x (x<100), return e^x and ln(x). The first 6 decimal places of the number have to be right, but any others after do not have to be correct.

You cannot have any "magic" constants explicitly stated (e.x. a=1.35914 since 1.35914*2 ~= e), but you can calculate them. Only use +, -, *, and / for arithmetic operators.

If x is less than or equal to 0, output ERROR instead of the intended value of ln(x).

Test Cases:

input: 2
output: 7.389056 0.693147
input: 0.25
output: 1.284025 -1.386294
input: 2.718281828
output: 15.154262 0.999999  (for this to output correctly, don't round to 6 places)
input: -0.1
output: 0.904837 ERROR


Shortest code wins.

• I assume you mean to exclude exponentiation of entirely (not just for the the calculation of e itself)? 2**(x*1.442695) for example seems a bit too easy. Nov 25, 2012 at 18:04
• @primo: yes, there is no exponentiation whatsoever, but things like product(*3) is ok. I guess I should rule out "magic constants" in the case of 1.442695. Nov 25, 2012 at 18:35
• You might want to also specify a valid range for the input - any approximation can lose accuracy if x becomes too large or too small. Nov 26, 2012 at 0:08
• @A.R.S.: added a boundary. Thanks. Nov 26, 2012 at 0:14
• No one uses APL!? Seriously? Dec 25, 2012 at 19:45

## PHP 109 107 bytes

<?for($g=1e4;--$g;$l=$y/$g+abs($y=$x>1?1-1/$x:$x-1)*$l)$e=1+$e/$g*$x.=fgets(STDIN);echo"$e ",$x>0?$l:ERROR;  $$\e^x\$$ is a fairly straight-forward calculation. I use a nested form of the sum of inverse factorials, which not only increases the convergence rate, but also allows for exponentiation at the same time: $$e^x = 1 + x \left( 1 + \frac x 2 \left( 1 + \frac x 3 \left( 1 + \frac x 4 \bigg( 1 + \dots \bigg)\right)\right)\right)$$ $$\\ln x\$$ is slightly more complicated. All convergent series seem to work for $$\x \le 1\$$ or $$\x \ge 1 \$$, but not both (Newton's iteration does not have this limitation, but requires the calculation of $$\e^{x_n}\$$ each step). This isn't really a problem, though, given the log identity: $$\ln x = -\ln \frac 1 x$$ This means that if, for example, the iteration you're using only works on $$\0 < x \le 1\$$ and $$\x > 1\$$, you can use the multiplicative inverse of $$\x\$$ and negate the result. Because I was using a nested identity for $$\e^x\$$, I also chose to use a nested identity for $$\\ln x\$$: $$\ln(1 + x) = x\left(1 - x\left(\frac 1 2 - x\left(\frac 1 3 - x\left(\frac 1 4 - \dots \right)\right)\right)\right)$$ where $$\0 < x \le 1\$$ Or equivalently, as demonstrated by Paul Walls' implementation: $$\ln(1 + x) = x - x\left(\frac x 2 - x\left(\frac x 3 - x\left(\frac x 4 - \dots \right)\right)\right)$$ I define the $$\0 < x \le 1\$$ case as $$\x-1\$$ (which is necessarily negative), using the absolute value for the inner product, and then allowing a bare $$\x\$$ value in the fraction to correct the sign. Sample I/O: $ echo 2 | php exp_ln.php
7.3890560989307 0.69314718055995

$echo 0.25 | php exp_ln.php 1.2840254166877 -1.3862943611199$ echo 2.718281828 | php exp_ln.php
15.154262234523 0.99999999983113

$echo -0.1 | php exp_ln.php 0.90483741803596 ERROR  ## Perl 9593 89 bytes $e=1+$e/$?*($x.=<>),$l=$_/$?+$l*abs,$_=$x>1?1-1/$x:$x-1while--$?;print"$e ",$x>0?$l:ERROR  Nearly identical to the PHP solution above, with a slightly larger iteration (65535 down to 0). Edits: • Both 2 byte improvements due to Paul Walls. • Four more bytes saved in Perl by (ab)using $?, which is stored internally as an unsigned short, and by using $_ to save parentheses in abs. • For x = 1e-4, I get php "1.0001000050002 -8.9909564381939" and perl "1.00010000500017 -8.99099322429857". Should be like "1.000100005 -9.21034037195" Anyways nice job taking advantage of ln x = -ln 1/x to use a nested expression Nov 26, 2012 at 13:49 • @milest x=1e-5 will be off by even more, because it's the same calculation as x=100000. As it is, x=1e-2 and x=100 are accurate to full floating point precision, and x=1e-3 and x=1000 are accurate to about 5 digits. If more accuracy is needed, the arbitrary 1e4 bound that I've chosen can be increased accordingly. Nov 26, 2012 at 14:25 ## Python 2 (168 char) basic implementation of power series I need to learn a golfing language =/ I increased the bound to 1e-14 (twice from 1e-7) since some values were off a bit in 6 decimal places, works well for input from 1e-5 to 100 (slows down at input approaches 0) x=input();t,r,i=1,0,1. while abs(t)>=1e-14:t,r,i=t*x/i,r+t,i+1 if x<=0:s='Error' else:z=(x-1.)/(x+1);t,s,i=2*z,0,1 while abs(t/i)>=1e-14:t,s,i=t*z*z,s+t/i,i+2 print r,s  • Doesn't python support m=1e-7? Nov 25, 2012 at 20:53 • yes it does but 1e-7 can be thought of as 1*10^-7 which might be thought of as exponentiation, so I'm not really sure if its allowed here Nov 25, 2012 at 20:59 • I will allow for scientific notation. Nov 26, 2012 at 0:02 ## Haskell, 166 (89 without I/O) s=1e-7 e x|x>s=1/e(-x)|x>0=1+x|y<-e$x+s=y-y*s
l x|x<1=0-l(1/x)|1>0=sum$map(s/)[1,1+s..x] n x|x<0="ERROR"|1>0=show$l x
main=interact$unwords.(\x->[show$e x,n x]).read


Takes an alternative approach: we use that

∂/∂x ex = ex

and solve the differential equation numerically, with a simple euler method. Similarly, use

ln x = 1x 1/x d‌x

and calculate the integral with the rectangular method.

Example:

$echo 2 | ./exp-and-log 7.389056835370484 0.6931472554471929$ echo 0.25 | ./exp-and-log
1.284025432730133 -1.3862944228194163
$echo 2.718281828 | ./exp-and-log 15.15426430695358 1.0000000576151333$ echo -0.1 | ./exp-and-log
0.9048374135134576 ERROR

It's quite amazingly inefficient, in fact it uses about 4 GB of memory even for these examples (since it's non-tail–recursive... you need to compile (in GHC) with -with-rtsopts=-K2G so it even accepts such a ridiculous stack size).

## JavaScript, 103101999793 90

This implementation is based on primo's comprehensive description of the algorithm he used.

for(e=l=x=prompt(g=1e5);--g;y=x-1,l=(x>1?y/=x:-y)*l+y/g)
e=1+e/g*x;


Edit:
- Trying to catch Perl. Stole a byte back from primo by copying his branch. :)
- 2 more bytes courtesy of primo.
- Finally, caught primo's version! With primo's help, of course... :)
- Simplified the assignment to L. Shaved 3 more bytes.

• It's somewhat humorous that defining Math.abs inline is actually shorter than using the built-in. Nov 27, 2012 at 7:39
• As far as catching perl goes, would it help if I pointed out that the initial values of e and l don't really matter? Dec 2, 2012 at 6:58
• @primo Nice catch! Dec 2, 2012 at 8:13
• I've got 93, by combining the y and l definitions: l=(x>1?y=1-1/x:-(y=x-1))*l+y/g Dec 14, 2012 at 7:29
• Very elegant. I probably spent over an hour trying to figure out a way to exploit the relationship between x<1 and y<0. You sir, are a genius! :) Dec 14, 2012 at 9:37

# R (101 bytes)

Note that $$e^{x} = \lim_{n \to \infty}\left(1 + \frac{x}{n}\right)^n.$$ Then, for large enough n, we can approximate e by a product.

n=1e+08;prod(rep(1+x/n,n))


Similarly, note that $$\log(x) = \int_{1}^{x}\frac{1}{t}dt \leq \Delta t \cdot \sum \frac{1}{t+\Delta t}$$

dt=0.1;sign(x-1)*sum((1/seq(min(1,x),max(1,x),by=dt))*dt))


Combined into one answer (80 bytes):

n=1e+08;c(prod(rep(1+x/n,n)),sign(x-1)*sum((1/seq(min(1,x),max(1,x),by=1/n))/n))


Will produce -Inf instead of ERROR in case x < 0.

 7.3890560 0.6931472
  1.284025 -1.386294
 15.15426  1.00000
 0.9048374      -Inf


Or, with the ERROR handling, 101 bytes:

n=1e+08;gsub("-Inf","ERROR",c(prod(rep(1+x/n,n)),sign(x-1)*sum((1/seq(min(1,x),max(1,x),by=1/n))/n)))

 "7.38905602540599"  "0.693147188059945"
 "1.28402541433558"  "-1.38629438611989"
 "15.154261581541"  "1.00000000372749"
 "0.904837420549773" "ERROR"

• A TIO link would be great.
– user7467
Oct 27, 2021 at 7:26