Linjär algebra
Colin Fahey
1. Mjukvara
LinearAlgebra.zip
Linjär algebra källkod (C#)
19910 bytes
MD5: 11d8c8035cac30ba543e5e0b72ee9767
2. Inledning
Denna artikel beskriver vektorer och matriser i (d)-dimensionell rymd.
3. (d)-dimensionell rymd: Attribut
3.1 Array
”array:” En samling av variabler sådana att varje variabel har ett unikt namn, så att namnen kan komma att tilldelas en beställning.
Integer värden kan användas som namn på variabler i en matris.
Till exempel om en rad innehåller (d) variabler, sedan integer värden { 0, 1, 2, ..., (d-1) } kan namnen tilldelas variabler i matrisen.
3.2 (d)-dimensionell vektor
”(d)-dimensionell vektor:” Massor av (d) variabler.
”vektorns komponent:” En variabel i en vektor.
3.3 (d)-dimensional vector space
”endimensionella rymden:” En komplett uppsättning värden som kan lagras i en variabel.
”(d)-dimensionell rymd:” Den fullständiga uppsättningen av kombinationer av värden som kan sparas genom en rad (d) variabler.
Den formella definitionen av en ”vektor rymden:”
Låt (T) vara en grundläggande typ (exempel: reella tal, heltal, komplexa antal, rationell antal etc).
Varje variabel av en grundläggande typ heter en ”skalär.”
En ”(T)-typ (d)-dimensional vector space” är den uppsättning (S) av (d)-dimensionell vektorer med två operationer, vektor Dessutom (+) och skalär multiplikation (*), uppfyller de villkor nedan:
(1) Om (v) och (w) är två vektorer i (S), sedan (v + w) är också en vektor i (S);
(2) Om (u), (v) och (w) är alla tre vektorer i (S), sedan (u + v) + w = u + (v + w);
[tillsats kommutativitet]
(3) Om (v) och (w) är två vektorer i (S), sedan (v + w) = (w + v);
[tillsats associativitet]
(4) Det finns ett ”noll vektor,” (0) i (S), så att varje vektor (v) i (S), (v + (0)) = v;
[Additive identity]
(5) Om (c) är en skalär av typ (T) och (v) är varje vektor i (S), då produkten (c * v) är en vektor i (S);
(6) Om (a), (b) och (c) är något scalars av typ (T) och (v) och (w) är alla vektorer i (S), sedan (a + b) * v = a*v + b*v och c*(v + w) = c*v + c*w;
[multiplicative distributivity]
(7) Om (a) och (b) är något scalars av typ (T) och (v) är varje vektor i (S), sedan (a*b)*v = a*(b*v);
(8) Om ”1” är en skalär av typ (T) sådan att (1*1)=1 och (v) är varje vektor i (S), sedan (1*v) = v;
(9) För varje vektor (v) i (S), vektorn (-1)*v = -v uppfyller v + (-v) = (0);
[additiv invers]
3.4 (d)-dimensionell vektor-kod
Koden nedan visar hur en (d)-dimensionell vektor, med 64-bitars floating-point komponenter, kan genomföras.
En matris är tillräcklig för att representera en vektor.
Koden nedan har en matris som återfinns i en klass, bara för enkelhetens skull.
Koden är inte avsedd att vara effektiv.
En struktur (exempel: ”struct” ett värde typ) som företräder vektorer för ett fast antal dimensioner (exempel: 3 eller 4) kommer sannolikt att vara mycket effektivare än de allmänna (d)-dimensionell vektor klass visas här.
Även om koden under definierar en vektor med floating-point komponenter, detta dokument också använder sig av vektorer med heltal komponenter.
Koden nedan kan lätt ändras för att genomföra vektorer med heltal komponenter.
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)-dimensional noll vektor:” en vektor med alla (d) komponenter lika med noll.
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)-dimensionell rymd: poäng
”(d)-dimensionell rymd punkt:” Massor av (d) variabler med särskilda värden ”(samordna värden).”
”(d)-dimensionell rymd ursprung:” Massor av (d) variabler med alla värden lika med noll.
3.6 (d)-dimensionell vektorer: icke-relativa och relativa
En (d)-dimensionell vektor som är ”icke-släkting” är en (d)-dimensionell vektor som direkt representerar en status eller konfiguration.
En (d)-dimensionell vektor som är ”relativ” är en (d)-dimensionell vektor som innebär ändringar i en uppsättning av komponenter.
En relativ vektor kan utgöra skillnaden mellan två icke-relativa vektorer.
Eftersom en relativ vektor, avgöra om en icke-relativa status eller konfiguration med hjälp av det relativa vektorn kräver att kombinera det relativa vektor med en icke-relativa vektor.
Icke relativa vektorer och relativa vektorer är båda vektorer.
Oavsett om en viss vektor är icke-anhörig eller släkting måste anges när vektorn är definierad.
Om en (d)-dimensionell vektor tolkas som varande icke-förhållande, sedan (d)-dimensionell vektor kan representera en punkt i (d)-dimensionell rymd.
3.7 (d)-dimensionell vektor Dessutom subtraktion och trappa
Vector Dessutom subtraktion och trappa:
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)-dimensional grund vektorer
Den formella definitionen av en ”utgångspunkt” i en vektor rymden:
Låt (T) vara en grundläggande typ (exempel: reella tal, heltal, komplexa antal, rationell antal etc).
Varje variabel av en grundläggande typ heter en ”skalär.”
Låt (V) vara en ”(T)-typ (d)-dimensional vector space.”
Om den icke-noll vektorer { u1, u2, ..., ud } i (V) är sådana att varje vektor (v) i (V) kan skrivas som en ”linjär kombination” av dessa vektorer, v = c1*u1 + c2*u2 + ... + cd*ud, där { c1, c2, ..., cd } är scalars av typ (T), sedan (V) är ”spännas” av vektorer { u1, u2, ..., ud }.
En rad icke-noll vektorer { u1, u2, ..., ud } att ”span” vector space (V) heter ”basis” av (V).
En enkel ”grund” av en (d)-dimensional vector space är den uppsättning av (d) distinkt (d)-dimensionella vektorer, vardera med en del som motsvarar en och alla andra komponenter lika med noll.
Sådana grund vektorer är ”orthonormal,” vilket innebär att de är ömsesidigt vinkelräta ”(rätvinkliga)” och att varje vektor har enheten längd.
Varje sådan vektor är en vektor parallell till ett av de (d) samordna axlarna.
Att uttrycka en godtycklig vektor som en ”linjär kombination” av dessa grund vektorer är direkt, varje del av godtycklig vektor multipliceras med motsvarande grund vektor, och dessa produkter läggs samman för att bilda den godtyckliga vektor.
Koden nedan visar hur en vektor kan uttryckas som en ”linjär kombination” av grund vektorer.
Koden nedan godtyckligt definierar en orthonormal uppsättning grund vektorer.
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 )
// . . .
}
}
Varje vektor i (d)-dimensionell rymd kan uttryckas som en summa av produkter av siffror och grund vektorer:
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)-dimensionell rymd: avstånd mellan punkter
Låt (P) vara en (d)-dimensionell vektor som representerar en punkt i (d)-dimensionell rymd.
Låt (Q) vara en (d)-dimensionell vektor som representerar en punkt i (d)-dimensionell rymd.
Låt (R) vara en (d)-dimensionell vektor som motsvarar förändringen i (d) koordinater för att ta sig från punkt (P) till punkt (Q); R = (Q - P).
I en-dimensionell rymd, P = ( p0 ), Q = ( q0 ) och R = (Q - P) = ( q0 - p0 ).
Avståndet mellan två punkter är: Abs( q0 - p0 ).
I två-dimensionell rymd, P = ( p0, p1 ), Q = ( q0, q1 ) och R = (Q - P) = ( q0-p0, q1-p1 ).
Tolkning av två vinkelräta förskjutningar som vinkelrätt sidor av en höger-triangeln är avståndet mellan de punkter som motsvarar längden på hypotenusan i den triangel.
Den Pythagorean formel, (a*a) + (b*b) = (c*c), där (a) och (b) är de längder av vinkelräta sidor av en höger-triangeln, och (c) är längden på hypotenusan (snedvrida sidan), kan användas för att bestämma avståndet mellan två punkter: Sqrt( Sq(q0-p0) + Sq(q1-p1) ).
I tredimensionella rymden, P = ( p0, p1, p2 ), Q = ( q0, q1, q2 ) och R = (Q - P) = ( q0-p0, q1-p1, q2-p2 ).
Tolkning av displacement ( q0-p0, q1-p1, 0 ) som vinkelrätt sidor av en höger-triangeln, och med hjälp av Pythagorean formel, får avståndet mellan punkt (P) och den punkt ( q0, q1, p2 ): d01 = Sqrt( Sq(q0-p0) + Sq(q1-p1) ).
Förskjutningen ( q0-p0, q1-p1, 0 ) är vinkelrät mot förskjutning ( 0, 0, q2-p2 ) och annan rättighet-triangeln kan bildas, och Pythagorean formel kan användas igen.
Alltså, avståndet från punkt (P) till punkt (Q) ges av: 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) ).
Den metod för att utvidga avståndet formel från tvådimensionell yta som tredimensionella rymden kan appliceras upprepade gånger för att så småningom bestämma avståndet formel för (d)-dimensionell rymd: Sqrt( (Sq(q0-p0) + Sq(q1-p1)) + Sq(q2-p2) + ... + Sq(qd-pd) ).
Koden nedan definierar en funktion som heter ”Längd” som beräknar längden av en (d)-dimensionell vektor.
När en vektor representerar förskjutning mellan två punkter i (d)-dimensionell rymd, längden av vektorn motsvarar avståndet mellan dessa två punkter.
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)-dimensionell vektorer: dot product
The ”dot product” konverterar två (d)-dimensionell vektorer för ett antal.
Koden nedan beräknar en prick produkt av två vektorer:
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);
}
// . . .
}
För varje vektor, (A), Length(A) = Sqrt(Dot(A,A)).
3.11 (d)-dimensionell vektorer: definitionen av ”parallella”
Vectors (A) och (B) är ”parallella” om samtliga följande villkor gäller:
(1) A.Length() > 0;
(2) B.Length() > 0;
(3) Abs(Dot(A,B)) = A.Length()*B.Length().
Koden nedan avgör om ett par av vektorer är parallella (eventuellt anti-anpassade).
Floating-point nummer kan ansamlas felaktigheter i decimaldelen på grund av de begränsade precision, och därför datakod bör omfatta icke-noll avvikelser vid en jämförelse floating-point nummer.
Koden omfattar exempel tolerans värden, men det exempel tolerans värden kanske inte är lämpliga för vissa uppgifter.
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)-dimensionell vektorer: Definition av ”vinkelrät”
Vectors (A) och (B) är ”vinkelrät” om samtliga följande villkor gäller:
(1) A.Length() > 0;
(2) B.Length() > 0;
(3) Abs(Dot(A,B)) = 0.
Koden nedan avgör om ett par av vektorer är vinkelräta. Floating-point nummer kan ansamlas felaktigheter i decimaldelen på grund av de begränsade precision, och därför datakod bör omfatta icke-noll avvikelser vid en jämförelse floating-point nummer.
Koden omfattar exempel tolerans värden, men det exempel tolerans värden kanske inte är lämpliga för vissa uppgifter.
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 Matriser
”matris:” En samling av variabler sådana att varje variabel har en unik kombination av en ”rad” namn och en ”kolumn” namn.
”:” En variabel i en matris.
Integer värden kan användas som ”raden” namn och ”kolumn” namn för variabler i en matris.
Till exempel om en matris har (totalRows) rader och (totalColumns) kolumner, sedan integer värden { 0, 1, ..., (totalRows-1) } kan namnen tilldelas rader, och integer värden { 0, 1, ..., (totalColumns-1) } kan namnen tilldelas kolumner.
Således är en variabler i en matris kan anges genom att ange ett par av heltal, ( row, column ), som anger den kombination av vertikala och horisontella index i förhållande till de rörliga.
Storleken på en matris anges som ”(totalRows) * (totalColumns)” (eller ”(totalRows) av (totalColumns)).”
Denna ordning dimensioner är densamma som den ordning mått som används för att specificera poster i matrisen ”(( row, column )).”
[Denna konvention är lite olyckligt, eftersom många tvådimensionella användningsområden (exempel: bilder, diagram mm) den vanliga konventionen är att ange dimensioner som ”width * height” och koordinater som ”( horizontal, vertical )” (eller ”( x, y )).”
Detta är motsatsen till den ordning som mått och koordinater som används för att beskriva matriser och deras poster. ]
En matris med (totalRows) lika med (totalColumns) heter ”torget,” annars matrisen heter ”rektangulära.”
En matris kan ses som innehåller en uppsättning ”raden vektorer,” där variabler i varje rad skall tolkas som hör till en vektor.
En matris kan också betraktas som innehåller en rad ”kolumn vektorer,” där variabler i varje kolumn är tolkas som hör till en vektor.
Matriser kan representera en mängd olika matematiska relationer.
Innebörden av en matris, och de insatser som kan vara lämpliga för behandling av poster i en matris, beroende på sammanhanget.
Men det finns grundläggande regler för matrix arithmetic som är relevanta för många sammanhang, och dessa grundläggande regler kommer att fastställas i ett senare avsnitt.
En matris och en (totalColumns) värde är tillräckliga för att representera en matris.
Den array kan ha (totalRows * totalColumns) variabler, och inträde på ( row, column ) kan motsvara den array variabel i indexet ((totalColumns * row) + column).
Koden nedan visar en matris med 64-bitars floating-point-poster.
En matris och en (totalColumns) värde är tillräckliga för att representera en matris.
Koden nedan har en matris och en (totalColumns) värde i en klass, bara för enkelhetens skull.
Koden nedan är inte avsedd att vara effektiv.
En struktur (exempel: ”struct” ett värde typ) representerar matriser av särskilt fasta mått (exempel: 2*2, 3*3 eller 4*4) kommer sannolikt att vara mycket effektivare än de allmänna (totalRows * totalColumns) klass visas här.
Även om koden under definierar en matris med floating-point-poster, den här artikeln också använder sig av matriser med heltal poster.
Koden nedan kan lätt ändras för att genomföra matriser med heltal poster.