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

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



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


PostPosted: Fri May 29, 2009 4:48 pm ()
   Post subject:
Reply with quote


М

Выделено из темы «"Решалка" квадратичных уравнений»,
расположенной в форуме Разное :: JavaScript (08 Июня 2009, 13:30).
Back to top
View user's profile Send private message Send e-mail
Юрий Насретдинов
Модератор



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

Location: 007 495

PostPosted: Fri May 29, 2009 4:48 pm (спустя 1 секунду; написано за 3 минуты 3 секунды)
   Post subject:
Reply with quote

dimagolov wrote:
даже с учетом того, что мои личные воспоминания об этом курсе вообще и предмете в частности весьма смутные, никто не отменял вот это: tinyurl.com/lungdd
Представляю себе круглые глаза человека, впервые узнавшего о концепции комплексных чисел и увидевшего формулу для корня порядка N из комплексного числа :).
Back to top
View user's profile Send private message Send e-mail
dimagolov
Участник форума



Joined: 04 Feb 2007
Posts: 1664
Карма: 96
   поощрить/наказать

Location: Christ Church, Barbados

PostPosted: Fri May 29, 2009 4:58 pm (спустя 9 минут; написано за 11 секунд)
   Post subject:
Reply with quote

Quote:
А теперь, если ты каждый метод опишешь (как он работает) будет вообще супер. =)
Что там описывать? это просто арифметика комплексных чисел, если Юрий не накосячил (я просто не проверял), то Вы по его коду можете выучить ее. Комплексное число у него представлено массивом - 0-й элемент это действительная часть, 1-й это комплексная.
Quote:
Мне интересно значть что вы тм в ТФКП проходили... =)
Если есть время и желание, то даже 8-й класс не станет проблемой: tinyurl.com/llzu4m
Правда, придется многое чего подучить, я вот не помню когда изучаются тригонометрические ф-ии. На самом деле комплексные числа это просто - вместо числовой прямой это можно представить как плоскость. Правда, уже ф-я комплексной переменной создает некоторые трудности в воображении, так как график такой ф-ии придется рисовать в 4-х мерном пространстве
Back to top
View user's profile Send private message
dimagolov
Участник форума



Joined: 04 Feb 2007
Posts: 1664
Карма: 96
   поощрить/наказать

Location: Christ Church, Barbados

PostPosted: Fri May 29, 2009 5:26 pm (спустя 28 минут; написано за 3 минуты 43 секунды)
   Post subject:
Reply with quote

кстати, первой программой, которую я самостоятельно написал были именно решалка квадратных уравнений. написана она была на Basic для Искра 226, был в свое время такой персональный компьютер (невероятно компактный, помещался на одном столе даже вместе с приводами 8-дюймовых флопов)...
странно, мне казалось, что квадратные уравнения изучались много раньше, чем в 8-м классе, если считать с 6-и лет (хотя тогда ходили в школу с 7-ми) то по идее в 6-м, если даже не в 5-м?
Back to top
View user's profile Send private message
Rumata
Профессионал



Joined: 17 Aug 2003
Posts: 1850
Карма: 184
   поощрить/наказать


PostPosted: Fri May 29, 2009 9:13 pm (спустя 3 часа 46 минут; написано за 6 минут 27 секунд)
   Post subject:
Reply with quote

Хотя реализация комплексных чисел на js (как мне кажется) не представляет практического интереса, но ради интереса можно попытаться воплотить большинство математических действий для комплексных чисел. Конечно, перегрузка операций в js невозможна, но даже этот недостаток частично можно обойти, например, с помощью функций-методов. Последнее я представляю примерно так:
Code (JavaScript): скопировать код в буфер обмена
// z1 = 1 + i
z1 = new Complex(1, 1);

// z2 = 1 - i
z2 = new Complex(1, -1);

// z3 = z1 + z2
z3 = a1.add(z2);
Опять же повторюсь, практического значения у данной реализации мало - данное решение интересно лишь с учебной точки зрения. Медленно и отсутствие поддержки перегрузки операторов со стороны языка.
Back to top
View user's profile Send private message
Александр Михалицын
Модератор



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


PostPosted: Mon Jun 01, 2009 12:02 pm (спустя 2 дня 14 часов 49 минут; написано за 44 секунды)
   Post subject:
Reply with quote

Rumata,
угу. Как только я разберусь с комплексными числами, обязательно напишу подобные объекты, именно в целях обучения.
Спасибо всем, кто подсказал и помог с кодом. [+]ы. ;-)
Back to top
View user's profile Send private message Send e-mail
Rumata
Профессионал



Joined: 17 Aug 2003
Posts: 1850
Карма: 184
   поощрить/наказать


PostPosted: Mon Jun 01, 2009 12:29 pm (спустя 26 минут; написано за 1 минуту 24 секунды)
   Post subject:
Reply with quote

ru.wikipedia.org/wiki/Комплексное_число
en.wikipedia.org/wiki/Complex_number

Информация не самая полная, но для начала должно хватить.
Пишите. Хотелось бы увидеть ваше решение. Я уже приготовил каверзных вопросов (-:
Back to top
View user's profile Send private message
Александр Михалицын
Модератор



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


PostPosted: Mon Jun 01, 2009 5:01 pm (спустя 4 часа 31 минуту; написано за 44 секунды)
   Post subject:
Reply with quote

Rumata,
Quote:
Пишите.
Мы на "ты". ;-)
Quote:
Я уже приготовил каверзных вопросов (-:
Отлично... =)
Back to top
View user's profile Send private message Send e-mail
Александр Михалицын
Модератор



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


PostPosted: Sun Jun 07, 2009 10:39 am (спустя 5 дней 17 часов 38 минут; написано за 18 секунд)
   Post subject:
Reply with quote

Code (JavaScript): скопировать код в буфер обмена
/*
function Complex(a, b)
{
        this.a = a; //
        this.b = b; //

        /*
        this.sum = function(complex) //
        {
                return new Complex(this.a + complex.a, this.b + complex.b);
        }

        /*
        this.diff = function(complex) //
        {
                return new Complex(this.a - complex.a, this.b - complex.b);
        }

        /*
        this.multi = function(complex) //
        {
                var a = this.a;
                var c = complex.a;

                var b = this.b;
                var d = complex.b;

                return new Complex(a * c - b * d, b * c + a * d);
        }

        /*
        this.division = function(complex) //
        {
                var a = this.a;
                var c = complex.a;

                var b = this.b;
                var d = complex.b;

                var new_complex_a = (a * c + b * d) / (c * c + d * d);
                var new_complex_b = (d * c - a * d) / (c * c + d * d);

                return new Complex(new_complex_a, new_complex_b);
        }

        /*
        this.compare = function(complex) //
        {
                if (this.a == complex.a && this.b == complex.b)
                {
                        return true;
                } else {
                        return false;
                }
        }

        /*
        this.modules_compare = function(complex)
        {
                var module_this_z = Math.sqrt(this.a * this.a + this.b * this.b);
                var module_complex_z = Math.sqrt(complex.a * complex.a + complex.b * complex.b);

                if (module_this_z > module_complex_z)
                {
                        return true; //
                } else if (module_this_z < module_complex_z) {
                        return false; //
                } else {
                        return null; //
                }
        }

        this.toString = function()
        {
                return this.a + (this.b + 'i');
        }
}
Жду критики. :)
Back to top
View user's profile Send private message Send e-mail
Юрий Насретдинов
Модератор



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

Location: 007 495

PostPosted: Sun Jun 07, 2009 11:04 am (спустя 24 минуты; написано за 1 минуту 22 секунды)
   Post subject:
Reply with quote

Хм, ну да, и мой вариантик, + решалка квадратных уравнений, переписанная под использование класса комплексных чисел.
Code (JavaScript): скопировать код в буфер обмена
function Complex(x,y) { this.construct(x,y) }

Complex.prototype = {
    x: 0,
    y: 0,
   
    construct: function(x,y)
    {
        this.x = x;
        this.y = y;
    },
   
    toString: function()
    {
        return this.x+' + i*'+this.y;
    },
   
    // return |z|
   
    abs: function()
    {
        return Math.sqrt(this.x*this.x+this.y*this.y);
    },
   
    mul: function(b)
    {
        var a = this;
        return new Complex(a.x*b.x - a.y*b.y, a.y*b.x + b.y*a.x);
    },
   
    // complex division: returns (a/b)
   
    div: function(b)
    {
        // a/b = a*(b*)/|b|^2, where b* = Re b - i*Im b
       
        var a = this;
       
        var b2 = b.x*b.x + b.y*b.y; // (|b|^2)
        if(!b2) return false;
       
        return a.mul(new Complex(b.x/b2, -b.y/b2));
    },
   
    add: function(b)
    {
        var a = this;
        return new Complex( a.x + b.x, a.y + b.y );
    },
   
    // a - b
    sub: function(b)
    {
        var a = this;
        return new Complex( a.x - b.x, a.y - b.y);
    },
   
    neg: function()
    {
        var a = this;
        return new Complex( -a.x, -a.y );
    },
   
    // power (n is real, not complex!):
    // if n is integer, you will get the n'th power of z
    // if n = 1/k, where k is integer, you will get an array of k complex k'th roots of z
    // otherwise you will get 1 complex number
    // if you want to get, e.g., a power of 2/3, use pow2
   
    pow: function(n)
    {
        var a = this;
        // get the exponential form of an answer
        var r = Math.sqrt( a.x*a.x + a.y*a.y );
        if(r==0) return new Complex(0,0);
        if(n==0) return new Complex(1,0);
       
        var na = Math.abs(n);
       
        r = Math.pow(r,na);
        var phi = Math.atan2(a.y,a.x);
       
        if(na >= 1 && Math.round(na) == na || Math.abs( Math.round(1/na) - 1/na ) > 1e-10) // means, that n is integer or n is not (1/k), where k is integer
        {
            var ans = new Complex( r*Math.cos(na*phi), r*Math.sin(na*phi) ); // z^|n|
           
            if(n < 0) return new Complex(1,0).div(ans);
            else return ans;
        }else
        {
            // the result will be array of different complex roots
           
            var m = Math.round(1/na); // m means the power of the root
           
            var answers = [];
           
            var ang = 0;
           
            for(var i = 0; i < m; i++) // there will be m distinct answers
            {
                ang = (phi+i*2*Math.PI)/m;
                answers[i] = new Complex( r*Math.cos(ang), r*Math.sin(ang) ) ;
               
                if(n < 0) answers[i] = new Complex(1,0).div(answers[i]);
            }
           
            return answers;
        }
    },
   
    // use this function to get the power (n/m) for z
    // neither n or m should be equal to 1 or 0 or -1
    // returns array of m complex numbers
   
    pow2: function(n,m)
    {
        if(n!=Math.round(n) || Math.abs(n)<=1 || m!=Math.round(m) || Math.abs(m)<=1) return false;
       
        var answers = this.pow(1/m);
        for(var i = 0; i < m; i++)
        {
            answers[i] = answers[i].pow(n);
        }
       
        return answers;
    },
   
    // complex logarithm of a number
    // base is optional and must be real
    // the result is given only for _main_ branch of the logarithm
    //
    // the default base is E (2.71)
   
    log: function(base)
    {
        var a = this;
        var r = Math.sqrt( a.x*a.x + a.y*a.y );
       
        if(base == 1 || base <= 0) return false; // even though base for complex logarithm, possibly, could be negative, I do not want to consider this case
       
        var x = 0;
       
        if(base) x = Math.log(r)/Math.log(base);
        else     x = Math.log(r);
       
        var phi = Math.atan2(a.y, a.x);
       
        return new Complex( x, phi );
    },
   
    // complex exponent (in complex power)
   
    exp: function()
    {
        var z = this;
       
        var re = Math.exp(z.x);
       
        return new Complex( re*Math.cos(z.y), re*Math.sin(z.y) );
    },
   
    //
   
    sin: function()
    {
        var z = this;
       
        var z1 = z.mul(new Complex(0,1));
        var z2 = z1.neg();
       
        return ( z1.exp() ).sub( z2.exp() ).div(new Complex(0,2));
    },
   
    cos: function()
    {
        var z = this;
       
        var z1 = z.mul(new Complex(0,1));
        var z2 = z1.neg();
       
        return ( z1.exp() ).add( z2.exp() ).div(new Complex(2,0));
    }

};

var sq_eq_solver = {
   
    // a, b, c -- complex numbers
    //
    // another difference -- if a==0,b!=0 the answer is returned in format [ z ]
    // returns [z1, z2], where z1 and z2 are the roots
   
    solve: function(a,b,c)
    {
        if(!a.x && !a.y) return b.x&&b.y ? c.div(b).neg() : !c.x&&!c.y;
       
        // scale coeffs so, that a=0.5 and x1,x2 = ( -b +- sqrt(D) ); ( 1/2a == 1)
        var two_a_i = new Complex(0.5,0).div(a); // 1/2a
       
        a=new Complex(0.5,0);
        b=b.mul(two_a_i); // b = b*(1/2a)
        c=c.mul(two_a_i); // c = c*(1/2a)
       
        var D = b.mul(b).sub( c.mul(new Complex(2,0)) ); // var D = b*b - 2*c;
        var sqD = D.pow(1/2)[0] || new Complex(0,0);
       
        var nb = b.neg();
        return [nb.add(sqD), nb.sub(sqD)];
    }
};

function z(x,y)
{
    return new Complex(x,y);
}

//alert( z(4,0).pow(1/2)[0] );

//alert( sq_eq_solver.solve(1,0,4) );
alert( sq_eq_solver.solve( z(2,0) , z(-8,-6),z(-4,16) ) );
Back to top
View user's profile Send private message Send e-mail
Александр Михалицын
Модератор



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


PostPosted: Sun Jun 07, 2009 12:20 pm (спустя 1 час 16 минут; написано за 1 минуту 17 секунд)
   Post subject:
Reply with quote

Да уж... С такими темпами нам надо открыть доп. форум "Математика". (-:

Юрий Насретдинов,
классно... Что уж тут сказать...
Back to top
View user's profile Send private message Send e-mail
Rumata
Профессионал



Joined: 17 Aug 2003
Posts: 1850
Карма: 184
   поощрить/наказать


PostPosted: Sun Jun 07, 2009 6:38 pm (спустя 6 часов 17 минут; написано за 4 минуты 33 секунды)
   Post subject:
Reply with quote

Александр Михалицын
Юрий Насретдинов
Есть несколько замечаний. Что-то мне подсказывает, что некоторые места в ваших алгоритмах не оптимальны. Непонятно, почему никто из вас не воспользовался другими формами представления комплексных чисел. А методы - pow, pow2 и log - от чего такие страшные вычисления? Можно же проще.
Я ни в коем случае не придираюсь. Не такая уж серьезная задача ставилась. Но все-таки...
Back to top
View user's profile Send private message
Александр Михалицын
Модератор



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


PostPosted: Sun Jun 07, 2009 6:49 pm (спустя 11 минут; написано за 2 минуты 14 секунд)
   Post subject:
Reply with quote

Rumata,
Quote:
Непонятно, почему никто из вас не воспользовался другими формами представления комплексных чисел.
А что может быть оптимальнее объекта? (-:
Массив? Тоже объект -- насколько мне кажется, даже более "не оптимальный". (-:
Quote:
А методы - pow, pow2 и log - от чего такие страшные вычисления? Можно же проще.
Давай-ка изложишь тут или мне в ICQ? Интересно будет послушать (зачеркнуто) почитать...
Quote:
Я ни в коем случае не придираюсь.
Да можно и попридираться... (-:
Back to top
View user's profile Send private message Send e-mail
Юрий Насретдинов
Модератор



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

Location: 007 495

PostPosted: Sun Jun 07, 2009 6:51 pm (спустя 1 минуту 52 секунды; написано за 2 минуты 15 секунд)
   Post subject:
Reply with quote

Rumata wrote:
Непонятно, почему никто из вас не воспользовался другими формами представления комплексных чисел.
Для вычисления степени как раз осуществляется переход к экспоненциальной форме записи :).

А проще вряд ли можно сделать, потому что извлечение корня степени n из числа является многозначной функцией, поэтому необходимо такие ситуации обрабатывать правильно и возвращать массив ответов :).

Для логарифма количество возвращаемых значений счётно, поэтому возвращается только главное значение логарифма :). К тому же, я не очень понял, чего ты сложного увидел в реализации pow2 и логарифма?

Last edited by Юрий Насретдинов on Sun Jun 07, 2009 7:02 pm; edited 2 times in total
Back to top
View user's profile Send private message Send e-mail
Александр Михалицын
Модератор



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


PostPosted: Sun Jun 07, 2009 6:56 pm (спустя 5 минут)
   Post subject:
Reply with quote


М

Тему скоро надо будет порезать... Как закончим обсуждение -- сделаю.
А то тут уже и решение квадратичных уравнений и комплексные числа... Осталось только тригонометрические функции обсудить. (-:
Back to top
View user's profile Send private message Send e-mail
Rumata
Профессионал



Joined: 17 Aug 2003
Posts: 1850
Карма: 184
   поощрить/наказать


PostPosted: Sun Jun 07, 2009 7:36 pm (спустя 40 минут; написано за 7 минут 35 секунд)
   Post subject:
Reply with quote

Александр Михалицын
Я имел ввиду тригонометрическую форму представления
Code (any language): скопировать код в буфер обмена
z = r * (cos(f) + isin(f))
Юрий Насретдинов
Я видел перевод из алгебраической в тригонометрическую, но почему же так много строк в методе pow? К чему лишние проверки? К вопросу о многозначности результатов вычисления корней. Мне кажется, что pow - функция "общего назначения" для вычисления степени вообще. Не понятен смысл pow и pow2. По моему одна из них повторяет алгоритм другой. А умножение, деление - разве не проще выполнять в тригонометрической форме?
Back to top
View user's profile Send private message
Rumata
Профессионал



Joined: 17 Aug 2003
Posts: 1850
Карма: 184
   поощрить/наказать


PostPosted: Sun Jun 07, 2009 7:51 pm (спустя 14 минут; написано за 5 минут 52 секунды)
   Post subject:
Reply with quote

Юрий Насретдинов wrote:
К тому же, я не очень понял, чего ты сложного увидел в реализации pow2 и логарифма?
Я понимаю, что там предусмотрено вычисление произвольного логарифма, мне кажется, это можно было бы вынести за пределы. Но я это не оспариваю. Много кода чтобы вычислить логарифм числа
Code (any language): скопировать код в буфер обмена
log(z) = log(r) + i f
. Что может быть проще чем
Code (JavaScript): скопировать код в буфер обмена
Complex.prototype.log = function()
{
        return new Complex(this.abs(), this.arg());
};
Что характерно, в классе описан метод вычисления модуля Complex.abs(), но практически не используется.
Back to top
View user's profile Send private message
Юрий Насретдинов
Модератор



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

Location: 007 495

PostPosted: Sun Jun 07, 2009 10:04 pm (спустя 2 часа 12 минут; написано за 2 минуты 32 секунды)
   Post subject:
Reply with quote

Rumata wrote:
Что характерно, в классе описан метод вычисления модуля Complex.abs(), но практически не используется.
На самом деле, совсем не используется...
Rumata wrote:
Complex.prototype.log = function()
{
        return new Complex(this.abs(), this.arg());
};
Ну, во-первых, ты забыл самое главное, а именно, логарифм взять от модуля :).
К тому же, я думаю, ты мог заметить, что основную часть кода составляет проверка основания логарифма и выполнение соответствующих действий для различных оснований.
Ну и последнее, твой код вряд ли будет сильно эффективнее, поскольку вычислений будет на самом деле произведено ровно столько же, просто они запрятаны в методы, некоторых из которых к тому же не существует (к примеру, аргумента :)).
Back to top
View user's profile Send private message Send e-mail
Rumata
Профессионал



Joined: 17 Aug 2003
Posts: 1850
Карма: 184
   поощрить/наказать


PostPosted: Sun Jun 07, 2009 10:21 pm (спустя 17 минут; написано за 5 минут 23 секунды)
   Post subject:
Reply with quote

Конечно я заметил, что ведется большая проверка на корректность входных данных. И твой метод log позволяет вычислить произвольный логарифм для большинства случаев действительных оснований. Для этого и нужны были проверки. Но так ли необходимо такое усложнение? Приводя в качестве примера свое видение метода log я хотел только показать, что некоторые вычисления можно было бы вынести в отдельные методы. Можно даже провести самые тщательные проверки и показать, что мой вариант, возможно, будет слегка проигрывать по скорости. А возможно и нет. Я говорю не об эффективности. Я говорю о красоте кода :)
Back to top
View user's profile Send private message
Юрий Насретдинов
Модератор



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

Location: 007 495

PostPosted: Sun Jun 07, 2009 10:38 pm (спустя 16 минут; написано за )
   Post subject:
Reply with quote

Эм, ну все же проверки на корректность должны быть в коде, от этого никуда не деться. А вот с остальным, в том числе и с использованием .abs() и .arg() я пожалуй соглашусь и постараюсь доделать :).
Back to top
View user's profile Send private message Send e-mail
Rumata
Профессионал



Joined: 17 Aug 2003
Posts: 1850
Карма: 184
   поощрить/наказать


PostPosted: Sun Jun 07, 2009 11:12 pm (спустя 34 минуты; написано за 5 минут 54 секунды)
   Post subject:
Reply with quote

Неточно выразился. Я имел ввиду так ли необходима универсальность, например, того же метода log? Кстати
Code (any language): скопировать код в буфер обмена
ln(z) = ln(r) + i f
lg(z) = lg(r) + i f lg(e)
то есть
Code (JavaScript): скопировать код в буфер обмена
Complex.prototype.log = function(base)
{
        ...
        var r = this.abs();
        var x = Math.log(r);
        var y = this.arg();
        if ( base ) {
                var lg = Math.log(base);
                x /= lg;
                y /= lg;
        }
        return new Complex(x, y);
};
Back to top
View user's profile Send private message
Юрий Насретдинов
Модератор



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

Location: 007 495

PostPosted: Mon Jun 08, 2009 8:01 am (спустя 8 часов 48 минут; написано за )
   Post subject:
Reply with quote

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



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

Location: 007 495

PostPosted: Mon Jun 08, 2009 8:22 am (спустя 20 минут; написано за )
   Post subject:
Reply with quote

А pow() отличается от pow2() тем, что pow2() рассматривает число, как рациональное, а не вещественное, и соотвественно возвращает n корней вместо одного (в функции pow() считается, что если n или 1/n не являются целыми, то число, подающееся на вход, вещественное, и надо вернуть только 1 результат (как раз то, о чем ты говорил).
Back to top
View user's profile Send private message Send e-mail
Александр Михалицын
Модератор



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


PostPosted: Mon Jun 08, 2009 10:36 am (спустя 2 часа 14 минут; написано за 2 минуты 25 секунд)
   Post subject:
Reply with quote


М

Сейчас дообсуждаем, допилим -- можно будет в "склад".
[off]Я еще строилку графиков писал =) Тоже выложу потом.
А то, к сожалению, в разделах JavaScript'a большинство новых тем
из серии "Памагите!!!".[/off]


Так с логарифмом, я так понимаю проблема решена? Вариант от Rumata верный?

Last edited by Александр Михалицын on Thu Aug 19, 2010 4:54 pm; edited 1 time in total
Back to top
View user's profile Send private message Send e-mail
Rumata
Профессионал



Joined: 17 Aug 2003
Posts: 1850
Карма: 184
   поощрить/наказать


PostPosted: Sat Jun 13, 2009 12:58 pm (спустя 5 дней 2 часа 22 минуты; написано за 20 минут 57 секунд)
   Post subject:
Reply with quote

Добавлю свое видение задачи. Оно в принципе не отличается от варианта, предложенного Юрием Насретдиновым. Особенностью модуля является вычисление всех частей (вещественной, мнимой, модуля и аргумента) комплексного числа на момент его создания. Это ни прибавляет, ни отнимает скорости вычислений, но оптимизирует некоторые вычисления (например, при вычислениях в алгебраической или полярной формах). Описаны арифметические операции, основные функции над комплексными числами (возведение в степень, логарифм, степенная функция, экспонента, квадратный корень и вычисление всех корней). Арифметические операции расширены для операций над несколькими числами. То есть
Code (JavaScript): скопировать код в буфер обмена
var x = new Complex(1, 1);
var y = x.add(new Complex(2, 0)).add(new Complex(3, 0));
// Расширение
var y = x.add(new Complex(2, 0), new Complex(3, 0));
Определены методы вычисления частей комплексного числа - вещественной re(), мнимой im(), модуля abs() и аргумента arg() комплексного числа, а также вычисление сопряженного комплексного числа conj() и его отрицательного значения neg(). Функция строкового преобразования Complex.prototype.toString позволяет отобразить комплексное число как в алгебраической, так и в полярной формах. Добавлены одноименные методы объекту Number для упрощения совместной работы с комплексными и реальными числами. То есть предыдущий пример можно записать еще короче
Code (JavaScript): скопировать код в буфер обмена
var y = x.add(2, 3);
n-ные корни чисел вычисляются все. Результатом является как массив корней комплексных чисел (по умолчанию), так и массив аргументов комплексных чисел и общий модуль как свойство abs результирующего массива (аргументы корней определены на интервале от -pi до +pi):
Code (JavaScript): скопировать код в буфер обмена
var x = -2;
//
var carte = x.roots(2);
//
var polar = x.roots(2, true);
В общем, никому ненужный модуль. Баловство одно.
Code (JavaScript): скопировать код в буфер обмена
/**
 * Constructor of the complex in the cartesian coordinates (x, y)
 * z = x + iy
 *
 */

function Complex()
{

    var self = this;

    // Cartesian notation
    // z = x + iy
    var x;
    var y;

    // Polar notation
    // z = r (cos(f) + i sin(f))
    // z = r exp(if)
    var r;
    var f;

    // Initialization
    x = Number(arguments[0]) || 0;
    y = Number(arguments[1]) || 0;

    if ( arguments.callee.caller == Complex.construct ) {
        r = Number(arguments[2]);
        f = Number(arguments[3]);
    } else {
        r = Math.sqrt(x * x + y * y);
        f = Math.atan2(y, x);
    }

    // Normalization within the left-opened interval (-pi +pi]
    if ( f > Math.PI || f <= -Math.PI ) {
        var pi2 = 2 * Math.PI;

        f += Math.PI;
        f -= Math.floor(f / pi2) * pi2;
        f -= Math.PI;
    }

    /**
     * Comparison of complex
     *
     */

    self.equals = function(z)
    {
        return x == z.re() && y == z.im();
    };

    /**
     * True if the complex is real
     *
     */

    self.isReal = function()
    {
        return y == 0;
    };

    /**
     * Re(z) = x
     *
     */

    self.re = function()
    {
        return x;
    };

    /**
     * Im(z) = y
     *
     */

    self.im = function()
    {
        return y;
    };

    /**
     * Module (absolute value) of z
     * |z| = sqrt(x^2 + y^2)
     *
     */

    self.abs = function()
    {
        return r;
    };

    /**
     * Argument of z
     * Arg(z) = arctg(y / x)
     *
     */

    self.arg = function()
    {
        return f;
    };

    /**
     * Complex conjugate
     * z  = x + iy
     * z' = x - iy
     *
     */

    self.conj = function()
    {
        return Complex.construct(x, -y, r, -f);
    };

    /**
     * Complex negative
     *
     */

    self.neg = function()
    {
        return Complex.construct(-x, -y, r, r ? f + Math.PI : 0);
    };

    /**
     * Add
     *
     */

    self.add = function()
    {
        var x1 = x;
        var y1 = y;
        for (var i = 0; i < arguments.length; i++) {
            var z = arguments[i];
            x1 += z.re();
            y1 += z.im();
        }
        return new Complex(x1, y1);
    };

    /**
     * Substract
     *
     */

    self.sub = function()
    {
        var x1 = x;
        var y1 = y;
        for (var i = 0; i < arguments.length; i++) {
            var z = arguments[i];
            x1 -= z.re();
            y1 -= z.im();
        }
        return new Complex(x1, y1);
    };

    /**
     * Multiply
     *
     */

    self.mul = function()
    {
        var r1 = r;
        var f1 = f;
        for (var i = 0; i < arguments.length; i++) {
            var z = arguments[i];
            r1 *= z.abs();
            f1 += z.arg();
        }
        return Complex.fromPolar(r1, f1);
    };

    /**
     * Divide
     *
     */

    self.div = function()
    {
        var r1 = r;
        var f1 = f;
        for (var i = 0; i < arguments.length; i++) {
            var z = arguments[i];
            r1 /= z.abs();
            f1 -= z.arg();
        }
        return Complex.fromPolar(r1, f1);
    };

    /**
     * Degree z^n
     *
     */

    self.pow = function(n)
    {
        n = Number(n) || 0;
        return Complex.fromPolar(Math.pow(r, n), f * n);
    };

    /**
     * Returns the list of n-th roots
     *
     */

    self.roots = function(n, toPolar)
    {
        n = Number(n);

        if ( n - Math.floor(n) ) {
            return Number.NaN;
        }

        var nr = Math.pow(r, 1 / n);
        var nf = [];

        var fi = f / n;
        var d = Math.PI * 2 / n;
       
        n = Math.abs(n);
        var i = n;
        while ( i-- ) {
            nf.push(fi);
            fi += d;
        };

        if ( toPolar ) {
            nf.abs = nr;
            return nf;
        }

        var z = [];
        for (var i = 0; i < n; i++) {
            z.push(Complex.fromPolar(nr, nf[i]));
        }

        return z;
    };

    /**
     * Square root of z
     *
     */

    self.sqrt = function()
    {
        return Complex.fromPolar(Math.sqrt(r), f / 2);
    };

    /**
     * Exponential exp(z)
     *
     */

    self.exp = function()
    {
        return Complex.fromPolar(Math.exp(x), y);
    };

    /**
     * Natural logarithm ln(z)
     *
     */

    self.log = function()
    {
        return new Complex(Math.log(r), f);
    };

    /**
     * Creates a new complex from itself
     *
     */

    self.z = function()
    {
        return Complex.construct(this.re(), this.im(), this.abs(), this.arg());
    };

    var eps = function(x)
    {
        return Math.abs(x) <= Complex.ZERO_THRESHOLD ? 0 : x;
    };

    /**
     * String presentation of the complex number
     * If toPolar is true then this method returns the (r, f) pair
     * Otherwise the (x, y) pair
     *
     */

    self.toString = function(toPolar)
    {
        if ( toPolar ) {
            return [eps(r), eps(f)].join(' ');
        }

        if ( ! eps(y) ) {
            return '' + eps(x);
        }

        return [eps(x), y].join('i');
    };

};

/**
 * Zero displaying threshold
 * ZERO_THRESHOLD = 1e-15
 */

Complex.ZERO_THRESHOLD = 1e-15;

/**
 * Internally used method
 *
 */

Complex.construct = function(x, y, r, f)
{
    return new Complex(x, y, r, f);
};

/**
 * Creates a complex from polar coordinates (r, f)
 * z = r (cos(f) + isin(f))
 * z = r exp(if)
 *
 */

Complex.fromPolar = function()
{
    var r = Number(arguments[0]) || 0;
    var f = Number(arguments[1]) || 0;

    var x = r * Math.cos(f);
    var y = r * Math.sin(f);

    return Complex.construct(x, y, r, f);
};

/**
 * Creates a complex from a real
 *
 */

Complex.re = function()
{
    if ( arguments[0] && arguments[0].constructor != Number ) {
        throw new TypeError();
    }

    var n = Number(arguments[0]) || 0;
    return n.z();
};

/**
 * Creates imaginary number
 *
 */

Complex.im = function()
{
    if ( arguments[0] && arguments[0].constructor != Number ) {
        throw new TypeError();
    }

    var y = Number(arguments[0]) || 1;
    var f = Math.PI / 2;
    return Complex.construct(0, y, Math.abs(y), y < 0 ? -f : f);
};

/**
 * Clones new complex without calculation of internal variables
 *
 */

Complex.z = function(x, y)
{
    return new Complex(x, y);
};

/**
 * Methods for compatibility of Number with Complex
 *
 */

Number.prototype.equals = function(z)
{
    return this == z.re() && z.im() == 0;
};

Number.prototype.isReal = function()
{
    return true;
};

Number.prototype.re = function()
{
    return this;
};

Number.prototype.im = function()
{
    return 0;
};

Number.prototype.abs = function()
{
    return Math.abs(this);
};

Number.prototype.arg = function()
{
    return this >= 0 ? 0 : Math.PI;
};

Number.prototype.conj = function()
{
    return this.z();
};

Number.prototype.neg = function()
{
    return (-this).z();
};

Number.prototype.add = function(z)
{
    return this.z().add.apply(this, arguments);
};

Number.prototype.sub = function(z)
{
    return this.z().sub.apply(this, arguments);
};

Number.prototype.mul = function(z)
{
    return this.z().mul.apply(this, arguments);
};

Number.prototype.div = function(z)
{
    return this.z().pow.apply(this, arguments);
};

Number.prototype.pow = function(n)
{
    return this.z().pow(n);
};

Number.prototype.roots = function(n, toPolar)
{
    return this.z().roots(n, toPolar);
};

Number.prototype.sqrt = function()
{
    return this.z().sqrt();
};

Number.prototype.exp = function()
{
    return Math.exp(this).z();
};

Number.prototype.log = function()
{
    return this.z().log();
};

Number.prototype.z = function()
{
    return Complex.construct(this.re(), this.im(), this.abs(), this.arg());
};


Last edited by Rumata on Sun Jun 21, 2009 1:57 pm; edited 6 times in total
Back to top
View user's profile Send private message
Юрий Насретдинов
Модератор



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

Location: 007 495

PostPosted: Sat Jun 13, 2009 2:42 pm (спустя 1 час 43 минуты; написано за 3 минуты 31 секунду)
   Post subject:
Reply with quote

Rumata wrote:
self.neg = function()
    {
        return Complex.construct(-x, -y, r, -f);
    };
Кажется, тут всё-таки ошибка.
К примеру: есть число 1. У него аргумент = 0. После того, как взяли его с обратным знаком (-1), согласно этой формуле аргумент всё равно остаётся 0. А должен быть аргумент PI (ну или -PI). Поэтому, правильная формула должна выглядеть примерно так:
Code (JavaScript): скопировать код в буфер обмена
self.neg = function()
    {
        return Complex.construct(-x, -y, r, f>0 ? Math.PI-f : Math.PI-f - 2*Math.PI);
    };
Back to top
View user's profile Send private message Send e-mail
Rumata
Профессионал



Joined: 17 Aug 2003
Posts: 1850
Карма: 184
   поощрить/наказать


PostPosted: Sat Jun 13, 2009 3:56 pm (спустя 1 час 14 минут; написано за 2 минуты 43 секунды)
   Post subject:
Reply with quote

И то верно. Юрий Насретдинов, спасибо за подсказку. Издержки копи-паста. Вот верный вариант:
Code (JavaScript): скопировать код в буфер обмена
    self.neg = function()
    {
        return Complex.construct(-x, -y, r, r ? -f || Math.PI : 0);
    };
Учитывает действительные числа и "комплексные нули", так что аргументы чисел лежат в интервале (-pi, +pi], а ноль он по всем параметрам ноль.

Last edited by Rumata on Sat Jun 13, 2009 4:31 pm; edited 1 time in total
Back to top
View user's profile Send private message
Александр Михалицын
Модератор



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


PostPosted: Sat Jun 13, 2009 4:22 pm (спустя 25 минут; написано за 1 минуту 14 секунд)
   Post subject:
Reply with quote

Rumata,
[+] За хорошую реализацию.

М

Я думаю самое время переместить эти классы в "склад". Не так ли?
Что решим? Оба ваших класса туда выставить?
Back to top
View user's profile Send private message Send e-mail
Юрий Насретдинов
Модератор



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

Location: 007 495

PostPosted: Sat Jun 13, 2009 4:22 pm (спустя 30 секунд; написано за 2 минуты 36 секунд)
   Post subject:
Reply with quote

Сильно измененная версия, по-максимуму избавленная от непонятных и сложных операций (кроме метода .toString(), который сделан «умным»).

Также изменено название класса с Complex на Z для краткости, а также новый способ передачи аргументов функциям: если указывается 2 аргумента, а не 1, то они трактуются как компоненты комплексного числа.

Пример:
Code (JavaScript): скопировать код в буфер обмена
var a = new Z(1,2);
alert( a.mul(0,1) ); // выведет -2+i

// эквивалентно следующему:

alert( a.mul( new Z(0,1) ) ); // выведет то же самое
 
Код:
Code (JavaScript): скопировать код в буфер обмена
function Z(x,y,r,f) { this.construct(x,y,r,f); }

Z.prototype = {
   
    /* should be read-only properties */
    x: 0,
    y: 0,
    r: 0, // abs
    f: 0, // arg
   
    construct: function(x,y,r,f)
    {
        if(r && r < 0) throw new Error('Absolute value of a complex number cannot be less than zero');
       
        if(r)
        {
            x = r*Math.cos(f);
            y = r*Math.sin(f);
        }
       
        this.x = x;
        this.y = y;
        this.r = r || Math.sqrt(x*x+y*y);
        this.f = Math.atan2(y,x); // guarantees that you get normalized form of arg
    },
   
    toString: function(polar)
    {
        var sign = function(x) { return x<0 ? '-' : '+'; }
        var sigm = function(x) { return x<0 ? '-' : ''; } // returns "-" or nothing
        var a = function(x) { return Math.abs(x); }
        var is0 = this._is0;
        var is1 = function(x) { return is0(a(x) - 1); } // is |x| == 1 ?
       
        var r = this.r, f = this.f, x = this.x, y = this.y;
       
        if(is0(r)) return '0';
       
        var ans = '';
       
        if(polar)
        {
            var rm = is1(r) ? '': r;
            var exp = is0(f) ? '' : 'exp('+(is1(f) ? sigm(f)+'i' : sigm(f)+'i*'+a(f))+')';
           
            ans = rm + (!is1(r)&&exp?'*':'') + exp;
           
            if(!ans.length) ans+='1'; // either sign (-) or nothing means 1
        }else
        {
            ans = (is0(x)?'':x)+(is0(y) ? '' : sign(y)+'i'+(is1(y)?'':'*'+a(y)));
        }
       
        return ans;
    },
   
    mul: function(b)
    {
        b = this._pa(b,arguments);
       
        var a = this;
        return new Z(a.x*b.x - a.y*b.y, a.y*b.x + b.y*a.x);
    },
   
    // complex division: returns (a/b)
   
    div: function(b)
    {
        b = this._pa(b,arguments);
       
        // a/b = a*(b*) / |b|^2, where b* = Re b - i*Im b
       
        if(!b.r) throw new Error('Complex division by zero');
       
        return this.mul( b.x/b.r/b.r, -b.y/b.r/b.r )
    },
   
    add: function(b)
    {
        b = this._pa(b,arguments);
       
        return new Z( this.x + b.x, this.y + b.y );
    },
   
    // z - b
    sub: function(b)
    {
        b = this._pa(b,arguments);
       
        return new Z( this.x - b.x, this.y - b.y);
    },
   
    neg: function()
    {
        return new Z( -this.x, -this.y );
    },
   
    conj: function()
    {
        return new Z(  this.x, -this.y );
    },
   
    // is*() return BOOL
   
    isEqual: function(b)
    {
        b = this._pa(b,arguments);
        return this._is0(b.x - this.x) && this._is0(b.y - this.y);
    },
   
    isReal: function()
    {
        return this._is0(this.y);
    },
   
    isIm: function()
    {
        return this._is0(this.x);
    },
   
    // power: z^b (b is complex!)
   
    pow: function(b)
    {
        b = this._pa(b,arguments);
        // z^a = exp(a * log(z) )
        return b.mul( this.log() ).exp();
    },
   
    // complex logarithm of a number
    // the result is given only for _main_ branch of the logarithm
    // if you want other branches, add or subtract 2*PI*i as many times as you want
   
    log: function()
    {
        return new Z( Math.log(this.r), this.f );
    },
   
    // alias for log
    ln: function()
    {
        return this.log();
    },
   
    // exp(z), z is complex
   
    exp: function()
    {
        return new Z(0, 0, Math.exp(this.x), this.y );
    },
   
    // sin(z)
   
    sin: function()
    {
        var z = this;
       
        var z1 = z.mul(0,1);
        var z2 = z1.neg();
       
        return ( z1.exp() ).sub( z2.exp() ).div(0,2);
    },
   
    // cos(z)
   
    cos: function()
    {
        var z = this;
       
        var z1 = z.mul(0,1);
        var z2 = z1.neg();
       
        return ( z1.exp() ).add( z2.exp() ).div(2,0);
    },
   
    // check, if the method of Z with name mname
    // is differentiable at point z
    //
    // _diff_delta and _diff_eps are the value of delta in formula f'(x) = (f(x+delta)-f(x))/delta
    // and the value of epsilon when f'(x-0) is compared to f'(x+0) and other
    // derivatives comparison
   
    _diff_delta: Math.pow(2, -25),
    _diff_eps: Math.pow(2, -15),
   
    is_diff: function(mname, alert_reason)
    {
        try
        {
            var der = this.deriv(mname);
        }catch(e)
        {
            if(alert_reason) alert(e);
            return false;
        }
       
        return true;
    },
   
    deriv: function(mname)
    {
        var z = this;
        var x0 = z.x, y0 = z.y;
       
        // the idea is that a complex function is differentiable if
        // the Cauchy-Riemann conditions are satisfied
       
        // f(z) = u(x,y) + i*v(x,y)
        //
        // define real functions of 1 argument
       
        try
        {
            var ux = this._deriv( function(x){ return (new Z(x,y0))[mname]().x; }, x0, 'ux', mname); // u'(x,y0)|x=x0
            var uy = this._deriv( function(y){ return (new Z(x0,y))[mname]().x; }, y0, 'uy', mname); // u'(x0,y)|y=y0
           
            var vx = this._deriv( function(x){ return (new Z(x,y0))[mname]().y; }, x0, 'vx', mname); // v'(x,y0)|x=x0
            var vy = this._deriv( function(y){ return (new Z(x0,y))[mname]().y; }, y0, 'vy', mname); // v'(x0,y)|y=y0
        }catch(e)
        {
            // there is only 1 case when the exception is thrown: when a real function is non-diff
            throw e;
        }
       
        var damp = Math.max(Math.abs(ux), Math.abs(uy), Math.abs(vx), Math.abs(vy)); // damping factor to take scale of variables into account
        if(damp < 1) damp = 1;
       
        if( !this._diff_is0( (ux-vy)/damp ) || !this._diff_is0( (uy+vx)/damp )  ) throw new Error('Cauchy-Riemann conditions for '+mname+' are not met (ux-vy='+(ux-vy)+', uy+vx='+(uy+vx)+')');
       
        return new Z(ux, vx);
    },
   
    // count the derivative of a real function func
    // at real point x
   
    _deriv: function(func, x, fname, mname)
    {
        var delta = this._diff_delta; // the function of x must not oscillate faster than 1/delta
       
        if(Math.abs(x) > 1) delta *= Math.abs(x); // coefficient for delta and epsilon to take scale into account
       
        var left_der  = (func(x) - func(x - delta)) / delta;
        var right_der = (func(x + delta) - func(x)) / delta;
       
        var damp = Math.max(Math.abs(left_der), Math.abs(right_der)); // damping factor to take scale of variables into account
        if(damp < 1) damp = 1;
       
        if( ! this._diff_is0( (left_der - right_der) / damp) ) throw new Error('The function '+fname+' of '+mname+' is non-differentiable (left_der - right_der = '+(left_der - right_der)+', left_der = '+(left_der)+', right_der = '+(right_der)+')'); // the function is not differentiable in that point
       
        return (left_der + right_der)/2;
    },
   
    _pa: function(b,args) // _parseArguments -- returns new b if needed
    {
        if(args.length==2) b = new Z(args[0], args[1]);
        if(b.length && b.length == 2) b = new Z(b[0],b[1]);
        if(!b instanceof Z) b = new Z(b,0);
       
        return b;
    },
   
    _is0: function(x)
    {
        return Math.abs(x) < 1e-15;
    },
   
    _diff_is0: function(x)
    {
        return Math.abs(x) < this._diff_eps;
    }

};

Z.ONE = new Z(1,0);
Z.I   = new Z(0,1);

var sq_eq_solver = {
   
    // a, b, c -- complex numbers
    //
    // another difference -- if a==0,b!=0 the answer is returned in format [ z ]
    // returns [z1, z2], where z1 and z2 are the roots
   
    solve: function(a,b,c)
    {
        if(!a.r) return b.r ? c.div(b).neg() : !c.r;
       
        // scale coeffs so, that a=0.5 and x1,x2 = ( -b +- sqrt(D) ); ( 1/2a == 1)
        var two_a_i = new Z(0.5,0).div(a); // 1/2a
       
        a=new Z(0.5,0);
        b=b.mul(two_a_i); // b = b*(1/2a)
        c=c.mul(two_a_i); // c = c*(1/2a)
       
        var D = b.mul(b).sub( c.mul(2,0) ); // var D = b*b - 2*c;
        var sqD = D.pow(1/2,0);
       
        var nb = b.neg();
        return [nb.add(sqD), nb.sub(sqD)];
    }
};

alert( sq_eq_solver.solve( new Z(2,0) , new Z(-8,-6), new Z(-4,16) ) );
//
var a = new Z(1,2);
alert( a.mul(0,1) );
//
alert('check, if are differentiable:\n\n' +
      'sin: '+(new Z(100,100)).is_diff('sin', 1) + '\n' +
      'cos: '+(new Z(100,100)).is_diff('cos', 1) + '\n' +
      'exp: '+(new Z(100,100)).is_diff('exp', 1) + '\n' +
      'conj: '+(new Z(5e10,5e10)).is_diff('conj', 1) + '\n' +
      'neg: '+(new Z(5000,5000)).is_diff('neg', 1) + '\n' +
      'log: '+(new Z(5000,5000)).is_diff('log', 1) + '\n' +
      '');


Last edited by Юрий Насретдинов on Tue Jun 16, 2009 3:31 pm; edited 11 times in total
Back to top
View user's profile Send private message Send e-mail
Юрий Насретдинов
Модератор



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

Location: 007 495

PostPosted: Sat Jun 13, 2009 4:32 pm (спустя 10 минут; написано за 3 минуты 1 секунду)
   Post subject:
Reply with quote

Rumata wrote:
self.neg = function()
    {
        return Complex.construct(-x, -y, r, x || y ? -f || Math.PI : 0);
    };
И всё равно «не то»...

Сравните:
Code (JavaScript): скопировать код в буфер обмена
var a = new Z(1,1.5);
var b = new Complex(1,1.5);
alert(a.neg().toString(true) + ' vs. ' + b.neg().toString(true));

// выведет 1.8027756377319946*exp(-i*2.158798930342464) vs. 1.8027756377319946 -0.982793723247329
 
Лучше в таком случае просто Math.atan2() используйте напрямую:
Code (JavaScript): скопировать код в буфер обмена
self.neg = function()
    {
        return Complex.construct(-x, -y, r, Math.atan2(-y,-x));
    };
Простая же задача, вот смотрите:

-1 = exp(i*PI) = exp(-i*PI)
-1*r*exp(i*f) = exp(-i*PI)*r*exp(i*f) = r*exp(i*(f-PI));

Откуда у Вас берется просто «-f»??
Back to top
View user's profile Send private message Send e-mail
Rumata
Профессионал



Joined: 17 Aug 2003
Posts: 1850
Карма: 184
   поощрить/наказать


PostPosted: Sat Jun 13, 2009 4:44 pm (спустя 11 минут; написано за 9 секунд)
   Post subject:
Reply with quote

Юрий Насретдинов wrote:
Также изменено название класса с Complex на Z для краткости, а также новый способ передачи аргументов функциям: если указывается 2 аргумента, а не 1, то они трактуются как компоненты комплексного числа.
Очень понравилась идея с аргументами. А также можно массив двух элементов трактовать как комплексное число, и т.д (-:. Немного спорно переименование, но, в-целом, тоже нравится.

Мне больше нравится "сливать" всякие вычисления в eval, например:
Code (JavaScript): скопировать код в буфер обмена
eval.equ2 = fucntion(a, b, c)
...

var x = eval.equ2(1, 1, -1);
Back to top
View user's profile Send private message
Rumata
Профессионал



Joined: 17 Aug 2003
Posts: 1850
Карма: 184
   поощрить/наказать


PostPosted: Sat Jun 13, 2009 4:52 pm (спустя 8 минут; написано за 8 секунд)
   Post subject:
Reply with quote

Юрий Насретдинов wrote:
И всё равно «не то
А-а-а! Шайтан!
Back to top
View user's profile Send private message
Юрий Насретдинов
Модератор



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

Location: 007 495

PostPosted: Sat Jun 13, 2009 4:53 pm (спустя 46 секунд; написано за 5 секунд)
   Post subject:
Reply with quote

Rumata wrote:
eval.equ2 = fucntion(a, b, c)
...

var x = eval.equ2(1, 1, -1);
Да, идея прикольная :).
Rumata wrote:
А также можно массив двух элементов трактовать как комплексное число, и т.д (-:.
И т.д., к сожалению, лень, но вот про массив из двух элементов добавил :).
Back to top
View user's profile Send private message Send e-mail
Юрий Насретдинов
Модератор



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

Location: 007 495

PostPosted: Sat Jun 13, 2009 5:11 pm (спустя 18 минут; написано за 55 секунд)
   Post subject:
Reply with quote

Rumata wrote:
self.neg = function()
    {
        return Complex.construct(-x, -y, r, r ? f + Math.PI : 0);
    };
Хехе :). А если f > 0, то у Вас получится, что новый аргумент выходит за границы (-pi, pi], что как бы не очень здорово (а при извлечении корня так вообще губительно).
Back to top
View user's profile Send private message Send e-mail
Rumata
Профессионал



Joined: 17 Aug 2003
Posts: 1850
Карма: 184
   поощрить/наказать


PostPosted: Sat Jun 13, 2009 5:24 pm (спустя 12 минут; написано за 30 секунд)
   Post subject:
Reply with quote

Юрий Насретдинов wrote:
И всё равно «не то»...
Я всячески не хотел делать вычисления компонентов (корни, квадраты, арктангенсы), поэтому у меня вылезло -f, когда надо было f+PI или f-PI. Или опять ошибка?
Юрий Насретдинов wrote:
если f > 0, то у Вас получится, что новый аргумен
Не выходит. Учтено изначально в Complex.construct.
Back to top
View user's profile Send private message
Юрий Насретдинов
Модератор



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

Location: 007 495

PostPosted: Sat Jun 13, 2009 5:36 pm (спустя 12 минут; написано за 1 минуту 9 секунд)
   Post subject:
Reply with quote

Rumata wrote:
Я всячески не хотел делать вычисления компонентов (корни, квадраты, арктангенсы), поэтому у меня вылезло -f, когда надо было f+PI или f-PI. Или опять ошибка?
Да, вроде бы теперь нормально, с учетом проверки в конструкторе.
В моем классе таких проблем чисто в принципе не возникло, потому что у меня в конструкторе значения r и f в основном синтезируются на основе x и y, а не считаются вручную :).
Back to top
View user's profile Send private message Send e-mail
Rumata
Профессионал



Joined: 17 Aug 2003
Posts: 1850
Карма: 184
   поощрить/наказать


PostPosted: Sat Jun 13, 2009 5:54 pm (спустя 18 минут; написано за 8 минут 54 секунды)
   Post subject:
Reply with quote

Да. Когда я начал реализовывать свой класс, у меня возникла мысль, что неплохо бы вычислять сразу все части числа, тогда код усложняется ненамного, а преимущества видны сразу - инициализация объекта комплексного числа готовыми полями для исключения некоторых вычислений (например, при умножении используются модули и аргументы перемножаемых чисел). Насколько это оправдано, сказать сложно. Оба представления (x, y) и (r, f) - равнозначны и при выборе только одного представления неизбежна операция перевода из одного в другое. Ну а эта путаница - conj() и neg() была создана бездумным копированием и исправлением первого из второй.
Back to top
View user's profile Send private message
Юрий Насретдинов
Модератор



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

Location: 007 495

PostPosted: Sat Jun 13, 2009 6:12 pm (спустя 18 минут; написано за 4 минуты)
   Post subject:
Reply with quote

Rumata
«Но и это ещё не всё» ©

Нормализация аргумента сделана тоже некорректно :) (я это заметил, когда добавил нормализацию аргумента в свой конструктор)!

Смотрите:
Code (JavaScript): скопировать код в буфер обмена
var a = new Z(0,0,1,2.5*Math.PI);
alert(a.toString(true));

var b = Complex.fromPolar(1,2.5*Math.PI);
alert( b.toString(true) );
Аргумент (правильный) должен быть PI/2. А в Вашей реализации это -PI/2, что соответствует смене знака у числа :). Я, поэтому, некоторую хитрость добавил:
Code (JavaScript): скопировать код в буфер обмена
// normalize argument
            if(Math.abs(f) >= Math.PI)
            {
                f+=Math.PI;
                f-=Math.floor(f/2/Math.PI)*2*Math.PI;
                f-=Math.PI;
            }
Т.е. для нормализации сначала переводится к интервалу [0; 2*PI], потом аргумент нормализуется в таком интервале, а потом интервал возвращается обратно к [-PI, PI]. Границы эта вещь не учитывает, но ИМХО они не настолько важны, особенно в вычислительной технике.
Back to top
View user's profile Send private message Send e-mail
Юрий Насретдинов
Модератор



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

Location: 007 495

PostPosted: Tue Jun 16, 2009 3:08 pm (спустя 2 дня 20 часов 55 минут; написано за 6 минут 8 секунд)
   Post subject:
Reply with quote

Добавил в класс также проверку на дифференцируемость функции комплексного переменного, а также на подсчет производной от этой функции в случае её дифференцируемости.

Пример:
Code (JavaScript): скопировать код в буфер обмена
Z.prototype.tan = function()
{
        return this.sin().div( this.cos() );
}

var tp = new Z(3,5); // test point

alert( tp.deriv('tan') + ' vs. ' + Z.ONE.div( tp.cos().pow(2,0) ) ); // ( tan(z) )' = 1 / (cos(z))^2

alert('Is complex conjugation differentiable: '+tp.is_diff('conj'));
Если Вы попытаетесь посчитать производную от функции, которая не дифференцируема в этой точке, выпадет исключение наподобие (Error: Cauchy-Riemann conditions for conj are not met (ux-vy=2, uy+vx=0) или The function ux of some_func is non-differentiable (left_der - right_der = ..., left_der = ..., right_der = ...) ). Готов выслушать ваши мнения по этому поводу :).
Back to top
View user's profile Send private message Send e-mail
Rumata
Профессионал



Joined: 17 Aug 2003
Posts: 1850
Карма: 184
   поощрить/наказать


PostPosted: Sun Jun 21, 2009 2:05 pm (спустя 4 дня 22 часа 56 минут; написано за 25 секунд)
   Post subject:
Reply with quote

Юрий Насретдинов wrote:
Но и это ещё не всё
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic All times are GMT + 3 Hours
Goto page 1, 2  Next
Page 1 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