$temp1
, $temp2
, and $temp3
, for example, are all MathObject Reals, not Perl reals. That means that when you do comparisons with them, they are fuzzy comparisons. That is, they respect the tolerance
and tolType
values in the context. Note that this applies not just to equality checks, but also to inequality checks as well. This is because you don't want both $a == $b
and $a > $b
to be true at the same time. That is, $a < $b
, $a == $b
, and $a > $b
should be mutually exclusive. The MathObject comparisons are arranged to work that way.
In your case, if you get a value like 1822.0004823, this is considered to be equal to 1822 by the fuzzy comparison, so $tmp3 > $p3
is false even though $p3 = 1822
. Indeed, the limit as n goes to infinity of your formula is $p0*e^(t*r)
, which is 1822.1188, which is fuzzy-equal to 1822, so you never get $temp3 > $p3
, and the is why the problem times out.
You probably want to convert to perl reals rather than MathObjects for the computation. You can use $temp3->value
for that, as this is the internal Perl real that underlies the MathObject Real. Also, if you are going to be evaluating a MathObject formula multiple times, you may want to create a perl function from the formula rather than calling eval()
repeatedly, as that will be much more efficient. For example, $F = $f->perlFunction
will get you a perl subroutine reference as $F
and you can call $temp3 = &$F($n3)->value
to get the Perl real result of the function at $n3
.
Even so, however, your loop is pretty inefficient. You could use a faster algorithm, for example the bisection algorithm (or Newton's method if you want to get fancy about it). Here is one approach:
$p0 = 1000; $t = 5; $r0 = 12; $r = $r0/100; $f = Formula("$p0*(1 + $r/n)^($t*n)"); $F = $f->perlFunction; $p1 = 1822; # # Assume the value you want is between these two # (they should be a power of two apart). # $n0 = 12; $n1 = $n0 + 2**10; # # Use bisection to locate the two values that are # one apart on opposite sides of the desired value. # (In this case, it will take 10 iterations to find it # as opposed to the 541 iterations for your version # that simply increments $n3, which is 54 times faster.) # while ($n1 - $n0 > 1) { $n2 = ($n0 + $n1) / 2; $f2 = &$F($n2)->value; if ($f2 > $p1) {$n1 = $n2} else {$n0 = $n2} } # # $n0 is below the value, $n1 is above it. # TEXT($n1);Hope that clears up the issues for you.