2011-05-12 17:51:41 -04:00
|
|
|
##
|
|
|
|
# = mathn
|
1998-01-16 07:13:05 -05:00
|
|
|
#
|
2011-05-22 20:08:30 -04:00
|
|
|
# mathn is a library for changing the way Ruby does math. If you need
|
|
|
|
# more precise rounding with multiple division or exponentiation
|
|
|
|
# operations, then mathn is the right tool. It makes sense to use this
|
|
|
|
# library if you can use it's late rounding. Mathn does not convert
|
|
|
|
# Fixnums into Floats as long as you do not convert it yourself.
|
|
|
|
# Instead of using Float as intermediate value it use Rational as
|
|
|
|
# value representation.
|
|
|
|
#
|
|
|
|
# Example Fixnum with intermediate Float:
|
|
|
|
#
|
|
|
|
# 20 / 9 * 3 * 14 / 7 * 3 / 2 # => 18
|
|
|
|
#
|
|
|
|
# Example: using mathn Fixnum/Rational:
|
|
|
|
#
|
|
|
|
# require 'mathn'
|
|
|
|
# 20 / 9 * 3 * 14 / 7 * 3 / 2 # => 20
|
1998-01-16 07:13:05 -05:00
|
|
|
#
|
2011-05-12 17:51:41 -04:00
|
|
|
# == Usage
|
|
|
|
#
|
|
|
|
# To start using this library, simply:
|
|
|
|
#
|
|
|
|
# require "mathn"
|
|
|
|
#
|
|
|
|
# This will change the way division works for Fixnums, specifically
|
1998-01-16 07:13:05 -05:00
|
|
|
#
|
2011-05-12 17:51:41 -04:00
|
|
|
# 3 / 2
|
2009-03-05 22:56:38 -05:00
|
|
|
#
|
2011-05-22 20:08:30 -04:00
|
|
|
# will return +Rational+ (3/2) instead of the usual +Fixnum+ 1.
|
1998-01-16 07:13:05 -05:00
|
|
|
#
|
2011-05-12 17:51:41 -04:00
|
|
|
# == Copyright
|
|
|
|
#
|
|
|
|
# Author: Keiju ISHITSUKA(SHL Japan Inc.)
|
|
|
|
#
|
2011-05-22 20:08:30 -04:00
|
|
|
#--
|
2011-05-12 17:51:41 -04:00
|
|
|
# $Release Version: 0.5 $
|
|
|
|
# $Revision: 1.1.1.1.4.1 $
|
1998-01-16 07:13:05 -05:00
|
|
|
|
2008-09-19 09:55:52 -04:00
|
|
|
require "cmath.rb"
|
1998-01-16 07:13:05 -05:00
|
|
|
require "matrix.rb"
|
2008-09-03 09:57:21 -04:00
|
|
|
require "prime.rb"
|
1998-01-16 07:13:05 -05:00
|
|
|
|
2008-10-24 05:39:53 -04:00
|
|
|
require "mathn/rational"
|
|
|
|
require "mathn/complex"
|
|
|
|
|
2008-09-19 09:55:52 -04:00
|
|
|
unless defined?(Math.exp!)
|
|
|
|
Object.instance_eval{remove_const :Math}
|
|
|
|
Math = CMath
|
|
|
|
end
|
|
|
|
|
2011-05-22 20:08:30 -04:00
|
|
|
##
|
|
|
|
# When mathn is required Fixnum's division and exponentiation are enhanced to
|
|
|
|
# return more precise values in mathematical formulas.
|
|
|
|
#
|
|
|
|
# 2/3*3 # => 0
|
|
|
|
# require 'mathn'
|
|
|
|
# 2/3*3 # => 2
|
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
class Fixnum
|
2005-09-19 12:01:06 -04:00
|
|
|
remove_method :/
|
2011-05-22 20:08:30 -04:00
|
|
|
|
|
|
|
##
|
|
|
|
# +/+ defines the Rational division for Fixnum.
|
|
|
|
#
|
|
|
|
# 1/3 # => (1/3)
|
|
|
|
|
2003-01-23 01:22:50 -05:00
|
|
|
alias / quo
|
2008-09-27 19:41:21 -04:00
|
|
|
|
2009-09-23 20:42:23 -04:00
|
|
|
alias power! ** unless method_defined? :power!
|
2008-09-27 20:41:42 -04:00
|
|
|
|
2011-05-12 17:51:41 -04:00
|
|
|
##
|
2011-05-22 20:08:30 -04:00
|
|
|
# Exponentiate by +other+
|
|
|
|
|
2008-09-27 20:41:42 -04:00
|
|
|
def ** (other)
|
|
|
|
if self < 0 && other.round != other
|
|
|
|
Complex(self, 0.0) ** other
|
|
|
|
else
|
|
|
|
power!(other)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
|
|
|
|
2011-05-22 20:08:30 -04:00
|
|
|
##
|
|
|
|
# When mathn is required Bignum's division and exponentiation are enhanced to
|
|
|
|
# return more precise values in mathematical formulas.
|
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
class Bignum
|
2005-09-19 12:01:06 -04:00
|
|
|
remove_method :/
|
2011-05-22 20:08:30 -04:00
|
|
|
|
|
|
|
##
|
|
|
|
# +/+ defines the Rational division for Bignum.
|
|
|
|
#
|
|
|
|
# (2**72) / ((2**70) * 3) # => 4/3
|
|
|
|
|
2003-01-23 01:22:50 -05:00
|
|
|
alias / quo
|
2008-09-27 19:41:21 -04:00
|
|
|
|
2009-09-23 20:42:23 -04:00
|
|
|
alias power! ** unless method_defined? :power!
|
2008-09-27 20:41:42 -04:00
|
|
|
|
2011-05-12 17:51:41 -04:00
|
|
|
##
|
2011-05-22 20:08:30 -04:00
|
|
|
# Exponentiate by +other+
|
|
|
|
|
2008-09-27 20:41:42 -04:00
|
|
|
def ** (other)
|
|
|
|
if self < 0 && other.round != other
|
|
|
|
Complex(self, 0.0) ** other
|
|
|
|
else
|
|
|
|
power!(other)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
|
|
|
|
2011-05-22 20:08:30 -04:00
|
|
|
##
|
|
|
|
# When mathn is required Rational changes to simplfy the usage of Rational
|
|
|
|
# operations.
|
|
|
|
#
|
|
|
|
# Normal behaviour:
|
|
|
|
#
|
|
|
|
# Rational.new!(1,3) ** 2 # => Rational(1, 9)
|
|
|
|
# (1 / 3) ** 2 # => 0
|
|
|
|
#
|
|
|
|
# require 'mathn' behaviour:
|
|
|
|
#
|
|
|
|
# (1 / 3) ** 2 # => 1/9
|
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
class Rational
|
2010-01-25 17:08:29 -05:00
|
|
|
remove_method :**
|
2011-05-12 18:04:59 -04:00
|
|
|
|
|
|
|
##
|
2011-05-22 20:08:30 -04:00
|
|
|
# Exponentiate by +other+
|
|
|
|
#
|
|
|
|
# (1/3) ** 2 # => 1/9
|
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
def ** (other)
|
|
|
|
if other.kind_of?(Rational)
|
2005-09-17 12:00:23 -04:00
|
|
|
other2 = other
|
1998-01-16 07:13:05 -05:00
|
|
|
if self < 0
|
2011-05-12 18:04:59 -04:00
|
|
|
return Complex(self, 0.0) ** other
|
1998-01-16 07:13:05 -05:00
|
|
|
elsif other == 0
|
2011-05-12 18:04:59 -04:00
|
|
|
return Rational(1,1)
|
1998-01-16 07:13:05 -05:00
|
|
|
elsif self == 0
|
2011-05-12 18:04:59 -04:00
|
|
|
return Rational(0,1)
|
1998-01-16 07:13:05 -05:00
|
|
|
elsif self == 1
|
2011-05-12 18:04:59 -04:00
|
|
|
return Rational(1,1)
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
2009-03-05 22:56:38 -05:00
|
|
|
|
2003-07-25 01:36:55 -04:00
|
|
|
npd = numerator.prime_division
|
|
|
|
dpd = denominator.prime_division
|
1998-01-16 07:13:05 -05:00
|
|
|
if other < 0
|
2011-05-12 18:04:59 -04:00
|
|
|
other = -other
|
|
|
|
npd, dpd = dpd, npd
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
2009-03-05 22:56:38 -05:00
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
for elm in npd
|
2011-05-12 18:04:59 -04:00
|
|
|
elm[1] = elm[1] * other
|
|
|
|
if !elm[1].kind_of?(Integer) and elm[1].denominator != 1
|
|
|
|
return Float(self) ** other2
|
|
|
|
end
|
|
|
|
elm[1] = elm[1].to_i
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
2009-03-05 22:56:38 -05:00
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
for elm in dpd
|
2011-05-12 18:04:59 -04:00
|
|
|
elm[1] = elm[1] * other
|
|
|
|
if !elm[1].kind_of?(Integer) and elm[1].denominator != 1
|
|
|
|
return Float(self) ** other2
|
|
|
|
end
|
|
|
|
elm[1] = elm[1].to_i
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
2009-03-05 22:56:38 -05:00
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
num = Integer.from_prime_division(npd)
|
|
|
|
den = Integer.from_prime_division(dpd)
|
2009-03-05 22:56:38 -05:00
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
Rational(num,den)
|
2009-03-05 22:56:38 -05:00
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
elsif other.kind_of?(Integer)
|
|
|
|
if other > 0
|
2011-05-12 18:04:59 -04:00
|
|
|
num = numerator ** other
|
|
|
|
den = denominator ** other
|
1998-01-16 07:13:05 -05:00
|
|
|
elsif other < 0
|
2011-05-12 18:04:59 -04:00
|
|
|
num = denominator ** -other
|
|
|
|
den = numerator ** -other
|
1998-01-16 07:13:05 -05:00
|
|
|
elsif other == 0
|
2011-05-12 18:04:59 -04:00
|
|
|
num = 1
|
|
|
|
den = 1
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
2008-03-15 20:23:43 -04:00
|
|
|
Rational(num, den)
|
1998-01-16 07:13:05 -05:00
|
|
|
elsif other.kind_of?(Float)
|
|
|
|
Float(self) ** other
|
|
|
|
else
|
|
|
|
x , y = other.coerce(self)
|
|
|
|
x ** y
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-05-22 20:08:30 -04:00
|
|
|
##
|
|
|
|
# When mathn is requried the Math module changes as follows:
|
|
|
|
#
|
|
|
|
# Standard Math module behaviour:
|
|
|
|
# Math.sqrt(4/9) # => 0.0
|
|
|
|
# Math.sqrt(4.0/9.0) # => 0.666666666666667
|
|
|
|
# Math.sqrt(- 4/9) # => Errno::EDOM: Numerical argument out of domain - sqrt
|
|
|
|
#
|
|
|
|
# After require 'mathn' this is changed to:
|
|
|
|
#
|
|
|
|
# require 'mathn'
|
|
|
|
# Math.sqrt(4/9) # => 2/3
|
|
|
|
# Math.sqrt(4.0/9.0) # => 0.666666666666667
|
|
|
|
# Math.sqrt(- 4/9) # => Complex(0, 2/3)
|
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
module Math
|
2004-10-04 21:37:46 -04:00
|
|
|
remove_method(:sqrt)
|
2011-05-12 17:51:41 -04:00
|
|
|
|
|
|
|
##
|
2011-05-22 20:08:30 -04:00
|
|
|
# Computes the square root of +a+. It makes use of Complex and
|
|
|
|
# Rational to have no rounding errors if possible.
|
|
|
|
#
|
|
|
|
# Math.sqrt(4/9) # => 2/3
|
|
|
|
# Math.sqrt(- 4/9) # => Complex(0, 2/3)
|
|
|
|
# Math.sqrt(4.0/9.0) # => 0.666666666666667
|
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
def sqrt(a)
|
|
|
|
if a.kind_of?(Complex)
|
2008-09-20 18:49:56 -04:00
|
|
|
abs = sqrt(a.real*a.real + a.imag*a.imag)
|
1998-01-16 07:13:05 -05:00
|
|
|
# if not abs.kind_of?(Rational)
|
2011-05-12 18:04:59 -04:00
|
|
|
# return a**Rational(1,2)
|
1998-01-16 07:13:05 -05:00
|
|
|
# end
|
|
|
|
x = sqrt((a.real + abs)/Rational(2))
|
|
|
|
y = sqrt((-a.real + abs)/Rational(2))
|
|
|
|
# if !(x.kind_of?(Rational) and y.kind_of?(Rational))
|
2011-05-12 18:04:59 -04:00
|
|
|
# return a**Rational(1,2)
|
1998-01-16 07:13:05 -05:00
|
|
|
# end
|
2009-03-05 22:56:38 -05:00
|
|
|
if a.imag >= 0
|
2011-05-12 18:04:59 -04:00
|
|
|
Complex(x, y)
|
1998-01-16 07:13:05 -05:00
|
|
|
else
|
2011-05-12 18:04:59 -04:00
|
|
|
Complex(x, -y)
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
2008-12-23 01:48:42 -05:00
|
|
|
elsif a.respond_to?(:nan?) and a.nan?
|
|
|
|
a
|
1998-01-16 07:13:05 -05:00
|
|
|
elsif a >= 0
|
|
|
|
rsqrt(a)
|
|
|
|
else
|
|
|
|
Complex(0,rsqrt(-a))
|
|
|
|
end
|
|
|
|
end
|
2009-03-05 22:56:38 -05:00
|
|
|
|
2011-05-22 20:08:30 -04:00
|
|
|
##
|
|
|
|
# Compute square root of a non negative number. This method is
|
|
|
|
# internally used by +Math.sqrt+.
|
|
|
|
|
|
|
|
def rsqrt(a)
|
1998-01-16 07:13:05 -05:00
|
|
|
if a.kind_of?(Float)
|
|
|
|
sqrt!(a)
|
|
|
|
elsif a.kind_of?(Rational)
|
|
|
|
rsqrt(a.numerator)/rsqrt(a.denominator)
|
|
|
|
else
|
|
|
|
src = a
|
|
|
|
max = 2 ** 32
|
|
|
|
byte_a = [src & 0xffffffff]
|
|
|
|
# ruby's bug
|
|
|
|
while (src >= max) and (src >>= 32)
|
2011-05-12 18:04:59 -04:00
|
|
|
byte_a.unshift src & 0xffffffff
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
2009-03-05 22:56:38 -05:00
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
answer = 0
|
|
|
|
main = 0
|
|
|
|
side = 0
|
|
|
|
for elm in byte_a
|
2011-05-12 18:04:59 -04:00
|
|
|
main = (main << 32) + elm
|
|
|
|
side <<= 16
|
|
|
|
if answer != 0
|
|
|
|
if main * 4 < side * side
|
|
|
|
applo = main.div(side)
|
|
|
|
else
|
|
|
|
applo = ((sqrt!(side * side + 4 * main) - side)/2.0).to_i + 1
|
|
|
|
end
|
|
|
|
else
|
|
|
|
applo = sqrt!(main).to_i + 1
|
|
|
|
end
|
|
|
|
|
|
|
|
while (x = (side + applo) * applo) > main
|
|
|
|
applo -= 1
|
|
|
|
end
|
|
|
|
main -= x
|
|
|
|
answer = (answer << 16) + applo
|
|
|
|
side += applo * 2
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
|
|
|
if main == 0
|
2011-05-12 18:04:59 -04:00
|
|
|
answer
|
1998-01-16 07:13:05 -05:00
|
|
|
else
|
2011-05-12 18:04:59 -04:00
|
|
|
sqrt!(a)
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-01-25 17:08:29 -05:00
|
|
|
class << self
|
|
|
|
remove_method(:sqrt)
|
|
|
|
end
|
1998-01-16 07:13:05 -05:00
|
|
|
module_function :sqrt
|
|
|
|
module_function :rsqrt
|
|
|
|
end
|
|
|
|
|
2011-05-22 20:08:30 -04:00
|
|
|
##
|
|
|
|
# When mathn is required Float is changed to handle Complex numbers.
|
|
|
|
|
2008-09-27 19:41:21 -04:00
|
|
|
class Float
|
2008-09-27 20:41:42 -04:00
|
|
|
alias power! **
|
|
|
|
|
2011-05-12 17:51:41 -04:00
|
|
|
##
|
2011-05-22 20:08:30 -04:00
|
|
|
# Exponentiate by +other+
|
|
|
|
|
2008-09-27 20:41:42 -04:00
|
|
|
def ** (other)
|
|
|
|
if self < 0 && other.round != other
|
|
|
|
Complex(self, 0.0) ** other
|
|
|
|
else
|
|
|
|
power!(other)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|