Last active
December 1, 2023 09:56
-
-
Save pandanote-info/f529f0c7a5d653ae568b4f67dc71792b to your computer and use it in GitHub Desktop.
Scalaで四元数を扱うためのオブジェクト(Quaternionオブジェクト)及びクラス(Quaternionクラス)の実装例。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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