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'
都允许对八元数进行计算。