Однажды решили попрактиковаться в реализации комплексных чисел средствами 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));
Вспомогательные функции -
$Z
,
$Re
,
$Im
(
синтаксический сахар) - упрощают работу с комплексными числами:
var x = $Z(1, 1);
var y = x.add($Z(2, 0)).add($Z(3, 0));
// Расширение
var y = x.add($Z(2, 0), $Z(3, 0));
Определены методы вычисления частей комплексного числа - вещественной re(), мнимой im(), модуля abs() и аргумента arg() комплексного числа, а также вычисление сопряженного комплексного числа conj() и его отрицательного значения neg(). Функция строкового преобразования Complex.prototype.toString позволяет отобразить комплексное число как в алгебраической, так и в полярной формах. Добавлены одноименные методы объекту Number для упрощения совместной работы с комплексными и реальными числами. То есть предыдущий пример можно записать еще короче
var y = x.add(2, 3);
n-ные корни чисел вычисляются все. Результатом является как массив корней комплексных чисел (по умолчанию), так и массив аргументов комплексных чисел и общий модуль как свойство abs результирующего массива (аргументы корней определены на интервале от -pi до +pi):
var x = -2;
// два корня: i*sqrt(2), -i*sqrt(2)
var carte = x.roots(2);
// два аргумента polar = [pi/2, -pi/2], polar.abs = sqrt(2)
var polar = x.roots(2, true);
В общем, никому ненужный модуль. Баловство одно.
/**
* 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);
};
/**
* The shortcuts for the most popular methods
*
*/
var $Z = Complex.z;
var $Re = Complex.re;
var $Im = Complex.im;
/**
* 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());
};
No comments:
Post a Comment