DUzun's Web
Programare, proiecte personale, divertisment

DUzun it's ME
 
/ 08 aprilie 2025, 22:38:10 /  
Conținut

Prims.php

x
 
<?php
/**
 * Prims class.
 *
 * @author DUzun (Dumitru Uzun)
 * @copyright Dumitru Uzun 2010
 * @web www.duzun.teologie.net
 *
 */
define('PRIMS_AUTOSAVE_COUNT', 1000);
/*------------------------------------------------------------------------------------------*/
class Prims
{
   static private $inst = NULL; // Obiectul Singletonal PkInts care contine lista interna de numere prime
   static private $nr_prims;
   protected function __construct()
   {
      if(empty(self::$inst))
      {
        self::$inst = new PkInts(dirname(__FILE__).'/../data/'.__CLASS__.'.bin', false, 2);
        $prims = array(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
        $l = self::$inst->len;
        if($l < count($prims)) self::$inst->ints = $prims; // lista initiala de primi
        else
        {
           $l = count($prims);
           $v = self::$inst->reset;
           for($i=0; $i<$l; $i++) if($v <> $prims[$i]) // daca in lista interna vreun nr e gresit
           {
              self::$inst->ints = $prims;              // resetam lista
              break;
           }
           else $v = self::$inst->next;
        }
        debug_('Prims->length: ' . self::$inst->len, __FILE__, __LINE__, "Prims::__construct");
      }
      else return false;
   }
   static function getInst()
   {
      if(empty(self::$inst)) new self();
      return self::$inst;
   }
   /*------------------------------------------------------------------------------------------*/
   /*! Nr elementelor prime din lista interna */
   static function count() { return self::getInst()->len; }
   /*! Lista interna de nr prime.
    *  Daca lista e mai mica ca $nr, se adauga nr neajuns la lista. */
   static function lista($nr = 0)
   {
      $ps = &self::getInst();
      if(!$nr) $nr = 4;
      $nr -= $ps->len;
      if($nr > 0) self::last($nr);
      return $ps->ints;
   }
   /*! Sterge lista interna de primi, rezervand $preserv elemente. */
   static function clear($preserv = 0)
   {
      $o = self::getInst();
      return $o->len = $preserv;
   }
   /*!
    * Returneaza ultimul prim din lista interna.
    * Daca $nr > 0, adauga $nr primi la lista.
    *
    * Nota: Pentru valori mari ale $nr, dureaza mult...
    * O($nr) = ($nr-$p)^2 (complexitatea)
    */
   static protected function last($nr = 1)
   {
//      if($nr < 0) return false;
     $o = self::getInst();
     $p = $o->last;
     while($nr)
     {
       $p += 2;
       $sp = floor(sqrt($p));
       $pr = true;
       $d = $o->reset; // $d parcurge lista de nr prime - divizor
       while($d !== false)
       {
         if($p % $d == 0){ $pr = false; break; } else
         if($d >= $sp) break;
         $d = $o->next;
       }
       if($pr)
       {
         $o->push($p);
         $nr--;
         if(empty(self::$nr_prims)) self::$nr_prims = $o->len;
         if(defined('PRIMS_AUTOSAVE_COUNT') && $o->len - self::$nr_prims >= PRIMS_AUTOSAVE_COUNT)
         {
            $o->save(false, true);
            self::$nr_prims = $o->len;
         }
       }
     }
     return $p;
   }
   /*!
    * Adauga la lista interna de nr prime numerele prime <= $nr.
    *
    * Nota: Pentru valori mari ale $nr, dureaza mult...
    * O($nr) = ($nr-$p)^3 (complexitatea)
    */
   static protected function add_lte_prims($nr) // add less then or equal prims
   {
     $nr = abs($nr);
     do $p = self::last(1); while($nr > $p);
     return $p;  // $nr <= $p
   }
   /*!
    * Returneaza al $idx-lea nr prim.
    *
    * Nota: Primul numar prim are indexul 0 ($idx==0)
    * Daca $idx depaseste count(), sunt generate nr prime neajuns
    * pana la $idx.
    */
   static function get($idx)
   {
      $o = self::getInst();
      $l = $o->len;
      if($idx >= $l) self::last($idx - $l + 1); else
      if($idx < 0) {
         $idx += $l;
         if($idx < 0) die("List index out of bounds: $idx<br />\n<b>Math::get()</b>");
      }
      return $o->get_int_($idx);
   }
   /*!
    * Returneaza produsul primelor $n nr prime.
    * Daca $n < 0, se returneaza inversul produsului primelor -$n nr prime.
    */
   function prod($n)
   {
      $o = &self::getInst();
      if( $s = $n < 0 ) $n = -$n;
      if( $n >= $o->len ) self::last($n - $o->len);
      $p = 1;
      while($n-- && is_finite($p)) $p *= $o->get_int($n);
      return $s ? 1/$p : $p;
   }
   /*!
    * Cauta $nr in lista interna de nr prime. (Binary search)
    * Returneaza pozitia din lista, sau false, daca nu-l gaseste.
    *
    * O(log($nr))
    *
    * Atentie!
    *   Primul nr din lista e pe pozitia 0 !== false
    */
    static function search($nr)
    {
       return self::getInst()->search(abs($nr));
    }
   /*!
    * Cel mai mic nr prim mai mare sau egal cu $nr
    *     ($p >= $nr)
    */
   static function ceil($nr)
   {
     $nr = abs($nr) ;
     if($nr == 0 || $nr == 1) return false;
     if($nr < 4) return $nr; // 2 || 3
     $o = self::getInst();
     $p = $o->last;
     if($nr >  $p) return self::add_lte_prims($nr);
     if($nr == $p) return $p;
     // if($nr < $p)
     $p = $o->search_ceil($nr);
     return $p === false ? false : $o->get_int_($p);
   }
   /*!
    * Cel mai mare nr prim mai mic sau egal cu $nr
    *     ($p <= $nr)
    */
   static function floor_idx($nr)
   {
     $nr = abs($nr) ;
     if($nr == 0 || $nr == 1) return false;
     if($nr == 2) return 0;
     if($nr == 3) return 1;
     $o = self::getInst();
     $p = $o->last;
     if($nr > $p)
     {
//        $q = self::add_lte_prims($nr);
       $q = self::last(1);
       if($nr <  $q) return $o->len-2; // $p < $nr < $q
       while($nr > $q) {
         $p = $q;
         $q = self::last(1);
       }
       $p = $q;   // last is $p futher
     }
     if($nr == $p) return $o->len;
     // if($nr < $p)
     return $o->search_floor($nr);
   }
   
   function floor($nr)
   {
     $idx = $o->floor_idx($nr);
     return $idx === false ? false : $o->get_int_($idx);
   }
/*------------------------------------------------------------------------*/
   static function div1($a, $b)
   {  // 9.00 x 10000 | 0.090 x 1000
      // greedy-iterativ
      $r = 1;
      for($i=$a<$b?$a:$b; $i>1; $i--) if(($a%$i==0)&&($b%$i==0)&&($r%$i!=0)) $r *= $i;
      return $r;
   }
   static function div1a($a, $b)
   {  // greedy-iterativ optimizat
      $r = 1;
      $min = $a<$b?$a:$b;
      $i = 0;
      while($p<=$min)
      {
         $p = self::get($i++);
         if($a%$p==0 && $b%$p==0)
         {
           do {
           $r *= $p;
           $a = floor($a /$p);
           $b = floor($b /$p);
           } while($a%$p==0 && $b%$p==0);
           $min = $a<$b?$a:$b;
         }
      } 
      return $r;
   }
   static function div2($a, $b)
   {  // 0.20 x 10000 | 0.016 x 1000
      // Euclid: recursiv-multiplicativ
//       if(!$a) return $b;  // $a > $b
      if(!$b) return $a;
      return self::div2($b, $a % $b);
   }
   static function div3($a, $b) // $a > 0 && $b > 0
   {  // err  x 10000 | 0.067 x 1000  // la numere mari apar probleme in PHP
      // Euclid: recursiv-aditiv
      if($a > $b) return self::div3($a - $b, $b);
      if($a < $b) return self::div3($a, $b - $a);
      return $a;
   }
   static function div4($a, $b) // cea mai rapida si mai frumoasa versiune
   {  // 0.10 x 10000 | 0.015 x 1000
      // Euclid: iterativ-multiplicativ
      while($b) { $r = $a % $b; $a = $b; $b = $r; }
      return $a;
   }
   static function div5($a, $b) // $a > 0 && $b > 0
   {  // 0.27 x 10000 | 0.022 x 1000
      // Euclid: iterativ-aditiv
//       if(!$a ^ !$b) return 1;
//       $a = abs($a); $b = abs($b);
      while($a != $b) if($a>$b) $a=$a-$b; else $b=$b-$a;
      return $a;
   }
/*------------------------------------------------------------------------*/
   /*!
    * Algoritmul lui Euclid de aflare a
    *   celui mai mare divizor comun a doua numere, $a si $b
    * Notatie: (a, b)
    */
   static function divCom($a, $b)
   {
      if($a < $b) { $r = $a; $a = $b; $b = $r; }
      // Euclid: iterativ-multiplicativ
      while($b) { $r = $a % $b; $a = $b; $b = $r; }
      return $a;
   }
   /*!
    * Cel mai mic multiplu comun a doua numere, $a si $b
    *
    * Notatie: [a, b]
    */
   static function mulCom($a, $b)
   {
     // [a,b] = (a*b) / (a,b)
     return (int)( $a*$b / self::divCom($a, $b) );
   }
/*------------------------------------------------------------------------*/
   /*!
    * Cel mai mare divizor comun.
    *
    * Sintaxa:
    *   CMMDC(mixed $arr[, mixed $arr1[, mixed $arr2...]])
    */
   static function CMMDC($arr)
   {
     if(is_array($arr))
     {
        sort($arr, SORT_NUMERIC); // daca toate sunt pozitive si exista 1, nu se vor mai parcurge celelalte elemente
        $r = array_pop($arr);
        foreach($arr as &$v)
        {
           if($r == 1 || $r == -1) break;
           $r = self::divCom($r, self::CMMDC($v));
        }
        $arr = $r;
     }
     if(func_num_args()==1) return $arr;
     for($i=1; $i < func_num_args(); $i++)
     {
        if($arr == 1 || $arr == -1) break;
        $v = func_get_arg($i);
        $arr = self::divCom($arr, self::CMMDC($v));
     }
     return $arr;
   }
   /*!
    * Cel mai mic multiplu comun.
    *
    * Sintaxa:
    *   CMMMC(mixed $arr[, mixed $arr1[, mixed $arr2...]])
    */
   static function CMMMC($arr)
   {
     if(is_array($arr))
     {
        $r = array_pop($arr);
        foreach($arr as &$v) $r = self::mulCom($r, self::CMMMC($v));
        $arr = $r;
     }
     if(func_num_args()==1) return $arr;
     for($i=1; $i < func_num_args(); $i++)
     {
        $v = func_get_arg($i);
        $arr = self::mulCom($arr, self::CMMMC($v));
     }
     return $arr;
   }
/*------------------------------------------------------------------------*/
   /*!
    * Verifica daca numarul $n este prim
    * O($n) <= 1 (complexitate)
    */
   static function isPrim($nr)
   {
     if($nr == 2) return true; // Unicul numar prim par
     if(~$nr&01 || $nr == 0 || $nr == 1 || $nr == -1) return false; // 0, +-1 si nr pare nu sunt prime
     $nr = abs($nr); // $nr se precauta ca nr pozitiv
     $o = self::getInst(); // lista interna de numere prime
     $p = $o->last;
     // Daca este mai mic decat ultimul prim din lista interna
     if($nr <= $p) { // se cauta in lista interna de nr prime
       return self::search($nr) !== false;
     }
     // $nr > $p: $nr este in afara listei (mai mare)
     $lim = floor(sqrt($nr));
     $p = $o->reset;
     while($p !== false) {
       if($nr % $p == 0) return false;
       if($p > $lim)     return true;
       $p = $o->next;
     }
     // Daca lista de nr prime e prea mica, // se cauta folosind algoritmul liniar
     do {
       $p = self::last(1); // adaugam un element la lista de nr prime
       if($nr % $p == 0) return false;
     } while($p <= $lim);
     // In sfarsit, daca nu se imparte la nimic, $nr este prim
     return true;
   }
   /*!
    *  Aplicarea teoremei de baza a aritmeticii:
    *    Orice numar intreg (>1) este prim sau
    *    se descompune in produs de factori primi.
    *  Aceasta descompunere se numeste forma canonica a numarului intreg.
    *
    *  Fie $n = pow(p1,a1)*pow(p2,a2)*...*pow(pn,an).
    *  @return array(p1=>a1, p2=>a2, ..., pn=>an);
    */
   static function canonic($nr)
   {
     if($nr == 0 || $nr == 1 || $nr == -1) return array(); // nici prim, nici compus
     $r = array();
     if($nr<0){ $r[-1] = 1; $nr = -$nr; }
     if(self::isPrim($nr)){ $r[$nr] = 1; return $r; } // $nr este prim sau...
     // se descompune in produs de factori primi
//      self::getInst();  // se keama in self::isPrim()
     $l = self::last(0);
     $o = &self::$inst;
     $p  = $o->reset;
     while($p !== false) {
       while($nr % $p == 0) { $r[$p]++; $nr = floor($nr/$p); }
       if($nr == 1) return $r;
       $p = $o->next;
     }
     do {
       $p = self::last(1);
       while($nr % $p == 0) { $r[$p]++; $nr = floor($nr/$p); }
     }
     while($nr>1);
     return $r;
   }
   /*!
    * Functia inversa a canonic($n)
    */
   static function can2nr($c)
   {
      $r = 1;
      foreach($c as $pr=>$pw) while($pw--) $r *= $pr;
      return $r;
   }
   /*!
    *  Formeaza codul HTML al formei canonice a nr $n.
    *  $n poate fi numarul descompunerea sa (array)
    *
    *  @return if($array) array(p1=>p1^a1, p2=>p2^a2, ..., pn=>pn^an); /
    *          else       p1^a1 * p2^a2 * ... * pn^an
    */
   static function canHTML($nr, $array=false)
   {
      if(!is_array($nr)) $nr = self::canonic($nr);
      foreach($nr as $pr=>&$pw) $pw = "$pr".($pw>1?"<sup>$pw</sup>":'');
      return $array ? $nr : implode(' * ', $nr);
   }
   /*!
    *  Suma divizorilor naturali ai numarului $nr
    */
   function sum_div($nr)
   {
   }
   /*!
    *  Numarul divizorilor naturali ai numarului $nr
    */
   function nr_div($nr)
   {
   }
   /*!
    *  Cantitatea ne numere reciproc prime cu $nr
    *  si mai mici decat $nr
    */
   function lt_nr_prims($nr) // less then $nr prims
   {
   }
}
/*------------------------------------------------------------------------------------------*/
?>

Aici acumulez programe şi algoritmi interesanti alcătuiţi de mine (cu mici excepţii) pe parcursul studierii unor limbaje de programare.

Cea mai mare parte din ele sunt realizate în Pascal. 

Nu am scopul creării unui curs specializat sau a descrierii detaliate a anumitor limbaje, ci doar prezint informaţii utile, plus ceva exemple interesante...

 

Răsfoitorul de fișiere (File Browser):

Codul sursă al programelor este organizat în mape şi fişiere.

Paginile care conțin cod sursă de programe de regulă au un răsfoitor de fișiere în partea stangă a paginii reprezentat de un bloc cu titlul „File Browser”.

Pentru a vizualiza un program sau conţinutul unei mape, faceţi click pe numele fişierului / mapei. Dacă fişierul nu este textual, el se va descărca automat, iar dacă este textual, conținutul lui se va afișa într-un bloc pe centrul paginii.

Pentru a descărca un fişier, faceţi click pe dimensiunea (size) lui.

arr_d Limba / Language


 


arr_r Login
 
 
Loading...