Project

General

Profile

Feature #2561 » ruby-1.8.7-rational.patch

Fixed Fixnum#gcd for FIXNUM_MIN. - kstephens (Kurt Stephens), 01/12/2010 01:18 AM

View differences:

lib/rational.rb
#
# Documentation by Kevin Jackson and Gavin Sinclair.
#
# Performance improvements by Kurt Stephens.
#
# When you <tt>require 'rational'</tt>, all interactions between numbers
# potentially return a rational result. For example:
#
......
num = -num
den = -den
end
if num.kind_of?(Integer) and den.kind_of?(Integer)
@numerator = num
@denominator = den
else
@numerator = num.to_i
@denominator = den.to_i
end
@numerator = num.to_i
@denominator = den.to_i
end
#
......
# r + 0.5 # -> 1.25
#
def + (a)
if a.kind_of?(Rational)
num = @numerator * a.denominator
num_a = a.numerator * @denominator
Rational(num + num_a, @denominator * a.denominator)
elsif a.kind_of?(Integer)
self + Rational.new!(a, 1)
elsif a.kind_of?(Float)
Float(self) + a
case a
when Rational # => Rational | Integer
Rational( (@numerator * a.denominator) + (a.numerator * @denominator), @denominator * a.denominator)
when Integer # => Rational
Rational.reduce((@numerator ) + (a * @denominator), @denominator)
when Float
self.to_f + a
else
x, y = a.coerce(self)
x + y
......
# r - 0.5 # -> 0.25
#
def - (a)
if a.kind_of?(Rational)
num = @numerator * a.denominator
num_a = a.numerator * @denominator
Rational(num - num_a, @denominator*a.denominator)
elsif a.kind_of?(Integer)
self - Rational.new!(a, 1)
elsif a.kind_of?(Float)
Float(self) - a
case a
when Rational # => Rational | Integer
Rational( (@numerator * a.denominator) - (a.numerator * @denominator), @denominator * a.denominator)
when Integer # => Rational
Rational.reduce((@numerator ) - (a * @denominator), @denominator)
when Float
self.to_f - a
else
x, y = a.coerce(self)
x - y
......
end
#
# Unary Minus--Returns the receiver's value, negated.
#
def -@
Rational.new!(- @numerator, @denominator)
end
#
# Returns the product of this value and +a+.
#
# Examples:
......
# r * Rational(1,2) # -> Rational(3,8)
#
def * (a)
if a.kind_of?(Rational)
num = @numerator * a.numerator
den = @denominator * a.denominator
Rational(num, den)
elsif a.kind_of?(Integer)
self * Rational.new!(a, 1)
elsif a.kind_of?(Float)
Float(self) * a
case a
when Rational
Rational(@numerator * a.numerator, @denominator * a.denominator)
when Integer
Rational(@numerator * a , @denominator)
when Float
self.to_f * a
else
x, y = a.coerce(self)
x * y
......
# r / Rational(1,2) # -> Rational(3,2)
#
def / (a)
if a.kind_of?(Rational)
num = @numerator * a.denominator
den = @denominator * a.numerator
Rational(num, den)
elsif a.kind_of?(Integer)
case a
when Rational
Rational(@numerator * a.denominator, @denominator * a.numerator)
when Integer
raise ZeroDivisionError, "division by zero" if a == 0
self / Rational.new!(a, 1)
elsif a.kind_of?(Float)
Float(self) / a
Rational(@numerator , @denominator * a )
when Float
self.to_f / a
else
x, y = a.coerce(self)
x / y
......
# r ** Rational(1,2) # -> 0.866025403784439
#
def ** (other)
if other.kind_of?(Rational)
Float(self) ** other
elsif other.kind_of?(Integer)
case other
when Rational, Float
self.to_f ** other
when Integer
if other > 0
num = @numerator ** other
den = @denominator ** other
Rational.new!(@numerator ** other, @denominator ** other)
elsif other < 0
num = @denominator ** -other
den = @numerator ** -other
elsif other == 0
num = 1
den = 1
Rational.new!(@denominator ** -other, @numerator ** -other)
else
Rational.new!(1, 1) # why not Fixnum 1?
end
Rational.new!(num, den)
elsif other.kind_of?(Float)
Float(self) ** other
else
x, y = other.coerce(self)
x ** y
......
#
def % (other)
value = (self / other).floor
return self - other * value
self - other * value
end
#
......
#
def divmod(other)
value = (self / other).floor
return value, self - other * value
[ value, self - other * value ]
end
#
......
end
end
# Returns true or false.
def zero?
@numerator.zero?
end
# See Numeric#nonzero?
def nonzero?
@numerator.nonzero? ? self : nil
end
#
# Returns +true+ iff this value is numerically equal to +other+.
#
......
# Don't use Rational.new!
#
def == (other)
if other.kind_of?(Rational)
case other
when Rational
@numerator == other.numerator and @denominator == other.denominator
elsif other.kind_of?(Integer)
self == Rational.new!(other, 1)
elsif other.kind_of?(Float)
Float(self) == other
when Integer
@numerator == other && @denominator == 1
when Float
self.to_f == other
else
other == self
end
......
# Standard comparison operator.
#
def <=> (other)
if other.kind_of?(Rational)
num = @numerator * other.denominator
num_a = other.numerator * @denominator
v = num - num_a
if v > 0
return 1
elsif v < 0
return -1
else
return 0
end
elsif other.kind_of?(Integer)
return self <=> Rational.new!(other, 1)
elsif other.kind_of?(Float)
return Float(self) <=> other
elsif defined? other.coerce
x, y = other.coerce(self)
return x <=> y
case other
when Rational
((@numerator * other.denominator) <=> (other.numerator * @denominator))
when Integer
((@numerator ) <=> (other * @denominator))
when Float
self.to_f <=> other
else
return nil
if defined? other.coerce
x, y = other.coerce(self)
x <=> y
end # nil
end
end
def coerce(other)
if other.kind_of?(Float)
return other, self.to_f
elsif other.kind_of?(Integer)
return Rational.new!(other, 1), self
case other
when Float
[ other, self.to_f ]
when Integer
[ Rational.new!(other, 1), self ]
else
super
end
......
def truncate()
if @numerator < 0
return -((-@numerator).div(@denominator))
-((-@numerator).div(@denominator))
else
@numerator.div(@denominator)
end
@numerator.div(@denominator)
end
alias_method :to_i, :truncate
def round()
if @numerator < 0
num = -@numerator
num = num * 2 + @denominator
den = @denominator * 2
-(num.div(den))
-((@numerator * -2 + @denominator).div(@denominator * 2))
else
num = @numerator * 2 + @denominator
den = @denominator * 2
num.div(den)
((@numerator * 2 + @denominator).div(@denominator * 2))
end
end
......
if @denominator == 1
@numerator.to_s
else
@numerator.to_s+"/"+@denominator.to_s
"#{@numerator}/#{@denominator}"
end
end
......
# Rational(5,8).inspect # -> "Rational(5, 8)"
#
def inspect
sprintf("Rational(%s, %s)", @numerator.inspect, @denominator.inspect)
"Rational(#{@numerator.inspect}, #{@denominator.inspect})"
end
#
numeric.c
return Qtrue;
}
static VALUE
fix_gcd(int argc, VALUE *argv, VALUE self) {
if ( argc != 1 ) {
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, 1);
}
/* Handle Fixnum#gcd(Fixnum) here. */
if ( FIXNUM_P(argv[0]) ) {
/* fprintf(stderr, "Using Fixnum#gcd(Fixnum)\n"); */
long a = FIX2LONG(self);
long b = FIX2LONG(argv[0]);
long min = a < 0 ? - a : a;
long max = b < 0 ? - b : b;
while ( min > 0 ) {
int tmp = min;
min = max % min;
max = tmp;
}
return LONG2FIX(max);
} else {
/* Delegate to Integer#gcd. */
return rb_call_super(1, argv);
}
}
void
Init_Numeric()
{
......
rb_define_method(rb_cFixnum, "divmod", fix_divmod, 1);
rb_define_method(rb_cFixnum, "quo", fix_quo, 1);
rb_define_method(rb_cFixnum, "fdiv", fix_quo, 1);
rb_define_method(rb_cFixnum, "gcd", fix_gcd, -1);
rb_define_method(rb_cFixnum, "**", fix_pow, 1);
rb_define_method(rb_cFixnum, "abs", fix_abs, 0);
numeric.c
fix_gcd(int argc, VALUE *argv, VALUE self) {
if ( argc != 1 ) {
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, 1);
}
/* Handle Fixnum#gcd(Fixnum) here. */
if ( FIXNUM_P(argv[0]) ) {
/* fprintf(stderr, "Using Fixnum#gcd(Fixnum)\n"); */
} else {
/* Handle Fixnum#gcd(Fixnum) here.
* Note: Cannot handle FIXNUM_MIN here due to overflow during negation.
*/
long a = FIX2LONG(self);
long b = FIX2LONG(argv[0]);
long min = a < 0 ? - a : a;
long max = b < 0 ? - b : b;
while ( min > 0 ) {
int tmp = min;
min = max % min;
max = tmp;
}
return LONG2FIX(max);
} else {
/* Delegate to Integer#gcd. */
return rb_call_super(1, argv);
if ( a != FIXNUM_MIN && FIXNUM_P(argv[0]) && b != FIXNUM_MIN ) {
/* fprintf(stderr, "Using Fixnum#gcd(Fixnum)\n"); */
long min = a < 0 ? - a : a;
long max = b < 0 ? - b : b;
while ( min > 0 ) {
int tmp = min;
min = max % min;
max = tmp;
}
return LONG2FIX(max);
} else {
/* Delegate to Integer#gcd. */
return rb_call_super(1, argv);
}
}
}
(5-5/8)