Python 和 Ruby 中的數學/Ruby 中的四元數
正如在前一章中所見,複數是一個包含 2 個實數(由 Ruby 稱為 real 和 imag)的物件。 這是凱萊-迪克森結構 的複數。 以非常類似的方式,四元數 可以被認為是由 2 個複數組成。
在以下所有內容中,cmath 將被使用,因為它會自動處理分數。 這章在某種程度上與前面的章節不同,因為它展示瞭如何在 Ruby 中建立全新的物件,而不是如何使用現有的物件。
四元數的定義是在一個名為 Quaternion 的類 中找到其庇護所
class Quaternion
end
def initialize(a,b)
@a,@b = a,b
end
從現在起,a 和 b(將是複數)將是四元數的 2 個屬性
由於定義四元數的兩個數字是複數,因此將它們稱為 real 和 imaginary 部分是不合適的。 此外,稍後在八元數中將需要另一個階段。 因此,選擇了最短的名稱,它們將被稱為四元數的 a 及其 b。
def a
@a
end
def b
@b
end
從現在起,可以使用 q.a 和 q.b 訪問四元數 q 的 a 和 b 部分。
為了便於使用 puts(q) 顯示四元數 q,有必要為其重新定義一個方法 to_s(多型性 的一個例子)。 有幾種選擇,但這種選擇效果還不錯
def to_s
'('+a.real.to_s+')+('+a.imag.to_s+')i+('+b.real.to_s+')j+('+b.imag.to_s+')k'
end
為了大聲朗讀,最好從右到左讀。 例如,a.real 表示 a 的實部,q.a.real 表示 q 的 a 部分的實部。
四元數的絕對值是一個(正)實數。
def abs
Math.hypot(@a.abs,@b.abs)
end
四元數的共軛是另一個四元數,具有相同的模。
def conj
Quaternion.new(@a.conj,-@b)
end
要新增兩個四元數,只需將它們的 a 相加,並將它們的 b 相加
def +(q)
Quaternion.new(@a+q.a,@b+q.b)
end
- 符號的使用是多型性的另一個例子,它允許用更簡單的形式編寫減法。
def -(q)
Quaternion.new(@a-q.a,@b-q.b)
end
四元數的乘法 更加複雜 (!)
def *(q)
Quaternion.new(@a*q.a-@b*q.b.conj,@a*q.b+@b*q.a.conj)
end
這種乘法不是交換的,可以從以下示例中檢查出來
p=Quaternion.new(Complex(2,1),Complex(3,4))
q=Quaternion.new(Complex(2,5),Complex(-3,-5))
puts(p*q)
puts(q*p)
除法可以定義為:
def /(q)
d=q.abs**2
Quaternion.new((@a*q.a.conj+@b*q.b.conj)/d,(-@a*q.b+@b*q.a)/d)
end
因為它們具有相同的模數,所以四元數與其共軛的商的模數為1。
p=Quaternion.new(Complex(2,1),Complex(3,4))
puts((p/p.conj).abs)
最後一個例子說明了,或,這是 的一個四平方和分解。
完整的類在這裡。
require 'cmath'
class Quaternion
def initialize(a,b)
@a,@b = a,b
end
def a
@a
end
def b
@b
end
def to_s
'('+a.real.to_s+')+('+a.imag.to_s+')i+('+b.real.to_s+')j+('+b.imag.to_s+')k'
end
def +(q)
Quaternion.new(@a+q.a,@b+q.b)
end
def -(q)
Quaternion.new(@a-q.a,@b-q.b)
end
def *(q)
Quaternion.new(@a*q.a-@b*q.b.conj,@a*q.b+@b*q.a.conj)
end
def abs
Math.hypot(@a.abs,@b.abs)
end
def conj
Quaternion.new(@a.conj,-@b)
end
def /(q)
d=q.abs**2
Quaternion.new((@a*q.a.conj+@b*q.b.conj)/d,(-@a*q.b+@b*q.a.conj)/d)
end
end
如果此內容儲存在名為 quaternion.rb 的文字檔案中,在執行 require 'quaternion' 後,就可以對四元數進行計算。
關於凱萊-迪克森構造的一個有趣的事實是,它可以被推廣,例如用於八元數。
所有以下方法都將包含在一個名為 Octonion 的類中。
class Octonion
def initialize(a,b)
@a,@b = a,b
end
def a
@a
end
def b
@b
end
此時,與四元數物件沒有太大區別。只是對於八元數,a 和 b 將是四元數,而不是複數。當 a 和 b 被例項化時,Ruby 將知道它。
八元數的 to_s 方法(將其轉換為字串物件以便顯示)與四元數等價,只是現在有 8 個實數要顯示。
def to_s
'('+a.a.real.to_s+')+('+a.a.imag.to_s+')i+('+a.b.real.to_s+')j+('+a.b.imag.to_s+')k+('+b.a.real.to_s+')l+('+b.a.imag.to_s+')li+('+b.b.real.to_s+')lj+('+b.b.imag.to_s+')lk'
end
這些數字中的第一個是第一個四元數的 a 部分的實部,也就是八元數的 a!訪問 八元數的 a 部分的 a 部分的實部,需要遍歷深度為 3 的二叉樹。
由於凱萊和迪克森,八元數計算所需的函式與四元數類似。
與四元數相同。
def abs
Math.hypot(@a.abs,@b.abs)
end
def conj
Octonion.new(@a.conj,Quaternion.new(0,0)-@b)
end
就像四元數一樣,只需要分別新增 a 和 b(只是現在 a 和 b 部分是四元數)。
def +(o)
Octonion.new(@a+o.a,@b+o.b)
end
def -(o)
Octonion.new(@a-o.a,@b-o.b)
end
def *(o)
Octonion.new(@a*o.a-o.b*@b.conj,@a.conj*o.b+o.a*@b)
end
這種乘法仍然不是可交換的,而且甚至也不是結合的!
m=Octonion.new(p,q)
n=Octonion.new(q,p)
o=Octonion.new(p,p)
puts((m*n)*o)
puts(m*(n*o))
def /(o)
d=1/o.abs**2
Octonion.new((@a*o.a.conj+o.b*@b.conj)*Quaternion.new(d,0),(Quaternion.new(0,0)-@a.conj*o.b+o.a.conj*@b)*Quaternion.new(d,0))
end
這裡再次,八元數與其共軛的商的模數為1。
puts(m/m.conj)
puts((m/m.conj).abs)
該檔案的大小與四元數檔案相差無幾。
class Octonion
def initialize(a,b)
@a,@b = a,b
end
def a
@a
end
def b
@b
end
def to_s
'('+a.a.real.to_s+')+('+a.a.imag.to_s+')i+('+a.b.real.to_s+')j+('+a.b.imag.to_s+')k+('+b.a.real.to_s+')l+('+b.a.imag.to_s+')li+('+b.b.real.to_s+')lj+('+b.b.imag.to_s+')lk'
end
def +(o)
Octonion.new(@a+o.a,@b+o.b)
end
def -(o)
Octonion.new(@a-o.a,@b-o.b)
end
def *(o)
Octonion.new(@a*o.a-o.b*@b.conj,@a.conj*o.b+o.a*@b)
end
def abs
Math.hypot(@a.abs,@b.abs)
end
def conj
Octonion.new(@a.conj,Quaternion.new(0,0)-@b)
end
def /(o)
d=1/o.abs**2
Octonion.new((@a*o.a.conj+o.b*@b.conj)*Quaternion.new(d,0),(Quaternion.new(0,0)-@a.conj*o.b+o.a.conj*@b)*Quaternion.new(d,0))
end
end
將其儲存為 octonions.rb,任何以以下內容開頭的指令碼
require 'octonions'
都允許對八元數進行計算。