Skip to content

Instantly share code, notes, and snippets.

@obelisk68 obelisk68/root.rb
Last active Nov 16, 2018

Embed
What would you like to do?
平方根の計算
require 'prime'
module Kernel
def Root(*args)
Root.new(*args)
end
end
module ExRoot
def to_root
case self
when Float
rationalize.to_root
else
Root.new(self ** 2)
end
end
def *(ob)
case ob
when Root
ob * to_root
else
super(ob)
end
end
def /(ob)
case ob
when Root
1.to_root / ob * to_root
else
super(ob)
end
end
def **(ob)
case ob
when Root
self ** (ob.coefficient * Math.sqrt(ob.content))
else
super(ob)
end
end
def +(ob)
case ob
when Root
case self
when Float
ob + self
else
(to_root + ob).int_check
end
else
super(ob)
end
end
def -(ob)
case ob
when Root
self + (-ob)
else
super(ob)
end
end
def ==(ob)
case ob
when Root
ob == self
else
super(ob)
end
end
def <=>(ob)
case ob
when Root
-1 * (ob <=> self)
else
super(ob)
end
end
def <(ob)
case ob
when Root
ob > self
else
super(ob)
end
end
def >(ob)
ob < self
end
def >=(ob)
case ob
when Root
ob <= self
else
super(ob)
end
end
def <=(ob)
ob >= self
end
[Integer, Rational, Float].each do |klass|
klass.send(:prepend, ExRoot)
end
end
class Root
def initialize(*args)
case args.size
when 2
a = args[0] * Root.new(args[1])
@coefficient = a.coefficient
@content = a.content
when 1
num = args[0]
case num
when Integer
@coefficient = 1
@content = num
convert
when Rational
r_to_root(num)
when Float
r_to_root(num.rationalize)
else
error(num)
end
else
raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 1 or 2)"
end
end
attr_accessor :coefficient, :content
protected :coefficient=, :content=
def *(ob)
case ob
when Root
a = Root.new(1)
a.coefficient = @coefficient * ob.coefficient
a.content = @content * ob.content
a.convert
a.int_check
when Integer, Rational
self * Root.new(ob * ob)
when Float
self * ob.rationalize
else
error(ob)
end
end
def /(ob)
case ob
when Integer, Rational
self * Rational(1, ob)
when Float
self / ob.rationalize
when Root
self * Root.new(Rational(1, ob.content)) * Rational(1, ob.coefficient)
else
error(ob)
end
end
def **(ob)
case ob
when Integer
a = copy
a.coefficient **= ob
a.coefficient *= @content ** (ob / 2)
a.content **= ob % 2
a.int_check
when Rational, Float
to_f ** ob
else
error(ob)
end
end
def +(ob)
case ob
when Root
return ob if @coefficient.zero?
if @content == ob.content
a = copy
a.coefficient += ob.coefficient
return a.int_check
end
when Integer, Rational
(@content == 1) ? (return @coefficient + ob) : error(self)
when Float
return to_f + ob
end
error(ob)
end
def -(ob)
self + (-ob)
end
def -@
a = copy
a.coefficient = -a.coefficient
a
end
def +@
int_check
end
def int_check
return 0 if @coefficient.zero?
(@content == 1) ? @coefficient : self
end
def inspect
if @coefficient == 1
"Root(#{@content})"
else
"(#{@coefficient})Root(#{@content})"
end
end
def to_s
inspect
end
def to_f
@coefficient * Math.sqrt(@content)
end
def to_i
to_f.to_i
end
def <(ob)
to_f < ob.to_f
end
def >(ob)
to_f > ob.to_f
end
def ==(ob)
case ob
when Root
@content == ob.content and @coefficient == ob.coefficient
else
to_f == ob.to_f
end
end
def >=(ob)
self > ob or self == ob
end
def <=(ob)
self < ob or self == ob
end
def <=>(ob)
if self == ob
0
elsif self > ob
1
else
-1
end
end
def to_root
self
end
protected
def convert
if @content.zero?
@content = 1
@coefficient = 0
else
c = 1
Prime.prime_division(@content).each do |a|
@coefficient *= a[0] ** (a[1] / 2)
c *= a[0] ** (a[1] % 2)
end
@content = c
end
end
def copy
a = Root.new(1)
a.coefficient = @coefficient
a.content = @content
a
end
private
def r_to_root(num)
deno = num.denominator
@coefficient = Rational(1, deno)
@content = num.numerator * deno
convert
end
def error(num)
raise TypeError, "#{num} (Class #{num.class}) can not be used at this place."
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.