Skip to content

Instantly share code, notes, and snippets.

@pandanote-info
Last active December 1, 2023 09:56
Show Gist options
  • Save pandanote-info/f529f0c7a5d653ae568b4f67dc71792b to your computer and use it in GitHub Desktop.
Save pandanote-info/f529f0c7a5d653ae568b4f67dc71792b to your computer and use it in GitHub Desktop.
Scalaで四元数を扱うためのオブジェクト(Quaternionオブジェクト)及びクラス(Quaternionクラス)の実装例。
package info.pandanote.test
import scala.reflect.ClassTag
import scala.math._
// A class to represent and to handle a quaternion.
// 四元数を扱うためのクラスを書いてみました。
case class Quaternion(real: Double, _i: Double, _j: Double, _k: Double) {
override def toString(): String = real + (if (_i == 0.0) "" else ((if (_i>0.0)"+"else"-")+(if (_i>0.0)_i else -_i) + "i")) + (if (_j == 0.0) "" else ((if (_j>0.0)"+"else"-")+(if (_j>0.0)_j else -_j) + "j")) + (if (_k == 0.0) "" else ((if (_k>0.0)"+"else"-")+(if (_k>0.0)_k else -_k) + "k"))
def re() = real
def i() = _i
def j() = _j
def k() = _k
def +(that: Quaternion) = Quaternion(this.real+that.real,this._i+that._i,this._j+that._j,this._k+that._k)
def +(that: Int) = Quaternion(this.real+that,this._i,this._j,this._k)
def +(that: Long) = Quaternion(this.real+that,this._i,this._j,this._k)
def +(that: Float) = Quaternion(this.real+that,this._i,this._j,this._k)
def +(that: Double) = Quaternion(this.real+that,this._i,this._j,this._k)
def -(that: Quaternion) = Quaternion(this.real-that.real,this._i-that._i,this._j-that._j,this._k-that._k)
def -(that: Int) = Quaternion(this.real-that,this._i,this._j,this._k)
def -(that: Long) = Quaternion(this.real-that,this._i,this._j,this._k)
def -(that: Float) = Quaternion(this.real-that,this._i,this._j,this._k)
def -(that: Double) = Quaternion(this.real-that,this._i,this._j,this._k)
def *(that: Quaternion)
= Quaternion(this.real*that.real-this._i*that._i-this._j*that._j-this._k*that._k,
this.real*that._i+this._i*that.real+this._j*that._k-this._k*that._j,
this.real*that._j-this._i*that._k+this._j*that.real+this._k*that._i,
this.real*that._k+this._i*that._j-this._j*that._i+this._k*that.real)
def *(that: Int) = Quaternion(this.real*that,this._i*that,this._j*that,this._k*that)
def *(that: Long) = Quaternion(this.real*that,this._i*that,this._j*that,this._k*that)
def *(that: Float) = Quaternion(this.real*that,this._i*that,this._j*that,this._k*that)
def *(that: Double) = Quaternion(this.real*that,this._i*that,this._j*that,this._k*that)
def unary_- = Quaternion(-this.real,-this._i,-this._j,-this._k)
def abs = math.sqrt(this.real*this.real+this._i*this._i+this._j*this._j+this._k*this._k)
def conjugate = Quaternion(this.real,-this._i,-this._j,-this._k)
// 除算: 四元数を除数とする除算は、逆数を右からかける演算として定義します。
def /(that: Int) = Quaternion(this.real/that,this._i/that,this._j/that,this._k/that)
def /(that: Long) = Quaternion(this.real/that,this._i/that,this._j/that,this._k/that)
def /(that: Float) = Quaternion(this.real/that,this._i/that,this._j/that,this._k/that)
def /(that: Double) = Quaternion(this.real/that,this._i/that,this._j/that,this._k/that)
def /(that: Quaternion) = {
val xnorm = that.real*that.real+that._i*that._i+that._j*that._j+that._k*that._k
val q = this*that.conjugate
Quaternion(q.real/xnorm,q._i/xnorm,q._j/xnorm,q._k/xnorm)
}
// 四元数の剰余計算というものが定義されているのかどうかわかりませんが、書いてみました。
// 複素数と同様の考え方で定義しています。
def %(that: Quaternion) = {
val div = this./(that)
this - Quaternion(Math.round(div.real),Math.round(div.i),Math.round(div.j),Math.round(div.k))*that
}
def %(that: Int): Quaternion = this.%(Quaternion(that, 0, 0, 0))
def %(that: Long): Quaternion = %(Quaternion(that, 0, 0, 0))
def %(that: Float): Quaternion = %(Quaternion(that, 0, 0, 0))
def %(that: Double): Quaternion = %(Quaternion(that, 0, 0, 0))
def exp = {
val expreal = math.exp(real)
val vlen = math.sqrt(_i*_i+_j*_j+_k*_k)
Quaternion(math.cos(vlen),math.sin(vlen)*_i/vlen,math.sin(vlen)*_j/vlen,math.sin(vlen)*_k/vlen)*expreal
}
def log = {
val logimag = math.acos(real/abs)/math.sqrt(_i*_i+_j*_j+_k*_k)
Quaternion(math.log(abs),_i*logimag,_j*logimag,_k*logimag)
}
def pow(that: Int): Quaternion = pow(Quaternion(that,0,0,0))
def pow(that: Double): Quaternion = pow(Quaternion(that,0,0,0))
def pow(that: Quaternion): Quaternion = {
if (that == Quaternion.zero) Quaternion.one
else if (this == Quaternion.zero) {
// 実数成分は正である場合に限り0を返す。
if (that.real < 0.0 || that._i != 0.0 || that._j != 0.0 || that._k != 0.0) Quaternion.nan
else Quaternion.zero
} else {
Quaternion.exp(log*that)
}
}
// こんなのも定義してみます。
def **(that: Quaternion): Quaternion = pow(that)
def **(that: Double): Quaternion = pow(that)
def **(that: Int): Quaternion = pow(that)
override def equals(that: Any) = that match {
case that: Quaternion => this.real == that.real && this._i == that._i && this._j == that._j && this._k == that._k
case real: Double => this.real == real && this._i == 0 && this._j == 0 && this._k == 0
case real: Int => this.real == real && this._i == 0 && this._j == 0 && this._k == 0
case real: Short => this.real == real && this._i == 0 && this._j == 0 && this._k == 0
case real: Long => this.real == real && this._i == 0 && this._j == 0 && this._k == 0
case real: Float => this.real == real && this._i == 0 && this._j == 0 && this._k == 0
case _ => false
}
// 試しにこんな演算子を定義してみます。
def <>(that: Quaternion) =
(this.real != that.real || this._i != that._i || this._j != that._j || this._k != that._k)
override def hashCode() = real.## ^ _i.## ^ _j.## ^ _k.##
}
object Quaternion {
outer =>
val one = new Quaternion(1,0,0,0)
val zero = new Quaternion(0,0,0,0)
val nan = new Quaternion(Double.NaN,Double.NaN,Double.NaN,Double.NaN)
// Javaでいうところのstaticなメソッドみたいなものです。
def exp(that: Quaternion): Quaternion = that.exp
def log(that: Quaternion): Quaternion = that.log
// 実数に四元数を作用させる演算が定義されていなかったので、追加しました。
// 試行錯誤の末、以下の一行になりました…
implicit def fromDouble(d: Double) = new Quaternion(d,0,0,0)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment