Linear Algebra
Colin Fahey
1. Oprogramowanie
LinearAlgebra.zip
Algebra liniowa kod źródłowy (C#)
19910 bajtów
MD5: 11d8c8035cac30ba543e5e0b72ee9767
2. Wstęp
W tym artykule opisano, wektory i macierze w (d)-wymiarowej przestrzeni.
3. (d)-dimensional space: Atrybuty
3.1 Array
"tablica:" zbierania zmiennych w taki sposób, że każda zmienna ma unikatową nazwę, a takie nazwiska, które mogą być przypisane zamówienia.
Integer wartości mogą być użyte jako nazwy zmiennych w tablicy.
Na przykład, jeżeli tablica zawiera (d) zmiennych, wówczas całkowita wartość { 0, 1, 2, ..., (d-1) } mogą być przypisane do nazw zmiennych w tablicy.
3.2 (d)-wymiarowego wektora
"(d)-wymiarowego wektora:" (d) tablicę zmiennych.
"wektor części:" zmiennej w wektor.
3.3 (d)-wymiarowego wektora przestrzeni kosmicznej
"one-dimensional space:" pełny zestaw wartości, które mogą być przechowywane w jednej zmiennej.
"(d)-dimensional space:" kompletny zestaw kombinacji wartości, które mogą być przechowywane przez tablicę (d) zmiennych.
Formalna definicja "wektora miejsce:"
Niech (T) być podstawowym typu (np.: liczba rzeczywista, integer, liczba złożonych, Liczby wymierne, itp).
Każdy z podstawowych zmiennych typu jest nazwany "skalarne."
A "(T) typu (d)-wymiarowego wektora przestrzeń" jest zestaw (S) z (d)-wymiarowych wektorów dwóch operacji, oprócz (+) wektor, skalarne i mnożenie (*), spełniający warunki poniżej:
(1) Jeśli (v) i (w) są dwa dowolne wektory w (S), a następnie (v + w) jest także wektor w (S);
(2) Jeśli (u), (v) i (w) są wektory w trzech (S), a następnie (u + v) + w = u + (v + w);
[dodatek przemienność]
(3) Jeśli (v) i (w) są dwa dowolne wektory w (S), a następnie (v + w) = (w + v);
[dodatek Powiazanie]
(4) Istnieje "zera wektor," (0), w (S), takie, że dla każdego wektora (v) w (S), (v + (0)) = v;
[dodatek tożsamości]
(5) Jeśli jest jakiekolwiek (c) skalarne typu (T) i (v) jest każdego wektora w (S), a następnie produkt (c * v) jest wektor w (S);
(6) Jeśli (a), (b) i (c) są wszelkie scalars typu (T) i (v) i (w) są jakiekolwiek wektory w (S), a następnie (a + b) * v = a*v + b*v i c*(v + w) = c*v + c*w;
[multiplicative rozdzielność]
(7) Jeśli (a) i (b) są wszelkie scalars typu (T) i (v) jest każdego wektora w (S), a następnie (a*b)*v = a*(b*v);
(8) Jeżeli "1" jest skalarne typu (T) takie, że (1*1)=1 i (v) jest każdego wektora w (S), a następnie (1*v) = v;
(9) Dla każdego wektora (v) w (S), wektor (-1)*v = -v spełnia v + (-v) = (0);
[dodatek odwróć]
3.4 (d)-wymiarowy wektor kodu
Poniższy kod pokazuje w jaki sposób (d)-wymiarowego wektora, z 64-bitowe obliczenia zmiennoprzecinkowe pkt składników, mogą być wprowadzone w życie.
Tablica jest wystarczająca do reprezentowania wektora.
Kod poniżej ma tablicę zawartych w klasie, tylko dla wygody.
Kod nie jest efektywny.
A struktury (np.: "struct", wartość typu) reprezentujących wektory stałą liczbę wymiarów (przykłady: 3 lub 4) będzie prawdopodobnie znacznie bardziej wydajne niż ogólne (d)-wymiarowego wektora klasy podana tutaj.
Chociaż poniższy kod definiuje wektor z punktu elementów pływających, dokument ten również korzysta z wektorów z całkowitą komponentów.
Poniższy kod można łatwo zmodyfikować tak, by wdrożyć wektorów z całkowitą komponentów.
using System;
using System.Collections.Generic;
using System.Text;
// Multidimensional vector with 64-bit floating-point components:
public class VectorF64
{
private double[] components;
public int Dimensions()
{
if (null == this.components)
{
return (0);
}
return (this.components.Length);
}
public VectorF64()
{
this.components = null;
}
public VectorF64( params double[] paramValues )
{
this.components = null;
if (null == paramValues)
{
return;
}
int dimensions = paramValues.Length;
this.components = new double[dimensions];
for (int i = 0; i < dimensions; i++)
{
this.components[i] = paramValues[i];
}
}
public VectorF64( VectorF64 other )
{
this.components = null;
if (null == other)
{
return;
}
if (null == other.components)
{
return;
}
int dimensions = other.Dimensions();
this.components = new double[dimensions];
for (int i = 0; i < dimensions; i++)
{
this.components[i] = other.components[i];
}
}
public double this[int index]
{
get
{
if (null == this.components)
{
return (0.0);
}
if
(
(index >= 0)
&& (index < this.components.Length)
)
{
return (this.components[index]);
}
return (0.0);
}
set
{
if (null == this.components)
{
return;
}
if
(
(index >= 0)
&& (index < this.components.Length)
)
{
this.components[index] = value;
}
}
}
public void Write( int precision )
{
if (null == this.components)
{
Log.Write( String.Empty + '(' + ' ' + ')' );
return;
}
int dimensions = this.Dimensions();
if (0 == dimensions)
{
Log.Write( String.Empty + '(' + ' ' + ')' );
return;
}
// Determine the largest component width in characters
// so that we can make all components an equal width.
int largestComponentWidth = 1;
for (int i = 0; i < dimensions; i++)
{
// { index [,minwidth] [:typeCode[precision]] }
// (minwidth<0) means left-justify
String text = String.Format( String.Empty + '{' + '0' + ':'
+ 'g' + precision + '}', this[i] );
if (text.Length > largestComponentWidth)
{
largestComponentWidth = text.Length;
}
}
Log.Write( '(' );
for (int i = 0; i < dimensions; i++)
{
Log.Write( ' ' );
String text =
String.Format( String.Empty + '{' + '0' + ','
+ largestComponentWidth + ':' + 'g' + precision + '}',
this[i] );
Log.Write( text );
if ((i + 1) < dimensions)
{
Log.Write( ',' );
}
else
{
Log.Write( ' ' );
}
}
Log.Write( ')' );
}
public void WriteLine( int precision )
{
this.Write( precision );
Log.WriteLine();
}
public void WriteLine()
{
const int defaultPrecision = 8;
this.Write( defaultPrecision );
Log.WriteLine();
}
// . . .
public static void Test()
{
// A 3-dimensional vector with 64-bit floating-point components:
VectorF64 v3 = new VectorF64( 0.0, 1.0, 2.0 );
v3.WriteLine(); // ( 0, 1, 2 )
// A 4-dimensional vector with 64-bit floating-point components:
VectorF64 v4 = new VectorF64( 0.0, 1.0, 2.0, 3.0 );
v4.WriteLine(); // ( 0, 1, 2, 3 )
// . . .
}
}
"(d) zero-wymiarowych wektorów:" wektora z (d) wszystkich składników równa zeru.
public class VectorF64
{
// . . .
public static VectorF64 Zero( int dimensions )
{
VectorF64 zero = new VectorF64();
zero.components = new double[dimensions];
for (int i = 0; i < dimensions; i++)
{
zero[i] = 0.0;
}
return (zero);
}
// . . .
public static void Test()
{
// . . .
// An 8-dimensional vector with all 8 64-bit floating-point
// components set to zero:
VectorF64 z = VectorF64.Zero( 8 );
z.WriteLine(); // ( 0, 0, 0, 0, 0, 0, 0, 0 )
// . . .
}
}
3.5 (d)-dimensional space: punkty
"(d)-wymiarowa przestrzeń punkt:" tablicę zmiennych (d) z konkretnymi wartościami "(koordynuje wartości)."
"(d)-wymiarowa przestrzeń pochodzenia:" tablicę (d) ze wszystkich wartości zmiennych równa zeru.
3.6 (d)-wymiarowych wektorów: non-względne i relatywne
A (d)-wymiarowego wektora, że "nie" jest to "względne" (d)-wymiarowego wektora, które bezpośrednio stanowi stanu lub konfiguracji.
A (d)-wymiarowego wektora, że jest "względna" jest (d)-wymiarowy wektor, który reprezentuje zmiany zestawu komponentów.
Względną wektor może stanowić różnicę między dwoma non-względne wektorów.
Biorąc pod uwagę względną wektora, bez określania stanu względnej lub konfiguracji za pomocą że względna wektora wymaga łączenia, że względna wektora o braku w stosunku wektora.
Non-nosicieli i względnych w stosunku wektory są wektory.
Czy dany wektor nie jest względne lub względne muszą być określone, gdy wektor jest określony.
Jeśli (d)-wymiarowy wektor jest interpretowane jako non-względne, a następnie (d)-wymiarowy wektor może stanowić punkt w (d)-wymiarowej przestrzeni.
3.7 (d)-wymiarowego wektora dodawania, odejmowania, skalowania
Vector dodawania, odejmowania, skalowania:
public class VectorF64
{
// . . .
public static VectorF64 operator +( VectorF64 a, VectorF64 b )
{
if ((null == a) ¦¦ (null == b))
{
return (new VectorF64()); // Vector not specified.
}
if ((null == a.components) ¦¦ (null == b.components))
{
return (new VectorF64()); // Vector is empty.
}
if (a.Dimensions() != b.Dimensions())
{
return (new VectorF64()); // Vectors not the same size.
}
int dimensions = a.Dimensions();
VectorF64 result = VectorF64.Zero( dimensions );
for (int i = 0; i < dimensions; i++)
{
result[i] = a[i] + b[i];
}
return (result);
}
public static VectorF64 operator -( VectorF64 a, VectorF64 b )
{
if ((null == a) ¦¦ (null == b))
{
return (new VectorF64()); // Vector not specified.
}
if ((null == a.components) ¦¦ (null == b.components))
{
return (new VectorF64()); // Vector is empty.
}
if (a.Dimensions() != b.Dimensions())
{
return (new VectorF64()); // Vectors not the same size.
}
int dimensions = a.Dimensions();
VectorF64 result = VectorF64.Zero( dimensions );
for (int i = 0; i < dimensions; i++)
{
result[i] = a[i] - b[i];
}
return (result);
}
public static VectorF64 operator -( VectorF64 a )
{
if (null == a)
{
return (new VectorF64()); // Vector not specified.
}
if (null == a.components)
{
return (new VectorF64()); // Vector is empty.
}
int dimensions = a.Dimensions();
VectorF64 result = VectorF64.Zero( dimensions );
for (int i = 0; i < dimensions; i++)
{
result[i] = (-( a[i] ));
}
return (result);
}
public static VectorF64 operator *( double scale, VectorF64 a )
{
if (null == a)
{
return (new VectorF64()); // Vector not specified.
}
if (null == a.components)
{
return (new VectorF64()); // Vector is empty.
}
int dimensions = a.Dimensions();
VectorF64 result = VectorF64.Zero( dimensions );
for (int i = 0; i < dimensions; i++)
{
result[i] = scale * a[i];
}
return (result);
}
public static VectorF64 operator *( VectorF64 a, double scale )
{
if (null == a)
{
return (new VectorF64()); // Vector not specified.
}
if (null == a.components)
{
return (new VectorF64()); // Vector is empty.
}
int dimensions = a.Dimensions();
VectorF64 result = VectorF64.Zero( dimensions );
for (int i = 0; i < dimensions; i++)
{
result[i] = scale * a[i];
}
return (result);
}
// . . .
public static void Test()
{
// . . .
// Examples of vector addition, subtraction, and scaling:
VectorF64 a = new VectorF64( 0.0, 1.0, 2.0, 3.0 );
a.WriteLine(); // ( 0, 1, 2, 3 )
VectorF64 b = new VectorF64( 3.0, 2.0, 1.0, 0.0 );
b.WriteLine(); // ( 3, 2, 1, 0 )
VectorF64 c = new VectorF64();
c.WriteLine(); // ( )
c = a + b;
c.WriteLine(); // ( 3, 3, 3, 3 )
c = a - b;
c.WriteLine(); // ( -3, -1, 1, 3 )
c = -b;
c.WriteLine(); // ( -3, -2, -1, 0 )
c = 3.0 * a;
c.WriteLine(); // ( 0, 3, 6, 9 )
// . . .
}
}
3.8 (d)-wymiarowej podstawie wektorów
Formalna definicja w "oparciu" o wektor miejsce:
Niech (T) być podstawowym typu (np.: liczba rzeczywista, integer, liczba złożonych, Liczby wymierne, itp).
Każdy z podstawowych zmiennych typu jest nazwany "skalarne."
Niech (V) być "(T) typu (d)-wymiarowego wektora przestrzeni kosmicznej."
Jeśli nie zero nosicieli { u1, u2, ..., ud } w (V) są takie, że każdy wektor (v) w (V) mogą być zapisywane jako "liniowa kombinacja" tych wektorów, v = c1*u1 + c2*u2 + ... + cd*ud, gdzie { c1, c2, ..., cd } są scalars typu (T), a następnie (V) jest "kalibrowane" przez nosicieli { u1, u2, ..., ud }.
Każdy zestaw zera nosicieli { u1, u2, ..., ud } że wektor "span" przestrzeń (V) nazwie "na" bazie (V).
Jeden prosty "oparciu" o (d)-wymiarowego wektora przestrzeń jest zestaw (d) odrębne (d)-wymiarowych wektorów, z których każdy ma jeden element jest równy do jednego i wszystkich innych elementów równa zeru.
Takie są wektory podstawie "mat," co oznacza, że są one wzajemnie prostopadłe "(ortogonalne)" i że każda jednostka ma długość wektora.
Każdy taki wektor jednostkowy wektor jest równoległy do jednej z osi (d) koordynować.
Wyrażające arbitralne wektora jako "liniowa kombinacja" tych wektorów jest podstawie bezpośrednich; każdego elementu wektora jest arbitralne, pomnożonej przez odpowiednią podstawę wektora, a produkty te są sumowane do postaci wektorowej arbitralne.
Poniższy kod pokazuje w jaki sposób wektor może być wyrażony jako "liniowa kombinacja" podstawie wektorów.
Poniższy kod definiuje arbitralnie mat zestaw podstawie wektorów.
public class VectorF64
{
// . . .
public static VectorF64 BasisVector( int dimensions, int componentIndex )
{
if (dimensions < 0)
{
// Invalid number of dimensions specified.
return (new VectorF64());
}
VectorF64 basisVector = VectorF64.Zero( dimensions );
if ((componentIndex >= 0) && (componentIndex < dimensions))
{
basisVector[ componentIndex ] = 1.0;
}
return (basisVector);
}
// . . .
public static void Test()
{
// . . .
// The 4 basis vectors of 4-dimensional space,
// each with 4 64-bit floating-point components:
VectorF64 b0 = VectorF64.BasisVector( 4, 0 );
b0.WriteLine(); // ( 1, 0, 0, 0 )
VectorF64 b1 = VectorF64.BasisVector( 4, 1 );
b1.WriteLine(); // ( 0, 1, 0, 0 )
VectorF64 b2 = VectorF64.BasisVector( 4, 2 );
b2.WriteLine(); // ( 0, 0, 1, 0 )
VectorF64 b3 = VectorF64.BasisVector( 4, 3 );
b3.WriteLine(); // ( 0, 0, 0, 1 )
// . . .
}
}
Każdy wektor w (d)-wymiarowej przestrzeni kosmicznej może być wyrażony jako suma produktów podstawie liczby i wektory:
public class VectorF64
{
// . . .
public static void Test()
{
// . . .
// The following two vectors are equivalent:
// A 4-dimensional vector with 64-bit floating-point components:
VectorF64 va = new VectorF64( 0.1, 1.1, 2.2, 3.3 );
va.WriteLine(); // ( 0.1, 1.1, 2.2, 3.3 )
// A 4-dimensional vector formed by scaling the 4 independent
// basis vectors for 4-dimensional space:
VectorF64 vb =
0.1 * VectorF64.BasisVector( 4, 0 )
+ 1.1 * VectorF64.BasisVector( 4, 1 )
+ 2.2 * VectorF64.BasisVector( 4, 2 )
+ 3.3 * VectorF64.BasisVector( 4, 3 );
vb.WriteLine(); // ( 0.1, 1.1, 2.2, 3.3 )
// . . .
}
}
3.9 (d)-dimensional space: odległość między punktami
Niech (P) być (d)-wymiarowy wektor, który reprezentuje punkt w (d)-wymiarowej przestrzeni.
Niech (Q) być (d)-wymiarowy wektor, który reprezentuje punkt w (d)-wymiarowej przestrzeni.
Niech (R) być (d)-wymiarowego wektora, że stanowi zmianę w (d) współrzędne, aby (P) z punktu do punktu (Q); R = (Q - P).
W jednym-wymiarowej przestrzeni, P = ( p0 ), Q = ( q0 ) i R = (Q - P) = ( q0 - p0 ).
Odległość między dwoma punktami jest: Abs( q0 - p0 ).
W dwuwymiarowej przestrzeni, P = ( p0, p1 ), Q = ( q0, q1 ) i R = (Q - P) = ( q0-p0, q1-p1 ).
Interpretacja dwóch prostopadłych wysiedleń jak prostopadle strony prawej trójkąta, przy czym odległość między punktami odpowiada długości hypotenuse z tego trójkąta.
W Pythagorean formuły, (a*a) + (b*b) = (c*c), gdzie (a) i (b) są prostopadle do długości boków trójkąta prawo-i (c) jest długość tego hypotenuse (skew bocznych), mogą być wykorzystane do określenia odległości pomiędzy dwoma punktami: Sqrt( Sq(q0-p0) + Sq(q1-p1) ).
W trójwymiarowej przestrzeni, P = ( p0, p1, p2 ), Q = ( q0, q1, q2 ) i R = (Q - P) = ( q0-p0, q1-p1, q2-p2 ).
Interpretacja przemieszczenie ( q0-p0, q1-p1, 0 ) jak prostopadle strony prawej trójkąta, i przy użyciu wzoru Pythagorean, podaje odległość między punktem (P) i pkt ( q0, q1, p2 ): d01 = Sqrt( Sq(q0-p0) + Sq(q1-p1) ).
W przemieszczenie ( q0-p0, q1-p1, 0 ) jest prostopadła do wysiedlenia ( 0, 0, q2-p2 ), i innego prawo-trójkąt może być utworzona, a Pythagorean formuły mogą być ponownie użyte.
Tak, odległość od punktu do punktu (P) jest (Q) przez: Sqrt( Sq(d01) + Sq(q2-p2) ) = Sqrt( (Sq(q0-p0) + Sq(q1-p1)) + Sq(q2-p2) ) = Sqrt( Sq(q0-p0) + Sq(q1-p1) + Sq(q2-p2) ).
Metoda rozszerzenia formuły odległość od dwuwymiarowej przestrzeni kosmicznej do trójwymiarowej przestrzeni kosmicznej może być stosowana wielokrotnie, aby ostatecznie ustalić odległość formuły (d)-dimensional space: Sqrt( (Sq(q0-p0) + Sq(q1-p1)) + Sq(q2-p2) + ... + Sq(qd-pd) ).
Poniższy kod definiuje funkcję o nazwie "Długość" który oblicza długość z (d)-wymiarowy wektor.
Gdy wektor oznacza przemieszczenie między dwoma punktami w (d)-wymiarowej przestrzeni, długość wektora stanowi odległość pomiędzy tymi dwoma punktami.
public class VectorF64
{
// . . .
public double Length()
{
if (null == this.components)
{
return (0.0); // Vector empty.
}
int dimensions = this.Dimensions();
double sumOfSquares = 0.0;
for (int i = 0; i < dimensions; i++)
{
sumOfSquares += (this[i] * this[i]);
}
double length = Math.Sqrt( sumOfSquares );
return (length);
}
public static double Length( VectorF64 a )
{
if (null == a)
{
return (0.0); // Vector not specified.
}
if (null == a.components)
{
return (0.0); // Vector is empty.
}
return (a.Length());
}
// . . .
public static void Test()
{
// . . .
// Example of vector length:
// A 6-dimensional vector representing a point (p):
VectorF64 p = new VectorF64( 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 );
p.WriteLine(); // ( 0, 1, 2, 3, 4, 5 )
// A 6-dimensional vector representing a point (q):
VectorF64 q = new VectorF64( -5.0, 4.0, -3.0, 2.0, -1.0, 0.0 );
q.WriteLine(); // ( -5, 4, -3, 2, -1, 0 )
// A 6-dimensional vector representing the displacement
// from point (p) to point (q):
VectorF64 r = q - p;
r.WriteLine(); // ( -5, 3, -5, -1, -5, -5 )
// The distance between point (p) and point (q)
// in 6-dimensional space:
double distance = r.Length();
Log.WriteLine( distance ); // 10.4880884817015
// . . .
}
}
3.10 (d)-wymiarowych wektorów: dot produktu
"Kropka produktu" konwertuje dwa (d)-wymiarowych wektorów do szeregu.
Poniższy kod produktu oblicza kropką dwóch wektorów:
public class VectorF64
{
// . . .
public static double Dot( VectorF64 a, VectorF64 b )
{
if ((null == a) ¦¦ (null == b))
{
return (0.0); // Vector not specified.
}
if ((null == a.components) ¦¦ (null == b.components))
{
return (0.0); // Vector is empty.
}
if (a.Dimensions() != b.Dimensions())
{
return (0.0); // Vectors not the same size.
}
int dimensions = a.Dimensions();
double dotProduct = 0.0;
for (int i = 0; i < dimensions; i++)
{
dotProduct += (a[i] * b[i]);
}
return (dotProduct);
}
// . . .
}
Dla każdego wektora, (A), Length(A) = Sqrt(Dot(A,A)).
3.11 (d)-wymiarowych wektorów: definicja "równolegle"
Vectors (A) i (B) są "równolegle," jeżeli wszystkie poniższe warunki są prawdziwe:
(1) A.Length() > 0;
(2) B.Length() > 0;
(3) Abs(Dot(A,B)) = A.Length()*B.Length().
Poniższy kod określa, ile pary wektorów są równoległe (ewentualnie anty-wyrównany).
Floating-point numery mogą się kumulować błędy w ułamkowe części ze względu na ograniczoną precyzją, a zatem komputer powinien zawierać kod niż zero tolerancji porównując pływających punktu numery.
Kod zawiera przykład wartości tolerancji, ale przykład tolerancji wartości może nie być odpowiedni dla niektórych zadań.
public class VectorF64
{
// . . .
public static bool Parallel( VectorF64 a, VectorF64 b )
{
// Smallest normalized float : 1.1754943e-38
// Smallest normalized double: 2.2250738585072020e-308
double nonZeroThreshold = 1.0e-38; // conservative for double
// double: (52+1)-bit mantissa; log10(2^53)=15.95 decimal digits
double fractionalDifferenceThreshold = 1.0e-14; // conservative
if ((null == a) ¦¦ (null == b))
{
return (false); // Vector is not specified.
}
if ((null == a.components) ¦¦ (null == b.components))
{
return (false); // Vector is empty.
}
if (a.Dimensions() != b.Dimensions())
{
return (false); // Vectors not the same size.
}
double lengthA = a.Length();
if (lengthA <= nonZeroThreshold)
{
return (false);
}
double lengthB = b.Length();
if (lengthB <= nonZeroThreshold)
{
return (false);
}
double oneImpliesParallel =
Math.Abs( VectorF64.Dot( a, b ) ) / (lengthA * lengthB);
double absoluteDifferenceFromOne =
Math.Abs( oneImpliesParallel - 1.0 );
if (absoluteDifferenceFromOne <= fractionalDifferenceThreshold)
{
return (true);
}
return (false);
}
// . . .
public static void Test()
{
// . . .
// Example of testing for parallel vectors:
// A 6-dimensional vector:
VectorF64 vf = new VectorF64( 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 );
vf.WriteLine(); // ( 0, 1, 2, 3, 4, 5 )
// A 6-dimensional vector:
VectorF64 vg = new VectorF64( 0.0, -2.0, -4.0, -6.0, -8.0, -10.0 );
vg.WriteLine(); // ( 0, -2, -4, -6, -8, -10 )
// Determine if the specified vectors are parallel
// (or "anti-aligned"):
bool parallel = VectorF64.Parallel( vf, vg );
Log.WriteLine( parallel ); // True
// Add a non-negligible displacement to a component of a vector:
vf[0] += 1.0e-5;
vf.WriteLine(); // ( 1E-05, 1, 2, 3, 4, 5 )
// Determine if the specified vectors are parallel
// (or "anti-aligned"):
parallel = VectorF64.Parallel( vf, vg );
Log.WriteLine( parallel ); // False
// . . .
}
}
3.12 (d)-wymiarowych wektorów: definicja "prostopadle"
Vectors (A) i (B) są "prostopadłe," jeżeli wszystkie poniższe warunki są prawdziwe:
(1) A.Length() > 0;
(2) B.Length() > 0;
(3) Abs(Dot(A,B)) = 0.
Poniższy kod określa, ile pary wektorów są prostopadłe. Floating-point numery mogą się kumulować błędy w ułamkowe części ze względu na ograniczoną precyzją, a zatem komputer powinien zawierać kod niż zero tolerancji porównując pływających punktu numery.
Kod zawiera przykład wartości tolerancji, ale przykład tolerancji wartości może nie być odpowiedni dla niektórych zadań.
public class VectorF64
{
// . . .
public static bool Perpendicular( VectorF64 a, VectorF64 b )
{
// Smallest normalized float : 1.1754943e-38
// Smallest normalized double: 2.2250738585072020e-308
double nonZeroThreshold = 1.0e-38; // conservative for double
// double: (52+1)-bit mantissa; log10(2^53)=15.95 decimal digits
double fractionalDifferenceThreshold = 1.0e-14; // conservative
if ((null == a) ¦¦ (null == b))
{
return (false); // Vector is not specified.
}
if ((null == a.components) ¦¦ (null == b.components))
{
return (false); // Vector is empty.
}
if (a.Dimensions() != b.Dimensions())
{
return (false); // Vectors not the same size.
}
double lengthA = a.Length();
if (lengthA <= nonZeroThreshold)
{
return (false);
}
double lengthB = b.Length();
if (lengthB <= nonZeroThreshold)
{
return (false);
}
double zeroImpliesPerpendicular =
Math.Abs( VectorF64.Dot( a, b ) ) / (lengthA * lengthB);
double absoluteDifferenceFromZero =
Math.Abs( zeroImpliesPerpendicular );
if (absoluteDifferenceFromZero <= fractionalDifferenceThreshold)
{
return (true);
}
return (false);
}
// . . .
public static void Test()
{
// . . .
// Example of testing for perpendicular vectors:
// A 6-dimensional vector:
VectorF64 vf2 = new VectorF64( 0.0, 1.0, 2.0, 0.0, 4.0, 5.0 );
vf2.WriteLine(); // ( 0, 1, 2, 0, 4, 5 )
// A 6-dimensional vector:
VectorF64 vg2 = new VectorF64( 10.0, 0.0, 0.0, -5.0, 0.0, 0.0 );
vg2.WriteLine(); // ( 10, 0, 0, -5, 0, 0 )
// Determine if the specified vectors are perpendicular
bool perpendicular = VectorF64.Perpendicular( vf2, vg2 );
Log.WriteLine( perpendicular ); // True
// Add a non-negligible displacement to a component of a vector:
vf2[0] += 1.0e-13;
vf2.WriteLine(); // ( 1E-13, 1, 2, 0, 4, 5 )
// Determine if the specified vectors are perpendicular
perpendicular = VectorF64.Perpendicular( vf2, vg2 );
Log.WriteLine( perpendicular ); // False
// . . .
}
}
3.13 Macierze
"matrycy:" zbierania zmiennych w taki sposób, że każda zmienna ma unikalną kombinację "wiersza" nazwę i nazwę "kolumny."
"wpis:" zmienna w matrycy.
Integer wartości mogą być używane jako nazwy "wiersza" i "kolumny" nazw zmiennych w macierzy.
Na przykład, jeżeli posiada matrycę (totalRows) wiersze i kolumny (totalColumns), wówczas całkowita wartość { 0, 1, ..., (totalRows-1) } może być przypisany do nazwy wierszy, a całkowita wartość { 0, 1, ..., (totalColumns-1) } może być przypisany do nazwy kolumny.
Tak, zmienne w macierzy może być określone poprzez określenie pary liczb całkowitych, ( row, column ), wskazując na połączenie wiersza i kolumny wskaźniki odnoszące się do konkretnych zmiennych.
Rozmiar macierzy jest określone jako "(totalRows) * (totalColumns)" (lub "(totalRows) przez (totalColumns))."
Tę kolejność wymiarów jest taka sama jak kolejność wymiarów wykorzystywane do określenia pozycji w matrycy "(( row, column ))."
[Konwencja ta jest trochę niefortunne, ponieważ dla wielu zastosowań dwuwymiarowych (przykłady: zdjęcia, wykresy, itp) jest zwykle konwencji, aby określić wymiary jak "width * height" i koordynuje jak "( horizontal, vertical )" (lub "( x, y ))."
To jest naprzeciwko rzędu wymiary i współrzędne używane do opisywania macierzy i ich wpisy. ]
A matryca z (totalRows) równa (totalColumns) nazwie "kwadrat;" inaczej, matrycy nazwie "prostokątne."
Macierz może być traktowane jako zawierające zestaw "wierszy wektorów," gdzie zmienne w każdym wierszu są interpretowane jako należące do wektora.
Macierz może być również traktowane jako zawierające zestaw "kolumn wektorów," gdzie zmienne w każdej kolumnie są interpretowane jako należące do wektora.
Matryce mogą reprezentują szeroki wachlarz relacji matematycznych.
Znaczenie macierzy i operacje, które mogą być odpowiednie do przetwarzania wpisów w matrycy, zależy od kontekstu.
Jednakże, istnieją podstawowe zasady matrycy arytmetycznych, które są istotne dla wielu kontekstach, a te podstawowe zasady zostaną określone w późniejszej części.
Tablica i (totalColumns) wartości są wystarczające do reprezentowania macierzy.
Na tablicy mogą mieć (totalRows * totalColumns) zmiennych, a wpis w ( row, column ) może odpowiadać na tablicy zmienna w indeksie ((totalColumns * row) + column).
Poniższy kod definiuje macierz, z 64-bitowe obliczenia zmiennoprzecinkowe pkt wpisów.
Tablica i (totalColumns) wartości są wystarczające do reprezentowania macierzy.
Kod poniżej ma tablicy i (totalColumns) wartości zawartych w klasie, tylko dla wygody.
Poniższy kod nie jest efektywny.
A struktury (np.: "struct", wartość typu) reprezentujących matryc poszczególnych stałych wymiarach (przykłady: 2*2, 3*3 lub 4*4) będzie prawdopodobnie znacznie bardziej wydajne niż ogólne (totalRows * totalColumns) klasy podana tut