Профессионал
Покинул форум
Сообщений всего: 9095
Дата рег-ции: Июнь 2007
Откуда: Berlin
Помог: 707 раз(а)
Ниже привожу код, оформленный в класс, который позволяет проводить базовые операции над целочисленными операндами с получением целочисленного результата. Суть отличия от обычных, встроенных арифметических операций в том, что поддерживаются операнды практически любой длины.
Код является по сути набором методов, то есть объединение в класс - весьма условно и скорее служит для удобства, нежели преследует архитектурные цели.
PHP:
скопировать код в буфер обмена
class Calculator
{
{
{
return null ;
}
$sA = $rgArgs [ 0] ;
$sB = $rgArgs [ 1] ;
return $this -> _pow_simple( $sA , $sB ) ;
}
public function factorial( $sA )
{
if ( ! isset ( $sA ) || ! preg_match ( '/^[-+]{0,1}[0-9]+$/' , $sA ) || $this -> _get_negative
( $sA ) ) {
return null ;
}
$sA = ( string) $sA ;
return $this -> _factorial_simple( $sA ) ;
}
{
{
return null ;
}
$sA = ( string) $sA ;
return $sA [ 0 ] == '-' ?
substr ( $sA , 1
) : $sA ; }
public function mult( )
{
{
return null ;
}
{
return ( string) $rgArgs [ 0] ;
}
$sResult = '1' ;
for ( $i = 0 ; $i < count( $rgArgs ) ; $i ++ )
{
$sResult = $this -> _mult_simple( $sResult , $rgArgs [ $i ] ) ;
}
return $sResult ;
}
public function sum( )
{
{
return null ;
}
{
return ( string) $rgArgs [ 0] ;
}
$sResult = '0' ;
for ( $i = 0 ; $i < count( $rgArgs ) ; $i ++ )
{
$sResult = $this -> _get_negative( $rgArgs [ $i ] ) ?
$this -> _diff_simple( $sResult , $this -> abs ( $rgArgs [ $i ] ) ) :
$this -> _sum_simple( $sResult , $rgArgs [ $i ] ) ;
}
return $sResult ;
}
public function diff( )
{
{
return null ;
}
$sA = $rgArgs [ 0] ;
$sB = $rgArgs [ 1] ;
//-|A| -(-|B|) = |B|-|A|
if ( $this -> _get_negative( $sA ) && $this -> _get_negative( $sB ) )
{
return $this -> _diff_simple( $this -> abs ( $sB ) , $this -> abs ( $sA ) ) ;
}
//|A| -(-|B|) = |A|+|B|
if ( ! $this -> _get_negative( $sA ) && $this -> _get_negative( $sB ) )
{
return $this -> sum ( $this -> abs ( $sA ) , $this -> abs ( $sB ) ) ;
}
//(-|A|) -(|B|) = -(|A|+|B|)
if ( $this -> _get_negative( $sA ) && ! $this -> _get_negative( $sB ) )
{
return '-' . $this -> sum ( $this -> abs ( $sA ) , $this -> abs ( $sB ) ) ;
}
//|A| -(|B|) = |A|-|B|
if ( ! $this -> _get_negative( $sA ) && ! $this -> _get_negative( $sB ) )
{
return $this -> _diff_simple( $this -> abs ( $sA ) , $this -> abs ( $sB ) ) ;
}
}
protected function _pow_simple( $sA , $sB )
{
if ( $sB == '0' || $sB == '1' )
{
return $sA ;
}
if ( $sA == '1' )
{
return '1' ;
}
$sD = $sA ;
$sI = '1' ;
while ( $sI != $sB )
{
$sA = $this -> _mult_simple( $sA , $sD ) ;
$sI = $this -> _sum_simple( $sI , '1' ) ;
}
return $sA ;
}
protected function _factorial_simple( $sA )
{
if ( $sA == '1' )
{
return '1' ;
}
return $this -> mult ( $this -> _factorial_simple( $this -> diff ( $sA , '1' ) ) , $sA ) ;
}
protected function _mult_simple( $sA , $sB )
{
$sSign = '' ;
if ( $this -> _get_negative( $sA ) ^ $this -> _get_negative( $sB ) )
{
$sSign = '-' ;
}
$sA = strrev ( $this -> abs ( $sA ) ) ; $sB = strrev ( $this -> abs ( $sB ) ) ; for ( $i = 0 ; $i < strlen( $sA ) ; $i ++ )
{
for ( $j = 0 ; $j < strlen( $sB ) ; $j ++ )
{
$iCR = ( int) $sA [ $i ] * ( int) $sB [ $j ] ;
$k = $i + $j ; //-1;
while ( $iCR > 0)
{
$iCR += ( isset ( $rgC [ $k ] ) ?
$rgC [ $k ] : 0
) ; $rgC [ $k ] = $iCR % 10 ;
$iCR = ( int) ( $iCR / 10) ;
$k ++;
}
}
}
}
protected function _diff_simple( $sA , $sB )
{
{
}
elseif ( strlen ( $sA ) > strlen
( $sB ) ) {
}
$sSign = '' ;
$iC = 0 ;
if ( $this -> _compare_longs( $sA , $sB ) ==- 1)
{
$sA = $sA ^ $sB ;
$sB = $sA ^ $sB ;
$sA = $sA ^ $sB ;
$sSign = '-' ;
}
for ( $i = $iMax - 1 ; $i >= 0 ; $i -- )
{
$iC += ( int) $sA [ $i ] - ( int) $sB [ $i ] + 10 ;
$sA [ $i ] = ( string) ( $iC % 10) ;
$iC = $iC < 10?- 1: 0 ;
}
}
protected function _sum_simple( $sA , $sB )
{
{
}
elseif ( strlen ( $sA ) > strlen
( $sB ) ) {
}
$iC = 0 ;
for ( $i = $iMax - 1 ; $i >= 0 ; $i -- )
{
$iC += ( int) $sA [ $i ] + ( int) $sB [ $i ] ;
$sA [ $i ] = ( string) ( $iC % 10) ;
$iC = ( int) ( $iC / 10) ;
}
if ( $iC > 0)
{
$sA = ( string) $iC . $sA ;
}
return $sA ;
}
protected function _get_negative( $sA )
{
return $sA [ 0 ] == '-' ;
}
protected function _compare_longs( $sA , $sB )
{
if ( $iA < $iB )
{
return - 1 ;
}
if ( $iA > $iB )
{
return 1 ;
}
for ( $i = 0 ; $i < $iA ; $i ++ )
{
if ( $sA [ $i ] > $sB [ $i ] )
{
return 1 ;
}
if ( $sA [ $i ] < $sB [ $i ] )
{
return - 1 ;
}
}
return 0 ;
}
protected function _get_args( $rgArgs )
{
{
}
{
$rgArgs = $rgArgs [ 0] ;
}
return $rgArgs ;
}
}
Пример использования: calculator.php:
Пример вывода:
CODE (
bash ):
скопировать код в буфер обмена
user@ host:/ path$ php calculator.php abs -999
string( 3 ) "999"
user@ host:/ path$ php calculator.php sum 284000000000000000000000 ,7876667
string( 24 ) "284000000000000007876667"
user@ host:/ path$ php calculator.php factorial 1100
string( 2870 ) "53437084880926377034242155822950561183080130768866895408827458818036618050723014259335974351566788327415467514488987033614582476645694464261738910473380885803623188713714545198124600746227142898076872654482044562793852138469677927330572749576948166807421216877498208458769005405366305220797476530746185417476140782853546532719240751414684044603768883655817696461533721419437912125211548097906523004133705326338238190387850483847780372458822923605205280273714625078767863125493425503475250719583192283718603023987580777780035594813037613795902372520221886503677746281612405469606784962303354557187806801326271107816217722875294947071835822552429855506265930472623552940043968375099545722982577206331181572059532678281770892042093628816805623646577311781257247365411215175318229952887274698387234062919360695915639222369179043852637274593590667561348816681249809804769738621480138253259745750162388467598365561726569010392596479459233302432353681098301798797894434267786419982234226196634154442756631212508306232465619001682438953114007137692949367324856071217925158630122800389968328140113994331216849121360746519587860857407128917920142291872364024648458248977997760361360471884983431550636400392657427356942110542723446483822959503637292174818359270147883844245449127993570399680145426326859121741129303986870840568357454719368907061892985017459280119751754150743559728998295556732360250510038817844274754285134199896907638396447772737827107154796119201921536215055057930454911959321972058937160676911357720743058994504672070549484826113247358505388161799865617708367349954370380853219243288318629194580898980578192438937035768656839681865937931209188508228267083150656101893608065513697027997680322239292135637993681781912498871451282367323691586047201433108789851894379984404592216092303916341628274737895100530937654565448323856309779964541012016062668881698149445697033513467332799250377144771926250403307819405123627234925136330333303194372550567266647893455948506593051342066573726745648579107585985953658931045614036038155596569125812922579750260586849926124666596524551569945200247660633286983652662621181138959151246904073105358802979855205418823070789221362661986273869727763296788726872748791940251859679734295741968501303689117417827157419981384831723405209115952963781151997639090113111889675710526793448609726730199591174357535880032929705149172105146812236476055910588649481636927879360190085978752657227077124882768256913401349756816955057706206475508584494415633608256789303048043193593527406679352116588129444309915056549129527927635234094060955675954342173050125247634953207808000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
Кстати, знаменитый "гугол" оказывается не таким уж и большим:
CODE (
bash ):
скопировать код в буфер обмена
user@ host:/ path$ php calculator.php pow 100 ,100
string( 201 ) "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
(в принципе, логично, так как 100^100 = (10^2)^100 = 10^(2*100) = 10^200, то есть 1 и 200 нулей) - а, между тем, считается, что это больше, чем число молекул в известной части Вселенной.
upd. Поправка: Гугол - равен 10^100, а не 100^100, таким образом, он еще вдвое "короче" записи выше. Тем не менее, число молекул известной части Вселенной меньше и настоящего "гугола", поскольку имеет порядок 10^79..10^81
Основной упор сделан, разумеется, на алгоритмы длинной арифметики, и, хотя базовая валидация включена для примера в методы abs или factorial, сделано это скорее для наглядности - чтобы при желании её можно было добавить и в остальных случаях.
Сделана поддержка операций:
sum - длинная сумма
diff - длинная разность
abs - длинный модуль
mult - длинное произведение
pow - длинное возведение в степень
factorial - длинный факториал
при этом последние две опираются на предыдущие, и , таким образом, из этого набора можно собрать некоторые другие вспомогательные функции. Длинное деление не возвращает целочисленного результата в общем случае и потому не реализовано.
-----Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.