Source of packages/Combie/Math/Bc.php

<?php
/**
 * BC Math
 *
 * Verschiedenste Methoden, um mit großen Zahlen zu rechen
 *
 * @filesource
 * @author Combie <uli@combie.de>
 * @version $Id$
 * @package Combie
 * @subpackage Math
 */


namespace Combie\Math;

/**
 * BC Math
 *
 * Rechnen mit unbegrenzter Genauigkeit
 * @example packages/Combie/tests/math/test_bc.php
 * @package Combie
 * @subpackage Math
 */
class Bc
{

/**#@+
 * interne Variablen
 * @var array Cache
 */
  
private static $fakutaetcache = array();
  private static 
$basecache = array();
/**#@-*/

/**
 * Fakultät
 *
 * Berechnet rekursiv die Fakaltät von beliebig großen Zahlen.
 * Um die Berechnungen zu beschleunigen, werden die Zwischenergebnisse
 * im Cache gespeichert.
 *
 * @param string|integer Eine Integer oder BCD Zahl
 * @return string Fakultät von Zahl
 */
  
public static function fakultaet($zahl)
  {
    if(-
=== bccomp($zahl,2)) return 1;
    if(isset(
self::$fakutaetcache[$zahl])) return self::$fakutaetcache[$zahl];
    
self::$fakutaetcache[$zahl] = bcmul($zahl,self::fakultaet(bcsub($zahl,1)));
    return 
self::$fakutaetcache[$zahl];
  }


/**
 * Base Konverter
 *
 * Entspricht in etwa der PHP Funktion base_convert()
 *
 * Erweitert um:
 * - Eine Vorzeichenbehandlung
 * - Arbeitet bis zur Base 62
 * - Zahlenbereich der PHP BC* Funktionen
 *
 * @param string|integer Eine Integer oder BCD Zahl
 * @param integer Basis der Quellzahl 2<=basis<=62
 * @param integer Basis des Ergebnisses 2<=basis<=62
 * @return string Zur neuen Basis umgewandelte 
 */
  
public static function base_convert($value,$quellformat,$zielformat)
  {
    
$vorrat '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    if(
max($quellformat,$zielformat) > strlen($vorrat))
        throw new 
InvalidArgumentException('Bad Format max: '.strlen($vorrat));
    if(
min($quellformat,$zielformat) < 2)
        throw new 
InvalidArgumentException('Bad Format min: 2');
    
$dezi   '0';
    
$level  0;
    
$result '';
    
$value  trim((string)$value,"\r\n\t +");
    
$vorzeichen '-' === $value{0}?'-':'';
    
$value  ltrim($value,"-0");
    
$len    strlen($value);
    for(
$i=0;$i<$len;$i++)
    {
      
$wert strpos($vorrat,$value{$len-1-$i});
      if(
FALSE === $wert)
          throw new 
InvalidArgumentException('Bad Char in input 1');
      if(
$wert >= $quellformat)
          throw new 
InvalidArgumentException('Bad Char in input 2');
      
$dezi bcadd($dezi,bcmul(bcpow($quellformat,$i),$wert));
    }
    if(
10 == $zielformat) return $vorzeichen.$dezi// abkürzung
    
while(!== bccomp(bcpow($zielformat,$level++),$dezi));
    for(
$i=$level-2;$i>=0;$i--)
    {
      
$factor  bcpow($zielformat,$i);
      
$zahl    bcdiv($dezi,$factor,0);
      
$dezi    bcmod($dezi,$factor);
      
$result .= $vorrat{$zahl};
    }
    
$result = empty($result)?'0':$result;
    return 
$vorzeichen.$result ;
  }
  
/**
 * Cache Base Konverter
 *
 * Erweitert die Methode base_convert() um einen Cache
 *
 * @param string|integer Eine Integer oder BCD Zahl
 * @param integer Basis der Quellzahl 2<=basis<=62
 * @param integer Basis des Ergebnisses 2<=basis<=62
 * @param integer Maximale Anzahl Elemente im Cache
 * @return string Zur neuen Basis umgewandelte Zahl
 */
  
public static function cache_base_convert($value,$quellformat,$zielformat,$max=1000)
  {
    if(
count(self::$basecache)>$maxarray_shift(self::$basecache); // begrenzen
    
$cache_key "$value|$quellformat|$zielformat;
    if(!isset(
self::$basecache[$cache_key]))
     
self::$basecache[$cache_key] = self::base_convert($value,$quellformat,$zielformat);
    return 
self::$basecache[$cache_key];
  }
}
 
?>