<?
// ---------------- Constants ----------------

define ('LENGTH'12);
define ('ZEROS''00000000000000000000');
define ('MAX'1000000000000); // LENGTH 0'er.
define ('MAXLIMIT'30000); // Serverbestemt - i princippet næsten uendelig.

// ---------------- Functions ----------------

function set_value (&$var,&$val,$def=1) {
    if (isset(
$val))
        
$var=$val;
    else
        
$var=$def;
}

function 
zerofill ($block) {
    
$extra=LENGTH-strlen($block);
    return 
substr(ZEROS,0,$extra).$block;
}

function 
long_divide ($number,$n) {
    
$rest=0;
    foreach (
$number as $nr => $block) {
        
$tal=$block+$rest*MAX;
        
$number[$nr]=floor($tal/$n);
        
$rest=$tal%$n;
    }
    return 
$number;
}

function 
long_add ($number,$addend) {
    
$blocks=count($number);
    
$mente=0;
    for (
$nr=$blocks-1$nr>=0; --$nr) {
        
$sum=$number[$nr]+$addend[$nr]+$mente;
        
$number[$nr]=$sum%MAX;
        
$mente=$sum/MAX;
    }
    
$number[0]+=$mente;
    return 
$number;
}

function 
display ($e) {
    GLOBAL 
$decimals;
    
$first_digit=floor(array_shift($e));
    echo 
"<table>\n";
    echo 
"<tr><td>e = $first_digit,</td></tr>\n";
    
$buffer="";
    
$echoed=10;
    
$units=0;
    echo 
"<tr>";
    foreach (
$e as $block) {
        
$buffer.=zerofill($block);
        while (
strlen($buffer)>&& $echoed<$decimals) {
            
$echoed+=10;
            echo 
"<td>".substr($buffer,0,10)."</td>";
            
$buffer=substr($buffer,10);
            if (++
$units%5==0)
                echo 
"</tr>\n<tr>";
        }
    }
    
$rest=$decimals-$echoed+10;
    echo 
"<td>".substr($buffer,0,$rest)."</td></tr>";
    echo 
"</table>\n";
}

// ---------------- Main ----------------

if (isset($_GET['show']))
    
show_source('beregn_e.inc.php');
exit();

echo 
"<pre>           1     1      1<br>";
echo 
" e = 1 + --- + --- + --- ...<br>";
echo 
"           1!    2!     3!</pre>\n";

set_value($decimals,$_POST['digits'],5);
$blocks=floor($decimals/LENGTH);

echo 
"
<p>Her kan man beregne konstanten e, grundtal for den naturlige logaritme.
På grund af tidsbegrænsninger på serveren er der sat en maksimum på 30'000
decimaler, men metoden i sig selv er kun begrænset af computerens
tilgængelige arbejdslager.</p>
<p>Der er ikke noget sindsoprivende nyt i beregningerne, og på nogle
hjemmesider kan man få programmer der er mange gange hurtigere, men
<a href='?page=matematik/beregningsmetode'>metoden</a>
er enkel og kan implementeres i stort set alle programmeringssprog.</p>

<form action='#' method='post'>
<p>Hvor mange decimaler? <input type='text' size='6' name='digits' value='
$decimals'>
<input type='submit' name='send' value='OK'></p>
</form>
"
;

if (isset(
$_POST['send']) && $decimals<=MAXLIMIT) {
    
$blocks=floor($decimals/LENGTH);
    while (
$blocks*LENGTH<$decimals)
        ++
$blocks;
    ++
$blocks;

    
$e=array_fill(0,$blocks,0);
    
$e[0]=1;
    
$rec_fact=$e;
    
$old_e=[0];

// ---------------- Compute ----------------

    
$n=0;
    
$compare=0;
    
$start microtime(1);
    while (
$compare<=$blocks) {
        ++
$n;
        
$old_e=$e;
        
$rec_fact=long_divide($rec_fact,$n);
        
$e=long_add($e,$rec_fact);

        if (!isset(
$e[$compare]))
            break;
        if (
$e[$compare]==$old_e[$compare])
            ++
$compare;
    }
    echo 
" Beregningstid i sekunder: "
     
.number_format(microtime(1)-$start,6,',',"'")."<br>"
     
." Sidste fakultetstal: $n";
    
display($e);
}
?>