Форум dkLab и Denwer
Здесь общаются Web-разработчики.
Генеральный спонсор:
Хостинг «Джино»

Процесс обсуждения и реализации класса комплексных чисел (Юрий Насретдинов, оценка: 5)
Goto page Previous  1, 2
Author Message
Александр Михалицын
Модератор



Joined: 23 May 2008
Posts: 1299
Карма: 82
   поощрить/наказать


PostPosted: Fri Sep 25, 2009 11:55 am (написано за 33 секунды)
   Post subject:
Reply with quote

А вот от меня вариант решалки уравнений с комплексными коэфициентами, на основе Юриного "класса" (надо будет свой доработать):
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
View user's profile Send private message Send e-mail
Александр Михалицын
Модератор



Joined: 23 May 2008
Posts: 1299
Карма: 82
   поощрить/наказать


PostPosted: Fri Sep 25, 2009 2:53 pm (спустя 2 часа 58 минут; написано за 12 секунд)
   Post subject:
Reply with quote

Еще чуть оптимизировал...
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
View user's profile Send private message Send e-mail
Александр Михалицын
Модератор



Joined: 23 May 2008
Posts: 1299
Карма: 82
   поощрить/наказать


PostPosted: Sat Sep 04, 2010 12:32 pm (спустя 11 месяцев 8 дней 21 час 38 минут; написано за 2 минуты 31 секунду)
   Post subject:
Reply with quote

Вот, побаловался тут пару часиков и портировал "классы" Юры и Ильдара на 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
View user's profile Send private message Send e-mail
Александр Михалицын
Модератор



Joined: 23 May 2008
Posts: 1299
Карма: 82
   поощрить/наказать


PostPosted: Sun Sep 05, 2010 3:09 pm (спустя 1 день 2 часа 36 минут; написано за 1 минуту 13 секунд)
   Post subject:
Reply with quote

Исправил предыдущий пост. Теперь "решалка кубических уравнений" работает. А в класс "комплексного числа" добавлена корректная нормализация аргумента комплексного числа (спасибо участнику форума Furax'у (forum.dklab.ru/profile.php?mode=viewprofile&u=12160)).
Back to top
View user's profile Send private message Send e-mail
Юрий Насретдинов
Модератор



Joined: 13 Mar 2003
Posts: 8642
Карма: 199
   поощрить/наказать

Location: 007 495

PostPosted: Tue Sep 07, 2010 1:30 pm (спустя 1 день 22 часа 20 минут; написано за 8 секунд)
   Post subject:
Reply with quote

Александр Михалицын wrote:
public function isReal() {
                return $this->re === 0;
        }
Ну здрасти приехали... Чему вас только в школе учат?
Back to top
View user's profile Send private message Send e-mail
Юрий Насретдинов
Модератор



Joined: 13 Mar 2003
Posts: 8642
Карма: 199
   поощрить/наказать

Location: 007 495

PostPosted: Tue Sep 07, 2010 1:33 pm (спустя 3 минуты; написано за 1 минуту 11 секунд)
   Post subject:
Reply with quote

Александр Михалицын wrote:
public function equals( Z $z ) {
                return ( $this->re === $z->re() ) && ( $this->im === $z->im() );
        }
Так нельзя сравнивать числа с плавающей запятой. Нужно задать какой-нибудь порог, и если разность между двумя значениями не превосходит этот порог, то нужно считать числа равными.

Пример: 0.7+0.1 и 0.8 не будут равны при такой функции сравнения.
Back to top
View user's profile Send private message Send e-mail
Александр Михалицын
Модератор



Joined: 23 May 2008
Posts: 1299
Карма: 82
   поощрить/наказать


PostPosted: Tue Sep 07, 2010 1:35 pm (спустя 1 минуту 51 секунду; написано за 42 секунды)
   Post subject:
Reply with quote

Юрий Насретдинов,
Quote:
Ну здрасти приехали... Чему вас только в школе учат?
это обычная опечатка.

И да: в школе, комплексные числа не рассматриваются. (=
Back to top
View user's profile Send private message Send e-mail
Юрий Насретдинов
Модератор



Joined: 13 Mar 2003
Posts: 8642
Карма: 199
   поощрить/наказать

Location: 007 495

PostPosted: Tue Sep 07, 2010 1:38 pm (спустя 3 минуты; написано за 34 секунды)
   Post subject:
Reply with quote

Александр Михалицын 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
View user's profile Send private message Send e-mail
Александр Михалицын
Модератор



Joined: 23 May 2008
Posts: 1299
Карма: 82
   поощрить/наказать


PostPosted: Tue Sep 07, 2010 1:42 pm (спустя 3 минуты; написано за 1 минуту 26 секунд)
   Post subject:
Reply with quote

Юрий Насретдинов,
пока решение не оттестировано настолько, чтобы его документировать (и я вообще не уверен, что это нужно, ибо это решение сделано
не для всех, а для заинтересованных людей, умеющих читать код).
Back to top
View user's profile Send private message Send e-mail
Юрий Насретдинов
Модератор



Joined: 13 Mar 2003
Posts: 8642
Карма: 199
   поощрить/наказать

Location: 007 495

PostPosted: Tue Sep 07, 2010 1:47 pm (спустя 5 минут; написано за 4 секунды)
   Post subject:
Reply with quote

Александр Михалицын 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
View user's profile Send private message Send e-mail
Display posts from previous:   
Post new topic   Reply to topic All times are GMT + 3 Hours
Goto page Previous  1, 2
Page 2 of 2    Email to a Friend.
You cannot post new topics in this forum. You cannot reply to topics in this forum. You cannot edit your posts in this forum. You cannot delete your posts in this forum. You cannot vote in polls in this forum. You cannot attach files in this forum. You can download files in this forum.
XML