http://qs321.pair.com?node_id=652437


in reply to Exponential Function Programming

I think that this is more noble and incomprehensible :>)
#!/usr/bin/perl use strict; use warnings; sub exp_ { my $x = shift; my ($d, $ret, $i) = (1.0, 1); while ($ret - $d != $ret) { $d *= $x/++$i; $ret += $d; } return $ret; } for (1..100) { print "exp($_) = ".exp_($_)."\n"; }

Replies are listed 'Best First'.
Re^2: Exponential Function Programming
by ikegami (Patriarch) on Nov 22, 2007 at 20:21 UTC
    $ret - $d != $ret is interesting. One would think it's the same as $d (in boolean context), but it isn't. By testing the effect of $d ($ret - $d != $ret) instead of $d itself, the loop can be ended sooner.
    my $ret = 1; for my $d (1e-15, 1e-20) { printf("%g %d %d\n", $d, ( $d )?1:0, ( $ret-$d != $ret )?1:0, ); }
    1e-015 1 1 # Often equivalent. 1e-020 1 0 # But not when there's an underflow.
      Of course, underflow behaves friendly in this case. But my prime goal was to demonstrate no necessity for evaluating both factorial and power in each loop.

        But such a demonstrations wasn't necessary for me since I had finished writing the following from scratch before you posted your solution. (I didn't post it since I didn't want to do the OP's homework for him.)

        sub ikegami_exp { my ($x) = @_; my $last = 0; my $result = 1; my $acc = 1; for (my $n = 1; abs($result-$last)>0; $n++) { $last = $result; $acc *= $x/$n; $result += $acc; } return $result; } for (1, 0.1, 10, 3.14, 0.1234, 100) { printf("%.16e: exp() = %.16e ikegami_exp() = %.16e\n", $_, exp($_), ikegami_exp($_), ); }

        The only difference was the terminating condition, so naturally, that's what interested me :) Mine goes into an infinite loop if you try to find ikegami_exp(1000), but that's easily fixed by replacing abs($result-$last)>0 with $result != $last.