quaternion_c2 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 11a23c8bee71f2eac9cdd28569ddbd060e1c78d6
4
+ data.tar.gz: 2da47444cd5b3c7f50da7f9cb0dfc281dcd187a1
5
+ SHA512:
6
+ metadata.gz: 3504d452e7841683a890fb01c8ca3a82ce44c9c334aa3309b50329dd17415a99d021c6d2b56cf0358a5c04d9d09b1aaf44508d030cc75072a32626d4c1a8d1eb
7
+ data.tar.gz: 6348e89acb1f9a31923c03d9ea1fac21d10d2a849d55c198fd757021ad35243dce10c411502f4ea4b6e622d331e4e66dfd4b014e46c2774d290320a77507265b
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.0.0
5
+ before_install: gem install bundler -v 1.14.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in quaternion_c2.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Masahiro Nomoto
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # Quaternion
2
+
3
+ ## Installation
4
+
5
+ Add this line to your application's Gemfile:
6
+
7
+ ```ruby
8
+ gem 'quaternion_c2'
9
+ ```
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ ## Usage
16
+
17
+ `Quaternion` is similar to a built-in class `Complex`.
18
+
19
+ There are several methods to create a quaternion. `Kernel.#Quaternion` accepts many patterns of arguments.
20
+
21
+ ```ruby
22
+ require 'quaternion_c2'
23
+
24
+ q1 = Quaternion.rect(Complex(1, 2), Complex(3, 4)) #=> (1+2i+3j+4k)
25
+ q2 = Quaternion.hrect(1, -2, Rational(-3, 4), 0.56) #=> (1-2i-(3/4)*j+0.56k)
26
+ vector = Vector[1, 1, 1].normalize
27
+ q3 = Quaternion.polar(1, Math::PI / 3, vector) #=> (0.5+0.5i+0.5j+0.5k)
28
+ q4 = Quaternion(1, [2, 3, 4]) #=> (1+2i+3j+4k)
29
+
30
+ q1.rect #=> [(1+2i), (3+4i)]
31
+ q2.hrect #=> [1, -2, (-3/4), 0.56]
32
+ q3.polar #=> [1.0, Math::PI / 3, vector]
33
+ q4.real #=> 1
34
+ q4.imag #=> Vector[2, 3, 4]
35
+
36
+ Complex::I.to_q #=> (0+1i+0j+0k)
37
+ 1 + 2.i + 3.j + 4.k #=> (1+2i+3j+4k)
38
+ ```
39
+
40
+ `Quaternion` supports standard calculations between numeric instances.
41
+
42
+ ```ruby
43
+ Complex::I * Quaternion::J #=> (0+0i+0j+1k)
44
+ 1 / Quaternion::I #=> ((0/1)-(1/1)*i+(0/0)*j+(0/0)*k)
45
+ Quaternion(1, 1, 1, 1) ** 6 #=> (64+0i+0j+0k)
46
+ ```
47
+
48
+ ## Development
49
+
50
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
51
+
52
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
53
+
54
+ ## Contributing
55
+
56
+ Bug reports and pull requests are welcome on GitHub at https://github.com/hmmnrst/quaternion_c2.
57
+
58
+
59
+ ## License
60
+
61
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
62
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "quaternion_c2"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,10 @@
1
+ require "quaternion_c2/base"
2
+ require "quaternion_c2/classification"
3
+ require "quaternion_c2/unary"
4
+ require "quaternion_c2/units"
5
+ require "quaternion_c2/equality"
6
+ require "quaternion_c2/attributes"
7
+ require "quaternion_c2/arithmetic"
8
+ require "quaternion_c2/to_type"
9
+ require "quaternion_c2/conversion"
10
+ require "quaternion_c2/utils"
@@ -0,0 +1,75 @@
1
+ require_relative 'base'
2
+ require_relative 'classification'
3
+ require_relative 'unary'
4
+
5
+ #
6
+ # Basic arithmetic operators (#+, #-, #*, #/)
7
+ # and related methods
8
+ #
9
+
10
+ class Quaternion
11
+ def +(other)
12
+ if other.kind_of?(Quaternion)
13
+ __new__(@a + other.a, @b + other.b)
14
+ elsif other.kind_of?(Numeric) && other.complex?
15
+ __new__(@a + other, @b)
16
+ else
17
+ n1, n2 = other.coerce(self)
18
+ n1 + n2
19
+ end
20
+ end
21
+
22
+ def -(other)
23
+ if other.kind_of?(Quaternion)
24
+ __new__(@a - other.a, @b - other.b)
25
+ elsif other.kind_of?(Numeric) && other.complex?
26
+ __new__(@a - other, @b)
27
+ else
28
+ n1, n2 = other.coerce(self)
29
+ n1 - n2
30
+ end
31
+ end
32
+
33
+ def *(other)
34
+ if other.kind_of?(Quaternion)
35
+ _a = other.a
36
+ _b = other.b
37
+ __new__(@a * _a - _b.conj * @b, _b * @a + @b * _a.conj)
38
+ elsif other.kind_of?(Numeric) && other.complex?
39
+ __new__(@a * other, @b * other.conj)
40
+ else
41
+ n1, n2 = other.coerce(self)
42
+ n1 * n2
43
+ end
44
+ end
45
+
46
+ [:quo, :fdiv].each do |sym|
47
+ define_method(sym) do |other|
48
+ if other.kind_of?(Quaternion)
49
+ self * other.conj.send(sym, other.abs2)
50
+ elsif other.kind_of?(Numeric) && other.complex?
51
+ __new__(@a.send(sym, other), @b.send(sym, other.conj))
52
+ else
53
+ n1, n2 = other.coerce(self)
54
+ n1.send(sym, n2)
55
+ end
56
+ end
57
+ end
58
+ alias / quo
59
+ undef div, %, modulo, remainder, divmod
60
+
61
+ #
62
+ # Conversion
63
+ #
64
+
65
+ def coerce(other)
66
+ if other.kind_of?(Quaternion)
67
+ [other, self]
68
+ elsif other.kind_of?(Numeric) && other.complex?
69
+ [__new__(other, 0), self]
70
+ else
71
+ raise TypeError,
72
+ "#{other.class} can't be coerced into #{self.class}"
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,25 @@
1
+ require_relative 'unary'
2
+ require_relative 'equality'
3
+
4
+ class Quaternion
5
+ # defined by Numeric:
6
+ # * zero? #=> self == 0
7
+ # * nonzero? #=> zero? ? nil : self
8
+
9
+ defined_methods = public_instance_methods
10
+
11
+ if defined_methods.include?(:finite?)
12
+ def finite?
13
+ abs.finite?
14
+ end
15
+ end
16
+
17
+ if defined_methods.include?(:infinite?)
18
+ def infinite?
19
+ abs.infinite?
20
+ end
21
+ end
22
+
23
+ undef positive? if defined_methods.include?(:positive?)
24
+ undef negative? if defined_methods.include?(:negative?)
25
+ end
@@ -0,0 +1,18 @@
1
+ class Quaternion < Numeric
2
+ attr_reader :a, :b
3
+ protected :a, :b
4
+
5
+ def initialize(a, b)
6
+ @a = a.to_c
7
+ @b = b.to_c
8
+ end
9
+
10
+ private_class_method :new
11
+
12
+
13
+ private
14
+
15
+ def __new__(a, b)
16
+ Quaternion.send(:new, a, b)
17
+ end
18
+ end
@@ -0,0 +1,32 @@
1
+ require_relative 'base'
2
+
3
+ #
4
+ # Number system classification
5
+ # (N <) Z < Q < R < C < H (< ...)
6
+ #
7
+ # * quaternion? : [H] Quaternion (*undefined*)
8
+ # * && complex? : [C] Complex
9
+ # * && real? : [R] Float, BigDecimal, Numeric
10
+ # * && rational? : [Q] Rational (*undefined*)
11
+ # * && integer? : [Z] Fixnum, Bignum, Integer
12
+ #
13
+
14
+ class Numeric
15
+ # defined:
16
+ # * integer? #=> false
17
+ # * real? #=> true
18
+
19
+ def complex?
20
+ true
21
+ end
22
+ end
23
+
24
+ class Quaternion
25
+ def real?
26
+ false
27
+ end
28
+
29
+ def complex?
30
+ false
31
+ end
32
+ end
@@ -0,0 +1,166 @@
1
+ require_relative 'base'
2
+ require_relative 'classification'
3
+ require_relative 'unary'
4
+ require_relative 'units'
5
+ require_relative 'arithmetic'
6
+ require_relative 'to_type'
7
+
8
+ require 'matrix'
9
+
10
+ class Quaternion
11
+ #
12
+ # Constructors
13
+ #
14
+
15
+ class << self
16
+ def rect(a, b = 0)
17
+ unless [a, b].all? { |c| c.kind_of?(Numeric) && c.complex? }
18
+ raise TypeError, 'not a complex'
19
+ end
20
+ new(a, b)
21
+ end
22
+ alias rectangular rect
23
+
24
+ def hrect(w, x = 0, y = 0, z = 0)
25
+ a = Complex.rect(w, x)
26
+ b = Complex.rect(y, z)
27
+ new(a, b)
28
+ end
29
+ alias hyperrectangular hrect
30
+
31
+ # Quaternion.polar(r) == r
32
+ # Quaternion.polar(r, theta) == Complex.polar(r, theta)
33
+ def polar(r, theta = 0, vector = Vector[1, 0, 0])
34
+ unless vector.kind_of?(Enumerable) && vector.size == 3
35
+ raise TypeError, 'not a 3-D vector'
36
+ end
37
+ unless [r, theta, *vector].all? { |a| a.kind_of?(Numeric) && a.real? }
38
+ raise TypeError, 'not a real'
39
+ end
40
+
41
+ vector = Vector[*vector] unless vector.kind_of?(Vector)
42
+ norm = vector.norm
43
+ theta *= norm
44
+
45
+ r_cos = r * Math.cos(theta)
46
+ r_sin = r * Math.sin(theta)
47
+ r_sin /= norm if norm > 0
48
+ hrect(r_cos, *(r_sin * vector))
49
+ end
50
+ end
51
+
52
+ #
53
+ # Accessors
54
+ #
55
+
56
+ def rect
57
+ [@a, @b]
58
+ end
59
+ alias rectangular rect
60
+
61
+ def hrect
62
+ rect.flat_map(&:rect)
63
+ end
64
+ alias hyperrectangular hrect
65
+
66
+ def real
67
+ @a.real
68
+ end
69
+ alias scalar real
70
+
71
+ def imag
72
+ Vector[*hrect.drop(1)]
73
+ end
74
+ alias imaginary imag
75
+ alias vector imag
76
+
77
+ # defined in unary.rb:
78
+ # * abs
79
+ # * magnitude
80
+
81
+ def arg
82
+ r_cos = real
83
+ r_sin = imag.norm
84
+ Math.atan2(r_sin, r_cos)
85
+ end
86
+ alias angle arg
87
+ alias phase arg
88
+
89
+ def axis
90
+ v = imag
91
+ norm = v.norm
92
+ if norm.zero?
93
+ # imag[0] == +0.0 -> q = r exp(+I PI)
94
+ # imag[0] == 0/1 -> q = r exp(+I PI)
95
+ # imag[0] == -0.0 -> q = r exp(-I PI)
96
+ sign = (1.0 / imag[0] >= 0) ? 1 : -1
97
+ Vector[sign, 0, 0]
98
+ else
99
+ v / norm
100
+ end
101
+ end
102
+
103
+ def polar
104
+ [abs, arg, axis]
105
+ end
106
+ end
107
+
108
+ #
109
+ # Generic constructor
110
+ #
111
+ # This accepts various arguments:
112
+ # * (Numeric) -> real quaternion
113
+ # * (Numeric, Numeric) -> a+bj
114
+ # * (Numeric, Vector) -> scalar and 3-D vector
115
+ # * (Numeric, Numeric, Numeric[, Numeric]) -> w+xi+yj+zk
116
+ # and String instead of Numeric.
117
+ #
118
+ module Kernel
119
+ module_function
120
+
121
+ def Quaternion(*args)
122
+ argc = args.size
123
+
124
+ unless (1..4).cover?(argc)
125
+ raise ArgumentError,
126
+ "wrong number of arguments (given #{argc}, expected 1..4)"
127
+ end
128
+
129
+ if args.any?(&:nil?)
130
+ raise TypeError, "can't convert nil into Quaternion"
131
+ end
132
+
133
+ # convert String into Numeric (strictly)
134
+ args.collect! do |arg|
135
+ case arg
136
+ when String
137
+ Quaternion.send(:parse, arg, true)
138
+ else
139
+ arg
140
+ end
141
+ end
142
+
143
+ case argc
144
+ when 2
145
+ if args[1].kind_of?(Enumerable)
146
+ # scalar and 3-D vector
147
+ if args[1].size != 3
148
+ raise TypeError, "not a 3-D vector"
149
+ end
150
+ args = [args[0], *args[1]]
151
+ else
152
+ # a pair of complex numbers
153
+ return args[0] + args[1] * Quaternion::J
154
+ end
155
+ end
156
+
157
+ # maximum four real numbers
158
+ i = Quaternion::I
159
+ j = Quaternion::J
160
+ k = Quaternion::K
161
+ zero = Quaternion.send(:new, 0, 0)
162
+ args.zip([1, i, j, k]).inject(zero) do |sum,(num,base)|
163
+ sum + num * base
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,30 @@
1
+ require_relative 'base'
2
+ require_relative 'classification'
3
+
4
+ class Quaternion
5
+ undef <=>
6
+ undef_method(*Comparable.instance_methods)
7
+
8
+ def ==(other)
9
+ if other.kind_of?(Quaternion)
10
+ @a == other.a && @b == other.b
11
+ elsif other.kind_of?(Numeric) && other.complex?
12
+ @a == other && @b == 0
13
+ else
14
+ other == self
15
+ end
16
+ end
17
+
18
+ def eql?(other)
19
+ if other.kind_of?(Quaternion)
20
+ @a.eql?(other.a) && @b.eql?(other.b)
21
+ else
22
+ false
23
+ end
24
+ end
25
+
26
+ # q1.eql?(q2) => q1.hash == q2.hash
27
+ def hash
28
+ [@a, @b].hash
29
+ end
30
+ end
@@ -0,0 +1,108 @@
1
+ require_relative 'base'
2
+ require_relative 'unary'
3
+
4
+ #
5
+ # to_xxx
6
+ #
7
+
8
+ class Quaternion
9
+ # defined by Numeric:
10
+ # * to_int #=> to_i
11
+
12
+ def to_q
13
+ self
14
+ end
15
+
16
+ def to_c
17
+ unless __exact_zero__(@b)
18
+ raise RangeError, "can't convert #{self} into Complex"
19
+ end
20
+ @a
21
+ end
22
+
23
+ [:to_f, :to_r, :to_i, :rationalize].each do |sym|
24
+ define_method(sym) { |*args| to_c.send(sym, *args) }
25
+ end
26
+
27
+ def to_s
28
+ __format__(:to_s)
29
+ end
30
+
31
+ def inspect
32
+ "(#{__format__(:inspect)})"
33
+ end
34
+
35
+ private
36
+
37
+ def __format__(sym)
38
+ w, *xyz = [@a, @b].flat_map(&:rect)
39
+ sw = w.send(sym)
40
+ sx, sy, sz = xyz.zip(%w[i j k]).collect do |num,base|
41
+ if num.kind_of?(Float)
42
+ str = num.send(sym)
43
+ str[0,0] = '+' if str[0] != '-'
44
+ elsif num < 0
45
+ str = '-' + (-num).send(sym)
46
+ else
47
+ str = '+' + num.send(sym)
48
+ end
49
+ str << '*' if str[-1] !~ /\d/
50
+ str << base
51
+ end
52
+ [sw, sx, sy, sz].join
53
+ end
54
+
55
+ class << self
56
+ def parse(str, strict = false)
57
+ regexp = %r{
58
+ \A
59
+ \s*+
60
+ (?:(?'real' [+-]?+ \g'rational' ) (?![ijk]))?+
61
+ (?:(?'imag_i' \g'head_or_sign' \g'rational'?+) i )?+
62
+ (?:(?'imag_j' \g'head_or_sign' \g'rational'?+) j )?+
63
+ (?:(?'imag_k' \g'head_or_sign' \g'rational'?+) k )?+
64
+ \s*+
65
+ |\z
66
+ (?'head_or_sign' (?<=^|\s) [+-]?+ | [+-])
67
+ (?'digits' \d++ (?:#{strict ? "_" : "_++"} \d++)*+)
68
+ (?'int_or_float' (?:\g'digits')?+ (?:\. \g'digits')?+ (?<=\d) (?:e [+-]?+ \g'digits')?+)
69
+ (?'rational' \g'int_or_float' (?:/ \g'digits')?+)
70
+ }xi
71
+
72
+ match_data = regexp.match(str)
73
+ if strict && (!$'.empty? || match_data.captures[0,4].all?(&:nil?))
74
+ raise ArgumentError, "invalid value for convert(): #{str.inspect}"
75
+ end
76
+
77
+ w, x, y, z = match_data.captures[0,4].collect do |s|
78
+ case s
79
+ when %r{/} then s.to_r
80
+ when %r{[.eE]} then s.to_f
81
+ when '+', '' then 1
82
+ when '-' then -1
83
+ else s.to_i # Integer or nil
84
+ end
85
+ end
86
+
87
+ new(Complex.rect(w, x), Complex.rect(y, z))
88
+ end
89
+ end
90
+ end
91
+
92
+ class Numeric
93
+ def to_q
94
+ Quaternion.send(:new, self, 0)
95
+ end
96
+ end
97
+
98
+ class String
99
+ def to_q
100
+ Quaternion.send(:parse, self, false)
101
+ end
102
+ end
103
+
104
+ class NilClass
105
+ def to_q
106
+ Quaternion.send(:new, 0, 0)
107
+ end
108
+ end
@@ -0,0 +1,43 @@
1
+ require_relative 'base'
2
+
3
+ #
4
+ # Unary operations
5
+ #
6
+
7
+ class Quaternion
8
+ # defined by Numeric:
9
+ # * +@ #=> self
10
+ # * -@ #=> 0 - self
11
+
12
+ def conj
13
+ __new__(@a.conj, -@b)
14
+ end
15
+ alias conjugate conj
16
+
17
+ def abs2
18
+ @a.abs2 + @b.abs2
19
+ end
20
+
21
+ def abs
22
+ a_abs = @a.abs
23
+ b_abs = @b.abs
24
+ if __exact_zero__(a_abs)
25
+ b_abs
26
+ elsif __exact_zero__(b_abs)
27
+ a_abs
28
+ else
29
+ Math.hypot(a_abs, b_abs)
30
+ end
31
+ end
32
+ alias magnitude abs
33
+
34
+ private
35
+
36
+ def __exact_zero__(x)
37
+ 1 / x
38
+ rescue ZeroDivisionError
39
+ true
40
+ else
41
+ false
42
+ end
43
+ end
@@ -0,0 +1,40 @@
1
+ require_relative 'base'
2
+
3
+ #
4
+ # Fundamental quaternion units
5
+ #
6
+
7
+ class Quaternion
8
+ i = Complex::I
9
+ I = new(i, 0)
10
+ J = new(0, 1)
11
+ K = new(0, i)
12
+ end
13
+
14
+ #
15
+ # Convert to an imaginary part
16
+ #
17
+
18
+ class Numeric
19
+ # defined:
20
+ # * #i #=> Complex.rect(0, self)
21
+
22
+ def j
23
+ Quaternion.send(:new, 0, self)
24
+ end
25
+
26
+ def k
27
+ Quaternion.send(:new, 0, self.i)
28
+ end
29
+ end
30
+
31
+ class Complex
32
+ # undefined:
33
+ # * #i
34
+
35
+ undef k
36
+ end
37
+
38
+ class Quaternion
39
+ undef i, j, k
40
+ end
@@ -0,0 +1,71 @@
1
+ require_relative 'base'
2
+ require_relative 'classification'
3
+ require_relative 'unary'
4
+ require_relative 'arithmetic'
5
+ require_relative 'conversion'
6
+
7
+ class Quaternion
8
+ def **(index)
9
+ if index.kind_of?(Numeric)
10
+ if __exact_zero__(index)
11
+ return __new__(1, 0)
12
+ end
13
+
14
+ # complex -> real
15
+ begin
16
+ index.to_f
17
+ rescue
18
+ else
19
+ index = index.real
20
+ end
21
+
22
+ # rational -> integer
23
+ if index.kind_of?(Rational) && index.denominator == 1
24
+ index = index.numerator
25
+ end
26
+
27
+ if index.integer?
28
+ # binary method
29
+ x = (index >= 0) ? self : 1 / self
30
+ n = index.abs
31
+
32
+ z = __new__(1, 0)
33
+ while true
34
+ n, i = n.divmod(2)
35
+ z *= x if i == 1
36
+ return z if n == 0
37
+ x *= x
38
+ end
39
+ elsif index.real?
40
+ r, theta, vector = polar
41
+ return Quaternion.polar(r ** index, theta * index, vector)
42
+ elsif index.complex? || index.kind_of?(Quaternion)
43
+ r, theta, vector = polar
44
+ q = Math.log(r) + Quaternion.hrect(0, *(theta * vector))
45
+ q *= index
46
+ return Quaternion.polar(Math.exp(q.real), 1, q.imag)
47
+ end
48
+ end
49
+
50
+ num1, num2 = other.coerce(self)
51
+ num1 ** num2
52
+ end
53
+
54
+ def denominator
55
+ ad = @a.denominator
56
+ bd = @b.denominator
57
+ ad.lcm(bd)
58
+ end
59
+
60
+ def numerator
61
+ an = @a.numerator
62
+ bn = @b.numerator
63
+ ad = @a.denominator
64
+ bd = @b.denominator
65
+ abd = ad.lcm(bd)
66
+ __new__(an * (abd / ad), bn * (abd / bd))
67
+ end
68
+
69
+ undef step
70
+ undef ceil, floor, round, truncate
71
+ end
@@ -0,0 +1,25 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "quaternion_c2"
6
+ spec.version = "0.1.1"
7
+ spec.authors = ["Masahiro Nomoto"]
8
+ spec.email = ["hmmnrst@users.noreply.github.com"]
9
+
10
+ spec.summary = %q{Quaternion class}
11
+ spec.description = %q{This provides a numeric class Quaternion which is similar to a built-in class Complex.}
12
+ spec.homepage = "https://github.com/hmmnrst/quaternion_c2"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
16
+ f.match(%r{^(test|spec|features)/})
17
+ end
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.14"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "rspec", "~> 3.0"
25
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: quaternion_c2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Masahiro Nomoto
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-03-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.14'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.14'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: This provides a numeric class Quaternion which is similar to a built-in
56
+ class Complex.
57
+ email:
58
+ - hmmnrst@users.noreply.github.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - .gitignore
64
+ - .rspec
65
+ - .travis.yml
66
+ - Gemfile
67
+ - LICENSE.txt
68
+ - README.md
69
+ - Rakefile
70
+ - bin/console
71
+ - bin/setup
72
+ - lib/quaternion_c2.rb
73
+ - lib/quaternion_c2/arithmetic.rb
74
+ - lib/quaternion_c2/attributes.rb
75
+ - lib/quaternion_c2/base.rb
76
+ - lib/quaternion_c2/classification.rb
77
+ - lib/quaternion_c2/conversion.rb
78
+ - lib/quaternion_c2/equality.rb
79
+ - lib/quaternion_c2/to_type.rb
80
+ - lib/quaternion_c2/unary.rb
81
+ - lib/quaternion_c2/units.rb
82
+ - lib/quaternion_c2/utils.rb
83
+ - quaternion_c2.gemspec
84
+ homepage: https://github.com/hmmnrst/quaternion_c2
85
+ licenses:
86
+ - MIT
87
+ metadata: {}
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 2.5.0
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Quaternion class
108
+ test_files: []