lib/rational.rb


DEFINITIONS

This source file includes following functions.


   1  #
   2  #   rational.rb - 
   3  #       $Release Version: 0.5 $
   4  #       $Revision: 1.7 $
   5  #       $Date: 1999/08/24 12:49:28 $
   6  #       by Keiju ISHITSUKA(SHL Japan Inc.)
   7  #
   8  # --
   9  #   Usage:
  10  #   class Rational < Numeric
  11  #      (include Comparable)
  12  #
  13  #   Rational(a, b) --> a/b
  14  #
  15  #   Rational::+
  16  #   Rational::-
  17  #   Rational::*
  18  #   Rational::/
  19  #   Rational::**
  20  #   Rational::%
  21  #   Rational::divmod
  22  #   Rational::abs
  23  #   Rational::<=>
  24  #   Rational::to_i
  25  #   Rational::to_f
  26  #   Rational::to_s
  27  #
  28  #   Integer::gcd
  29  #   Integer::lcm
  30  #   Integer::gcdlcm
  31  #   Integer::to_r
  32  #
  33  #   Fixnum::**
  34  #   Bignum::**
  35  #   
  36  #
  37  
  38  def Rational(a, b = 1)
  39    if a.kind_of?(Rational) && b == 1
  40      a
  41    else
  42      Rational.reduce(a, b)
  43    end
  44  end
  45    
  46  class Rational < Numeric
  47    @RCS_ID='-$Id: rational.rb,v 1.7 1999/08/24 12:49:28 keiju Exp keiju $-'
  48  
  49    def Rational.reduce(num, den = 1)
  50      raise ZeroDivisionError, "denominator is 0" if den == 0
  51  
  52      if den < 0
  53        num = -num
  54        den = -den
  55      end
  56      gcd = num.gcd(den)
  57      num = num.div(gcd)
  58      den = den.div(gcd)
  59      if den == 1 && defined?(Unify)
  60        num
  61      else
  62        new!(num, den)
  63      end
  64    end
  65    
  66    def Rational.new!(num, den = 1)
  67      new(num, den)
  68    end
  69    
  70    def initialize(num, den)
  71      if den < 0
  72        num = -num
  73        den = -den
  74      end
  75      if num.kind_of?(Integer) and den.kind_of?(Integer)
  76        @numerator = num
  77        @denominator = den
  78      else
  79        @numerator = num.to_i
  80        @denominator = den.to_i
  81      end
  82    end
  83    
  84    def + (a)
  85      if a.kind_of?(Rational)
  86        num = @numerator * a.denominator
  87        num_a = a.numerator * @denominator
  88        Rational(num + num_a, @denominator * a.denominator)
  89      elsif a.kind_of?(Integer)
  90        self + Rational.new!(a, 1)
  91      elsif a.kind_of?(Float)
  92        Float(self) + a
  93      else
  94        x , y = a.coerce(self)
  95        x + y
  96      end
  97    end
  98    
  99    def - (a)
 100      if a.kind_of?(Rational)
 101        num = @numerator * a.denominator
 102        num_a = a.numerator * @denominator
 103        Rational(num - num_a, @denominator*a.denominator)
 104      elsif a.kind_of?(Integer)
 105        self - Rational.new!(a, 1)
 106      elsif a.kind_of?(Float)
 107        Float(self) - a
 108      else
 109        x , y = a.coerce(self)
 110        x - y
 111      end
 112    end
 113    
 114    def * (a)
 115      if a.kind_of?(Rational)
 116        num = @numerator * a.numerator
 117        den = @denominator * a.denominator
 118        Rational(num, den)
 119      elsif a.kind_of?(Integer)
 120        self * Rational.new!(a, 1)
 121      elsif a.kind_of?(Float)
 122        Float(self) * a
 123      else
 124        x , y = a.coerce(self)
 125        x * y
 126      end
 127    end
 128    
 129    def / (a)
 130      if a.kind_of?(Rational)
 131        num = @numerator * a.denominator
 132        den = @denominator * a.numerator
 133        Rational(num, den)
 134      elsif a.kind_of?(Integer)
 135        raise ZeroDivisionError, "divided by 0" if a == 0
 136        self / Rational.new!(a, 1)
 137      elsif a.kind_of?(Float)
 138        Float(self) / a
 139      else
 140        x , y = a.coerce(self)
 141        x / y
 142      end
 143    end
 144    
 145    def ** (other)
 146      if other.kind_of?(Rational)
 147        Float(self) ** other
 148      elsif other.kind_of?(Integer)
 149        if other > 0
 150          num = @numerator ** other
 151          den = @denominator ** other
 152        elsif other < 0
 153          num = @denominator ** -other
 154          den = @numerator ** -other
 155        elsif other == 0
 156          num = 1
 157          den = 1
 158        end
 159        Rational.new!(num, den)
 160      elsif other.kind_of?(Float)
 161        Float(self) ** other
 162      else
 163        x , y = other.coerce(self)
 164        x ** y
 165      end
 166    end
 167    
 168    def % (other)
 169      value = (self / other).to_i
 170      return self - other * value
 171    end
 172    
 173    def divmod(other)
 174      value = (self / other).to_i
 175      return value, self - other * value
 176    end
 177    
 178    def abs
 179      if @numerator > 0
 180        Rational.new!(@numerator, @denominator)
 181      else
 182        Rational.new!(-@numerator, @denominator)
 183      end
 184    end
 185  
 186    def <=> (other)
 187      if other.kind_of?(Rational)
 188        num = @numerator * other.denominator
 189        num_a = other.numerator * @denominator
 190        v = num - num_a
 191        if v > 0
 192          return 1
 193        elsif v < 0
 194          return  -1
 195        else
 196          return 0
 197        end
 198      elsif other.kind_of?(Integer)
 199        return self <=> Rational.new!(other, 1)
 200      elsif other.kind_of?(Float)
 201        return Float(self) <=> other
 202      else
 203        x , y = other.coerce(self)
 204        return x <=> y
 205      end
 206    end
 207  
 208    def coerce(other)
 209      if other.kind_of?(Float)
 210        return other, self.to_f
 211      elsif other.kind_of?(Integer)
 212        return Rational.new!(other, 1), self
 213      else
 214        super
 215      end
 216    end
 217  
 218    def to_i
 219      Integer(@numerator.div(@denominator))
 220    end
 221    
 222    def to_f
 223      @numerator.to_f/@denominator.to_f
 224    end
 225    
 226    def to_s
 227      if @denominator == 1
 228        @numerator.to_s
 229      else
 230        @numerator.to_s+"/"+@denominator.to_s
 231      end
 232    end
 233    
 234    def to_r
 235      self
 236    end
 237    
 238    def inspect
 239      sprintf("Rational(%s, %s)", @numerator.inspect, @denominator.inspect)
 240    end
 241    
 242    def hash
 243      @numerator.hash ^ @denominator.hash
 244    end
 245    
 246    attr :numerator
 247    attr :denominator
 248    
 249    private :initialize
 250  end
 251  
 252  class Integer
 253    def numerator
 254      self
 255    end
 256    
 257    def denomerator
 258      1
 259    end
 260    
 261    def to_r
 262      Rational(self, 1)
 263    end
 264    
 265    def gcd(n)
 266      m = self.abs
 267      n = n.abs
 268  
 269      return n if m == 0
 270      return m if n == 0
 271  
 272      b = 0
 273      while n[0] == 0 && m[0] == 0
 274        b += 1; n >>= 1; m >>= 1
 275      end
 276      m >>= 1 while m[0] == 0
 277      n >>= 1 while n[0] == 0
 278      while m != n
 279        m, n = n, m if n > m
 280        m -= n; m >>= 1 while m[0] == 0
 281      end
 282      m << b
 283    end
 284    
 285    def gcd2(int)
 286      a = self.abs
 287      b = int.abs
 288    
 289      a, b = b, a if a < b
 290    
 291      while b != 0
 292        void, a = a.divmod(b)
 293        a, b = b, a
 294      end
 295      return a
 296    end
 297  
 298    def lcm(int)
 299      a = self.abs
 300      b = int.abs
 301      gcd = a.gcd(b)
 302      (a.div(gcd)) * b
 303    end
 304    
 305    def gcdlcm(int)
 306      a = self.abs
 307      b = int.abs
 308      gcd = a.gcd(b)
 309      return gcd, (a.div(gcd)) * b
 310    end
 311    
 312  end
 313  
 314  class Fixnum
 315    alias div! /;
 316    def div(other)
 317      if other.kind_of?(Fixnum)
 318        self.div!(other)
 319      elsif other.kind_of?(Bignum)
 320        x, y = other.coerce(self)
 321        x.div!(y)
 322      else
 323        x, y = other.coerce(self)
 324        x / y
 325      end
 326    end
 327    
 328  #  alias divmod! divmod
 329    
 330    if not defined? Complex
 331      alias power! **;
 332    end
 333    
 334  #   def rdiv(other)
 335  #     if other.kind_of?(Fixnum)
 336  #       Rational(self, other)
 337  #     elsif
 338  #       x, y = other.coerce(self)
 339  #       if defined?(x.div())
 340  #       x.div(y)
 341  #       else
 342  #       x / y
 343  #       end
 344  #     end
 345    #   end
 346    
 347    def rdiv(other)
 348      Rational.new!(self,1) / other
 349    end
 350    
 351    def rpower (other)
 352      if other >= 0
 353        self.power!(other)
 354      else
 355        Rational.new!(self,1)**other
 356      end
 357    end
 358      
 359    if not defined? Complex
 360      alias ** rpower
 361    end
 362  end
 363  
 364  class Bignum
 365    alias div! /;
 366    alias div /;
 367    alias divmod! divmod
 368    
 369    if not defined? power!
 370      alias power! **
 371    end
 372    
 373    def rdiv(other)
 374      Rational.new!(self,1) / other
 375    end
 376    
 377    def rpower (other)
 378      if other >= 0
 379        self.power!(other)
 380      else
 381        Rational.new!(self, 1)**other
 382      end
 383    end
 384    
 385    if not defined? Complex
 386      alias ** rpower
 387    end
 388    
 389  end
 390