Ich habe in letzter Zeit mit der Mandelbrot-Menge gespielt, was dazu geführt hat, dass ich meine Erinnerung daran, wie man mit komplexen Zahlen rechnet, abstauben musste. Ich habe eine nette JavaScript-Klassenhilfe erstellt, die sie verwendet. Hier ist jetzt, es funktioniert (es ist eine ziemlich trockene Erklärung, aber ich hoffe, es ist nützlich).
Wenn wir zwei Zahlen miteinander multiplizieren, ist das Ergebnis ungerade oder gerade , je nachdem, ob die Zahlen, die wir multiplizieren, lauten:
-1 * 1 = -1
1 * -1 = -1
1 * 1 = 1
-1 * -1 = 1
i ≔ √(-1)
∴ i² = -1
Eine komplexe Zahl ist eine Zahl, die einen Realteil und einen Imaginärteil hat . Sie sind in der Form geschrieben a + bi.
Da 0i = 0sich die Zahlenlinien bei treffen 0, können wir diese Zahlen in einem Diagramm darstellen, wobei die x-Achse normalerweise die reelle Zahlenlinie und die y-Achse die imaginäre ist.
Sie haben vielleicht bemerkt, dass komplexe Zahlen sehr wie Vektoren aussehen, und mit dem Vorbehalt, dass i * i = -1sie es sind. Alle Operationen sind nur reguläre Vektoroperationen, die basierend auf dieser Einschränkung angepasst werden.
Der ComplexKlassenkonstruktor hat zwei Parameter.
realimaginaryexport class Complex {
constructor(real, imaginary) {
this.real = real;
this.imaginary = imaginary;
}
}
/***
* Generate a new <code>Complex(0,0)</code>
* @returns {Complex}
*/
static zero = () => new Complex(0, 0);
/***
* Returns a string in the form <code>a ± bi</code>.
* @returns {string}
*/
toString() {
const operator = this.imaginary < 0 ? '-' : '+';
return `${this.real} ${operator} ${Math.abs(this.imaginary)}i`;
}
/***
* Both <i>real</i> and <i>imaginary</i> parts are equal.
* @param other
* @returns {boolean}
*/
equals(other) {
return this.real === other.real && this.imaginary === other.imaginary;
}
add(other) {
return new Complex(
this.real + other.real,
this.imaginary + other.imaginary
);
}
subtract(other) {
return new Complex(
this.real — other.real,
this.imaginary — other.imaginary
);
}
/***
* Multiple this Complex with another.<br/>
* <code>(a + bi)(c + di) = (ac - bd) + (ad + bc)i</code>
* @param other
* @returns {Complex}
*/
multiply(other) {
return new Complex(
this.real * other.real - this.imaginary * other.imaginary,
this.real * other.imaginary + this.imaginary * other.real
);
}
/***
* <code>(a + bi) / (c + di) = [(ac + bd) / (c^2 + d^2)] + [(bc - ad) / (c^2 + d^2)]i<code>
* @param other
*/
divide(other) {
const otherMagnitudeSquared =
other.real * other.real + other.imaginary * other.imaginary;
const r =
(this.real * other.real + this.imaginary * other.imaginary) /
otherMagnitudeSquared;
const i =
(this.imaginary * other.real - this.real * other.imaginary) /
otherMagnitudeSquared;
return new Complex(r, i);
}
Anwendungsklasse
export class Complex {
constructor(real, imaginary) {
this.real = real;
this.imaginary = imaginary;
}
/***
* Generate a new <code>Complex(0,0)</code>
* @returns {Complex}
*/
static zero = () => new Complex(0, 0);
add(other) {
return new Complex(
this.real + other.real,
this.imaginary + other.imaginary
);
}
subtract(other) {
return new Complex(
this.real - other.real,
this.imaginary - other.imaginary
);
}
/***
* Multiple this Complex with another.<br/>
* <code>(a + bi)(c + di) = (ac - bd) + (ad + bc)i</code>
* @param other
* @returns {Complex}
*/
multiply(other) {
return new Complex(
this.real * other.real - this.imaginary * other.imaginary,
this.real * other.imaginary + this.imaginary * other.real
);
}
/***
* <code>(a + bi) / (c + di) = [(ac + bd) / (c^2 + d^2)] + [(bc - ad) / (c^2 + d^2)]i<code>
* @param other
*/
divide(other) {
const otherMagnitudeSquared =
other.real * other.real + other.imaginary * other.imaginary;
const r =
(this.real * other.real + this.imaginary * other.imaginary) /
otherMagnitudeSquared;
const i =
(this.imaginary * other.real - this.real * other.imaginary) /
otherMagnitudeSquared;
return new Complex(r, i);
}
magnitude() {
return Math.sqrt(
this.real * this.real + this.imaginary * this.imaginary
);
}
/***
* Returns a string in the form <code>a ± bi</code>.
* @returns {string}
*/
toString() {
const operator = this.imaginary < 0 ? '-' : '+';
return `${this.real} ${operator} ${Math.abs(this.imaginary)}i`;
}
/***
* Both <i>real</i> and <i>imaginary</i> parts are equal.
* @param other
* @returns {boolean}
*/
equals(other) {
return this.real === other.real && this.imaginary === other.imaginary;
}
}
Hier kommt Vitest zum Einsatz.
import { describe, it, expect } from 'vitest';
import { Complex } from './Complex.js';
describe('Calling zero()', () => {
const zero = Complex.zero();
it('should return 0 real part', () => {
expect(zero.real).toBe(0);
});
it('should return 0 imaginary part', () => {
expect(zero.imaginary).toBe(0);
});
});
describe('Creating a new number', () => {
const expectedReal = Math.random();
const expectedImaginary = Math.random();
const actual = new Complex(expectedReal, expectedImaginary);
it(`should return the expected real part (${expectedReal})`, () => {
expect(actual.real).toBe(expectedReal);
});
it(`should return the expected imaginary part (${expectedImaginary})`, () => {
expect(actual.imaginary).toBe(expectedImaginary);
});
});
it('Should correctly calculate the magnitude', () => {
const dummyReal = Math.random();
const dummyImaginary = Math.random();
const expected = Math.sqrt(
dummyReal * dummyReal + dummyImaginary * dummyImaginary
);
const actual = new Complex(dummyReal, dummyImaginary).magnitude();
console.dir({ dummyReal, dummyImaginary, actual, expected });
expect(actual).toBe(expected);
});
describe('Equality', () => {
it('should return true when equal', () => {
const complex1 = new Complex(Math.random(), Math.random());
const complex2 = new Complex(complex1.real, complex1.imaginary);
const actual = complex1.equals(complex2);
expect(actual).toBe(true);
});
it('should return false when real part differs', () => {
const complex1 = new Complex(Math.random(), Math.random());
const complex2 = new Complex(complex1.real + 1, complex1.imaginary);
const actual = complex1.equals(complex2);
expect(actual).toBe(false);
});
it('should return true when equal', () => {
const complex1 = new Complex(Math.random(), Math.random());
const complex2 = new Complex(complex1.real, complex1.imaginary + 1);
const actual = complex1.equals(complex2);
expect(actual).toBe(false);
});
});
describe('Arithmetic', () => {
const complex1 = new Complex(6, 3);
const complex2 = new Complex(7, -5);
describe('Add', () => {
const expectedReal = complex1.real + complex2.real;
const expectedImaginary = complex1.imaginary + complex2.imaginary;
const actual = complex1.add(complex2);
it(`Real part should be ${expectedReal}`, () => {
expect(actual.real).toBe(expectedReal);
});
it(`Imaginary part should be ${expectedImaginary}`, () => {
expect(actual.imaginary).toBe(expectedImaginary);
});
});
describe('Subtract', () => {
const expectedReal = complex1.real - complex2.real;
const expectedImaginary = complex1.imaginary - complex2.imaginary;
const actual = complex1.subtract(complex2);
it(`Real part should be ${expectedReal}`, () => {
expect(actual.real).toBe(expectedReal);
});
it(`Imaginary part should be ${expectedImaginary}`, () => {
expect(actual.imaginary).toBe(expectedImaginary);
});
});
describe('Multiply', () => {
const expectedReal = complex1.real + complex2.real;
const expectedImaginary = complex1.imaginary + complex2.imaginary;
const actual = complex1.add(complex2);
it(`Real part should be ${expectedReal}`, () => {
expect(actual.real).toBe(expectedReal);
});
it(`Imaginary part should be ${expectedImaginary}`, () => {
expect(actual.imaginary).toBe(expectedImaginary);
});
});
describe('Divide', () => {
const expectedReal = 27 / 74;
const expectedImaginary = 51 / 74;
const actual = complex1.divide(complex2);
it(`should have correct real`, () => {
expect(actual.real).toBe(expectedReal);
});
it(`should have correct imaginary`, () => {
expect(actual.imaginary).toBe(expectedImaginary);
});
});
});
describe('toString()', () => {
it('for positive imaginary part', () => {
const dummyReal = 1;
const dummyImaginary = 1;
const expected = `${dummyReal} + ${dummyImaginary}i`;
const actual = new Complex(dummyReal, dummyImaginary).toString();
expect(actual).toBe(expected);
});
it('for zero imaginary part', () => {
const dummyReal = 1;
const dummyImaginary = 0;
const expected = `${dummyReal} + ${dummyImaginary}i`;
const actual = new Complex(dummyReal, dummyImaginary).toString();
expect(actual).toBe(expected);
});
it('for negative imaginary part', () => {
const dummyReal = 1;
const dummyImaginary = -1;
const expected = `${dummyReal} - ${Math.abs(dummyImaginary)}i`;
const actual = new Complex(dummyReal, dummyImaginary).toString();
expect(actual).toBe(expected);
});
});
Ich muss zugeben, es hat Spaß gemacht, diese Ableitungen wiederzuentdecken, ich habe mich schon lange nicht mehr mit Vektorrechnung beschäftigt.
Das war nicht gerade ein aufregender Artikel, er ist sehr trocken, aber die Funktionen sind wichtig, wenn Sie mit Mandelbrot- oder Julia-Mengen oder allem spielen wollen, was komplexe Zahlen benötigt.
Danke fürs Lesen.
Das Zulassungsverfahren für Herbst 2023 geht zu Ende und es kommt zu Verschiebungen/Ablehnungen. Herzlichen Glückwunsch, wenn Sie in Ihr Traumprogramm an der UW aufgenommen wurden.
Diese Woche erhielt ich eine E-Mail von einem Mitglied der täglichen E-Mail-Liste. Sie wollten wissen: Welche Ressourcen besuchen Sie täglich, wöchentlich und monatlich? Tolle Frage! Ich versuche gerne, einige Einblicke in meinen Arbeitsablauf und die wichtigsten Ressourcen, die ich verwende, mit Ihnen zu teilen.
Ich war kürzlich auf Linkedin, dem weltweit größten professionellen sozialen Netzwerk, und habe Beiträge von freiberuflichen Designern gefunden, denen ich folge und die meine Aufmerksamkeit erregt haben. Sie alle haben Fotos aus Flugzeugen, am Strand mit ihren Laptops, aus Schwimmbädern und Büros mit atemberaubender Aussicht gepostet.
Wenn man erwachsen wird, wird einem oft gesagt, dass die Welt so ist, wie sie ist, und dass das Leben nur darin besteht, sein Leben in der Welt zu leben, niemals sein Leben zu riskieren, einfach einem festgelegten Weg zu folgen und am Ende zu sterben, und versucht, es nicht zu tun Schlage zu viel gegen die Wände. Aber das ist ein sehr begrenztes Leben.
Offenes Tagebuch: Ein Bild pro Tag. Geschichten haben mich schon immer fasziniert.
Der Juckreiz in meiner Hand breitete sich aus, als ich mit dem örtlichen Buchhändler um ein weiteres Buch verhandelte. Dieses Buch würde wie die anderen, die ich kürzlich gekauft habe, seinen Thron auf meinem Stapel „To Be Read“ (TBR) finden; und trotzdem habe ich es gekauft.