Author |
Message |
Александр Михалицын
Модератор
Joined: 23 May 2008
Posts: 1299
Карма: 83 поощрить/наказать
|
Posted: Fri Sep 25, 2009 11:55 am (написано за 33 секунды)
Post subject:
|
|
А вот от меня вариант решалки уравнений с комплексными коэфициентами, на основе Юриного "класса" (надо будет свой доработать): Code (JavaScript): | скопировать код в буфер обмена | var qrt_equation_solver = new function() { var self = this;
var find_D = function(a, b, c) { // return b.mul(b).sub(new Z(4, 0).mul(a).mul(c)); }
var find_sqrt_D = function(D) { // return D.pow(1/2, 0); }
self.solve = function(a, b, c) { // //
//Re = 2; Im = 0; var TWO = new Z(2, 0);
// var sqrt_D = find_sqrt_D(find_D(a, b, c));
//
//x1 (-b + sqrt(D) / 2a) var x1 = b.neg().add(sqrt_D).div(TWO.mul(a));
//x2 (-b - sqrt(D) / 2a) var x2 = b.neg().sub(sqrt_D).div(TWO.mul(a));
return [x1, x2]; } }
WSH.Echo( qrt_equation_solver.solve( new Z(2,0) , new Z(-8,-6), new Z(-4,16) ) ); |
|
|
Back to top |
|
 |
Александр Михалицын
Модератор
Joined: 23 May 2008
Posts: 1299
Карма: 83 поощрить/наказать
|
Posted: Fri Sep 25, 2009 2:53 pm (спустя 2 часа 58 минут; написано за 12 секунд)
Post subject:
|
|
Еще чуть оптимизировал... Code (JavaScript): | скопировать код в буфер обмена | var qrt_equation_solver = new function() { var self = this;
var find_D = function(a, b, c) { //b*b - 4*a*c (Формула дискриминанта многочлена второй степени) return b.mul(b).sub(new Z(4, 0).mul(a).mul(c)); }
var find_sqrt_D = function(D) { //Возводим дискриминант в степень 1/2 (корень квадратный) return D.pow(1/2, 0); }
self.solve = function(a, b, c) { //Определяем "основные" числа, которые будут использоваться в формулах от 2х раз //(чтобы не создавать лишние экземпляры объектов) Бережем народную оперативку! (-;
// 2*a var TWO_a = new Z(2, 0).mul(a);
// -b var b_neg = b.neg();
//Находим дискриминант и сразу извлекаем из него корень квадратный var sqrt_D = find_sqrt_D(find_D(a, b, c));
//Находим корни уравнения:
//x1 (-b + sqrt(D) / 2a) var x1 = b_neg.add(sqrt_D).div(TWO_a);
//x2 (-b - sqrt(D) / 2a) var x2 = b_neg.sub(sqrt_D).div(TWO_a);
return [x1, x2]; } } |
|
|
Back to top |
|
 |
Александр Михалицын
Модератор
Joined: 23 May 2008
Posts: 1299
Карма: 83 поощрить/наказать
|
Posted: Sat Sep 04, 2010 12:32 pm (спустя 11 месяцев 8 дней 21 час 38 минут; написано за 2 минуты 31 секунду)
Post subject:
|
|
Вот, побаловался тут пару часиков и портировал "классы" Юры и Ильдара на PHP (толком не тестировал, но работать вроде должно (-:). Code (php): | скопировать код в буфер обмена | <?php //Основано на JS реализации комплексных чисел от Ильдара Шайморданова и частично от Юрия Насретдинова //портировал Александр Михалицын //Спасибо огромное Юрию Насретдинову, Ильдару Шайморданову (за подсказки, реализации, идеи), //а также Дмитрию Котерову (за отличный, уютный форум) и всем-всем-всем остальным. (-: function sqr( $x ) { return pow (www.php.net/pow)( $x, 2 ); } function Z( $re, $im ) { return Z::fromCartesian( $re, $im ); } function Re( $re ) { return Z::fromCartesian( $re, 0 ); } function Im( $im ) { return Z::fromCartesian( 0, $im ); } class Z { private $re, $im, $r, $f; private function __construct( $re, $im, $r, $f ) { $this->re = $re; $this->im = $im; $this->r = $r; $this->f = $f; } public static (www.php.net/static) function fromPolar( $r, $f ) { //argument must(!) lies in the (-pi; pi] interval $f = self::normalizeArg( $f );
//echo '<br />' . $r . ':' . $f . '<br />';
$re = $r * cos (www.php.net/cos)( $f ); $im = $r * sin (www.php.net/sin)( $f );
return new self( $re, $im, $r, $f ); }
private static (www.php.net/static) function normalizeArg( $f ) { return $f - 2 * M_PI * ( ceil (www.php.net/ceil)( $f / ( 2 * M_PI ) + 1 / 2 ) - 1 ); } public static (www.php.net/static) function fromCartesian( $re, $im ) { $r = sqrt (www.php.net/sqrt)( sqr( $re ) + sqr( $im ) ); $f = atan2 (www.php.net/atan2)( $im, $re ); return new self( $re, $im, $r, $f ); } public function re() { return $this->re; } public function im() { return $this->im; } public function abs (www.php.net/abs)() { return $this->r; } public function arg() { return $this->f; } public function isReal() { return $this->im == 0; }
public function isImaginary() { return $this->re == 0; } public function equals( Z $z ) { return ( $this->re === $z->re() ) && ( $this->im === $z->im() ); } public function conj() { return self::fromCartesian( $this->re, -$this->im ); } public function neg() { return self::fromCartesian( -$this->re, -$this->im ); } public function add() { $arguments = func_get_args (www.php.net/func_get_args)(); $arguments_count = count (www.php.net/count)($arguments); $re = $this->re; $im = $this->im; for ( $i = 0; $i < $arguments_count; $i++ ) { $re += $arguments[$i]->re(); $im += $arguments[$i]->im(); } return self::fromCartesian( $re, $im ); } public function sub() { $arguments = func_get_args (www.php.net/func_get_args)(); $arguments_count = count (www.php.net/count)($arguments); $re = $this->re; $im = $this->im; for ( $i = 0; $i < $arguments_count; $i++ ) { $re -= $arguments[$i]->re(); $im -= $arguments[$i]->im(); } return self::fromCartesian( $re, $im ); } public function mul() { $arguments = func_get_args (www.php.net/func_get_args)(); $arguments_count = count (www.php.net/count)($arguments); $r = $this->r; $f = $this->f; for ( $i = 0; $i < $arguments_count; $i++ ) { $r *= $arguments[$i]->abs(); $f += $arguments[$i]->arg(); } return self::fromPolar( $r, $f ); } public function div() { $arguments = func_get_args (www.php.net/func_get_args)(); $arguments_count = count (www.php.net/count)($arguments); $r = $this->r; $f = $this->f; for ( $i = 0; $i < $arguments_count; $i++ ) { $r /= $arguments[$i]->abs(); $f -= $arguments[$i]->arg(); } return self::fromPolar( $r, $f ); } public function pow (www.php.net/pow)( $n ) { return self::fromPolar( pow (www.php.net/pow)( $this->r, $n ), $this->f * $n ); } public function root( $n ) { return $this->pow( 1 / $n ); } public function sqrt (www.php.net/sqrt)() { return $this->root( 2 ); } public function exp (www.php.net/exp)() { return self::fromPolar( exp (www.php.net/exp)( $this->re ), $this->im ); } public function log (www.php.net/log)( $base ) { $re = log (www.php.net/log)( $this->re ); $im = $this->im; if ( $base ) { $lg = log (www.php.net/log)( $base ); $re /= $lg; $im /= $lg; } return self::fromCartesian( $re, $im ); } public function ln() { return $this->log(); } public function log10 (www.php.net/log10)() { return $this->log( 10 ); } public function lg() { return $this->log( 2 ); } public function sin (www.php.net/sin)() { $z1 = $this->mul( self::fromCartesian( 0, 1 ) ); $z2 = $z1->neg(); return $z1->exp()->sub( $z2->exp() )->div( self::fromCartesian( 0, 2 ) ); } public function cos (www.php.net/cos)() { $z1 = $this->mul( self::fromCartesian( 0, 1 ) ); $z2 = $z1->neg(); return $z1->exp()->sub( $z2->exp() )->div( self::fromCartesian( 2, 0 ) ); } private function eps( $x ) { $ZERO_THRESHOLD = 1e-15; return ( abs (www.php.net/abs)( $x ) <= $ZERO_THRESHOLD ) ? 0 : $x; } public function toString( $toPolar = false ) { //In Polar? if ( $toPolar ) return $this->eps( $this->r ) . ' ' . $this->eps( $this->f ); //Im(z) = 0? if ( !$this->eps( $this->im ) ) return '' . $this->eps( $this->re ); //Re(z) = 0? if ( !$this->eps( $this->re ) ) return $this->im . 'i'; //Something else?.. :-) $im = ( $this->im > 0 ) ? ' + ' : ' - '; $im .= $this->im . 'i'; return $this->eps( $this->re ) . $this->eps( $im ); } public function __toString() { return $this->toString(); } } class QRT_Equation_Solver { public static (www.php.net/static) function solve( $a, $b, $c ) { $D = self::getD( $a, $b, $c );//D $sqrtD = $D->sqrt();//sqrt(D) $minus_b = $b->neg();//-b $TwoA = $a->mul( Re( 2 ) );//2a //x1;2 = -b+-sqrt(D)/2a; $x1 = $minus_b->add( $sqrtD )->div( $TwoA ); $x2 = $minus_b->sub( $sqrtD )->div( $TwoA ); return array (www.php.net/array)( $x1, $x2 ); } private static (www.php.net/static) function getD( $a, $b, $c ) { //D = b^2 - 4ac; return $b->pow( 2 )->sub( Re( 4 )->mul( $a )->mul( $c ) ); } } class QBC_Equation_Solver { public static (www.php.net/static) function solve( $a, $b, $c, $d ) { //p = -b^2/3a^2 + c/a $p = $b->pow( 2 )->neg()->div( Re( 3 )->mul( $a->pow( 2 ) ) )->add( $c->div( $a ) );
//q = 2b^3 /27a^3 - bc/3a^2+d/a $q = $b->pow( 3 )->mul( Re( 2 ) )->div( Re( 27 )->mul( $a->pow( 3 ) ) ) ->sub( $b->mul( $c )->div( Re( 3 )->mul( $a->pow( 2 ) ) ) ) ->add( $d->div( $a ) );
//Q = (p/3)^3 + (q/2)^2; $Q = $p->div( Re( 3 ) )->pow( 3 )->add( $q->div( Re ( 2 ) )->pow( 2 ) );
//alpha = (-q/2+sqrt(Q))^(1/3) $alpha = $q->neg()->div( Re( 2 ) )->add( $Q->sqrt() )->root( 3 );
//betta = (-q/2-sqrt(Q))^(1/3); $betta = $q->neg()->div( Re( 2 ) )->sub( $Q->sqrt() )->root( 3 );
$y1 = $alpha->add( $betta );
$y23re = $y1->neg()->div( Re( 2 ) ); $y23im = $alpha->sub( $betta )->div( Re( 2 ) )->mul( Re( 3 )->sqrt()->mul( Im( 1 ) ) );
$y2 = $y23re->add( $y23im ); $y3 = $y23re->sub( $y23im );
$x1 = self::convertYtoX( $a, $b, $y1 ); $x2 = self::convertYtoX( $a, $b, $y2 ); $x3 = self::convertYtoX( $a, $b, $y3 );
return array (www.php.net/array)( $x1, $x2, $x3 ); }
private static (www.php.net/static) function convertYtoX( $a, $b, $y ) { //x = y - b/3a; return $y->sub( $b->div( Re( 3 )->mul( $a ) ) ); } } function print_numeric_array( $array ) { $array_count = count (www.php.net/count)( $array ); for ( $i = 0; $i < $array_count; $i++ ) { echo (www.php.net/echo) $array[$i]; if ( $i != $array_count - 1 ) echo (www.php.net/echo) ', '; } } echo (www.php.net/echo) '<pre>'; //x^2 + 1=0 print_numeric_array( QRT_Equation_Solver::solve( Re( 1 ), Re( 0 ), Re( 1 ) ) ); //x^3-2x^2-5x+6=0 print_numeric_array( QBC_Equation_Solver::solve( Re( 1 ), Re( -2 ), Re( -5 ), Re( 6 ) ) ); echo (www.php.net/echo) '</pre>'; ?> | Квадратные уравнения эта штука решает "на ура", а вот у кубических, пока, правильно определяет только 1 корень... )-: М |
| Хоть оно и на РHP - пусть пока лежит тут, потом разгребу... (-; |
Last edited by Александр Михалицын on Tue Sep 07, 2010 1:37 pm; edited 1 time in total
|
|
Back to top |
|
 |
Александр Михалицын
Модератор
Joined: 23 May 2008
Posts: 1299
Карма: 83 поощрить/наказать
|
Posted: Sun Sep 05, 2010 3:09 pm (спустя 1 день 2 часа 36 минут; написано за 1 минуту 13 секунд)
Post subject:
|
|
Исправил предыдущий пост. Теперь "решалка кубических уравнений" работает. А в класс "комплексного числа" добавлена корректная нормализация аргумента комплексного числа (спасибо участнику форума Furax'у (forum.dklab.ru/profile.php?mode=viewprofile&u=12160)).
|
|
Back to top |
|
 |
Юрий Насретдинов
Модератор

Joined: 13 Mar 2003
Posts: 8642
Карма: 198 поощрить/наказать
Location: 007 495
|
Posted: Tue Sep 07, 2010 1:30 pm (спустя 1 день 22 часа 20 минут; написано за 8 секунд)
Post subject:
|
|
Александр Михалицын wrote: |
public function isReal() { return $this->re === 0; } | Ну здрасти приехали... Чему вас только в школе учат?
|
|
Back to top |
|
 |
Юрий Насретдинов
Модератор

Joined: 13 Mar 2003
Posts: 8642
Карма: 198 поощрить/наказать
Location: 007 495
|
Posted: Tue Sep 07, 2010 1:33 pm (спустя 3 минуты; написано за 1 минуту 11 секунд)
Post subject:
|
|
Александр Михалицын wrote: |
public function equals( Z $z ) { return ( $this->re === $z->re() ) && ( $this->im === $z->im() ); } | Так нельзя сравнивать числа с плавающей запятой. Нужно задать какой-нибудь порог, и если разность между двумя значениями не превосходит этот порог, то нужно считать числа равными. Пример: 0.7+0.1 и 0.8 не будут равны при такой функции сравнения.
|
|
Back to top |
|
 |
Александр Михалицын
Модератор
Joined: 23 May 2008
Posts: 1299
Карма: 83 поощрить/наказать
|
Posted: Tue Sep 07, 2010 1:35 pm (спустя 1 минуту 51 секунду; написано за 42 секунды)
Post subject:
|
|
Юрий Насретдинов, Quote: |
Ну здрасти приехали... Чему вас только в школе учат? | это обычная опечатка. И да: в школе, комплексные числа не рассматриваются. (=
|
|
Back to top |
|
 |
Юрий Насретдинов
Модератор

Joined: 13 Mar 2003
Posts: 8642
Карма: 198 поощрить/наказать
Location: 007 495
|
Posted: Tue Sep 07, 2010 1:38 pm (спустя 3 минуты; написано за 34 секунды)
Post subject:
|
|
Александр Михалицын wrote: |
public function div() { $arguments = func_get_args(); $arguments_count = count($arguments); $r = $this->r; $f = $this->f; for ( $i = 0; $i < $arguments_count; $i++ ) { $r /= $arguments[$i]->abs(); $f -= $arguments[$i]->arg(); } return self::fromPolar( $r, $f ); } | По прототипу функции непонятно, что она делает... Т.е. (Z::fromCartesian(1,0))->div( Z::fromCartesian(2,0) ) будет 1/2, а вот чему равно такое: (Z::fromCartesian(1,0))->( Z::fromCartesian(2,0), Z::fromCartesian(3,1) ) из прототипа функции неясно. А будет равно оно -i/6, что совсем не очевидно.
|
|
Back to top |
|
 |
Александр Михалицын
Модератор
Joined: 23 May 2008
Posts: 1299
Карма: 83 поощрить/наказать
|
Posted: Tue Sep 07, 2010 1:42 pm (спустя 3 минуты; написано за 1 минуту 26 секунд)
Post subject:
|
|
Юрий Насретдинов, пока решение не оттестировано настолько, чтобы его документировать (и я вообще не уверен, что это нужно, ибо это решение сделано не для всех, а для заинтересованных людей, умеющих читать код).
|
|
Back to top |
|
 |
Юрий Насретдинов
Модератор

Joined: 13 Mar 2003
Posts: 8642
Карма: 198 поощрить/наказать
Location: 007 495
|
Posted: Tue Sep 07, 2010 1:47 pm (спустя 5 минут; написано за 4 секунды)
Post subject:
|
|
Александр Михалицын wrote: |
public static function fromPolar( $r, $f ) { //argument must(!) lies in the (-pi; pi] interval $f = self::normalizeArg( $f ); //echo '<br />' . $r . ':' . $f . '<br />'; $re = $r * cos( $f ); $im = $r * sin( $f ); return new self( $re, $im, $r, $f ); } | Для этого достаточно не нормализовать аргумент по какой-то страшной формуле, а воспользоваться готовым atan2, который возвращает нормализованный аргумент, т.е. Code (php): | скопировать код в буфер обмена | public static (www.php.net/static) function fromPolar( $r, $f ) { if($r < 0) throw new Exception('Argument r cannot be negative'); $re = $r * cos (www.php.net/cos)( $f ); $im = $r * sin (www.php.net/sin)( $f );
return new self( $re, $im, $r, atan2 (www.php.net/atan2)($im, $re) ); } |
|
|
Back to top |
|
 |
|