Ultimamente ho giocato con l'insieme di Mandelbrot, il che significa che ho dovuto rispolverare la mia memoria su come fare aritmetica con numeri complessi. Ho creato una bella classe JavaScript che aiuta a ingrassare usandoli. Ecco ora funziona (è una spiegazione abbastanza asciutta, ma spero sia utile).
Quando moltiplichiamo due numeri insieme il risultato sarà pari o dispari a seconda che i numeri che stiamo moltiplicando siano:
-1 * 1 = -1
1 * -1 = -1
1 * 1 = 1
-1 * -1 = 1
i ≔ √(-1)
∴ i² = -1
Un numero complesso è un numero che ha una parte reale e una parte immaginaria . Sono scritti nel form a + bi.
Poiché 0i = 0le linee dei numeri si incontrano in 0, quindi possiamo tracciare questi numeri su un grafico, in genere l'asse x è la linea dei numeri reali e l'asse y è quella immaginaria.
Potresti aver notato che i numeri complessi assomigliano molto ai vettori e con l'avvertenza che i * i = -1lo sono. Tutte le operazioni sono solo normali operazioni vettoriali che vengono regolate in base a tale avvertenza.
Il Complexcostruttore di classi ha due parametri.
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);
}
Classe di applicazione
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;
}
}
Vitest è usato qui.
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);
});
});
Devo ammettere che è stato abbastanza divertente riscoprire quelle derivazioni, non ho fatto matematica vettoriale per molto tempo.
Questo non era esattamente un articolo entusiasmante, è molto secco ma le funzioni sono importanti se vuoi giocare con gli insiemi di Mandelbrot o Julia o qualsiasi cosa richieda numeri complessi.
Grazie per aver letto.
Il processo di ammissione dell'autunno 2023 sta volgendo al termine e sono in corso rinvii/rifiuti. Congratulazioni se sei stato accettato nel programma dei tuoi sogni all'UW.
Questa settimana ho ricevuto un'e-mail da un membro della mailing list quotidiana. Volevano sapere: quali risorse visiti giornalmente, settimanalmente e mensilmente? Ottima domanda! Sono felice di provare a condividere alcune informazioni sul mio flusso di lavoro e sulle migliori risorse che utilizzo.
Quando cresci tendi a sentirti dire che il mondo è così com'è e che la tua vita è vivere la tua vita dentro il mondo, senza mai rischiare la vita, basta seguire un percorso prestabilito e morire alla fine, e cercare di non farlo sfondare troppo i muri. Ma questa è una vita molto limitata.
Ehi, cibernetici! Bentornati alla serie OSINT per la caccia alle minacce. Nel primo articolo, ti ho fornito una panoramica di OSINT e della sua importanza nella caccia alle minacce.
[Avviso di attivazione: questo saggio include schermate di persone che elogiano l'assassino di Jordan Neely.] I funzionari delle forze dell'ordine hanno finalmente - e forse con riluttanza - accusato Daniel Penny, l'uomo che ha soffocato Jordan Neely fino alla sua morte, per quell'omicidio.
Per evitare ambiguità verranno utilizzati i seguenti termini; Autenticatore; Il telefono cellulare utilizzato per effettuare il login Sito web; Il sito Web o l'applicazione che l'utente sta utilizzando per effettuare la richiesta di accesso al Servizio; Il fornitore che fornisce il servizio dato, ad es