rubysl-rational 0.0.1 → 1.0.0

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: 6d97dd5bf85e7b762cfdc4c32a3b49a7eafad136
4
+ data.tar.gz: b3f2880fd75ab9be870b6734c1a215f66bb62dfc
5
+ SHA512:
6
+ metadata.gz: 565531733759d1ec62f50bcf53131c863ebcb6ccce6c60d88829b0e9b2f56e10ed3c42057268f1db7e2665ee72b6f4b1cf55101fd1acfe975f440f6e2ee6939b
7
+ data.tar.gz: cfd2afa8e6d0f4e4a6032903a8ffc6edf948bcf35e94f58b12b3fda81e8cd7492cde2f8cdcc36a25a0192d2b038f88a029bceae8d1b74a41fbc86efcb06e01c8
data/.gitignore CHANGED
@@ -15,4 +15,3 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
- .rbx
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ env:
3
+ - RUBYLIB=lib
4
+ script: bundle exec mspec
5
+ rvm:
6
+ - 1.8.7
7
+ - rbx-nightly-18mode
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # RubySL::Rational
1
+ # Rubysl::Rational
2
2
 
3
3
  TODO: Write a gem description
4
4
 
@@ -24,6 +24,6 @@ TODO: Write usage instructions here
24
24
 
25
25
  1. Fork it
26
26
  2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Added some feature'`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
28
  4. Push to the branch (`git push origin my-new-feature`)
29
29
  5. Create new Pull Request
data/Rakefile CHANGED
@@ -1,2 +1 @@
1
- #!/usr/bin/env rake
2
1
  require "bundler/gem_tasks"
data/lib/rational.rb ADDED
@@ -0,0 +1 @@
1
+ require "rubysl/rational"
@@ -0,0 +1,2 @@
1
+ require "rubysl/rational/version"
2
+ require "rubysl/rational/rational"
@@ -0,0 +1,562 @@
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
+ # Documentation by Kevin Jackson and Gavin Sinclair.
9
+ #
10
+ # When you <tt>require 'rational'</tt>, all interactions between numbers
11
+ # potentially return a rational result. For example:
12
+ #
13
+ # 1.quo(2) # -> 0.5
14
+ # require 'rational'
15
+ # 1.quo(2) # -> Rational(1,2)
16
+ #
17
+ # See Rational for full documentation.
18
+ #
19
+
20
+
21
+ #
22
+ # Creates a Rational number (i.e. a fraction). +a+ and +b+ should be Integers:
23
+ #
24
+ # Rational(1,3) # -> 1/3
25
+ #
26
+ # Note: trying to construct a Rational with floating point or real values
27
+ # produces errors:
28
+ #
29
+ # Rational(1.1, 2.3) # -> NoMethodError
30
+ #
31
+ def Rational(a, b = 1)
32
+ if a.kind_of?(Rational) && b == 1
33
+ a
34
+ else
35
+ Rational.reduce(a, b)
36
+ end
37
+ end
38
+
39
+ #
40
+ # Rational implements a rational class for numbers.
41
+ #
42
+ # <em>A rational number is a number that can be expressed as a fraction p/q
43
+ # where p and q are integers and q != 0. A rational number p/q is said to have
44
+ # numerator p and denominator q. Numbers that are not rational are called
45
+ # irrational numbers.</em> (http://mathworld.wolfram.com/RationalNumber.html)
46
+ #
47
+ # To create a Rational Number:
48
+ # Rational(a,b) # -> a/b
49
+ # Rational.new!(a,b) # -> a/b
50
+ #
51
+ # Examples:
52
+ # Rational(5,6) # -> 5/6
53
+ # Rational(5) # -> 5/1
54
+ #
55
+ # Rational numbers are reduced to their lowest terms:
56
+ # Rational(6,10) # -> 3/5
57
+ #
58
+ # But not if you use the unusual method "new!":
59
+ # Rational.new!(6,10) # -> 6/10
60
+ #
61
+ # Division by zero is obviously not allowed:
62
+ # Rational(3,0) # -> ZeroDivisionError
63
+ #
64
+ class Rational < Numeric
65
+ @RCS_ID='-$Id: rational.rb,v 1.7 1999/08/24 12:49:28 keiju Exp keiju $-'
66
+
67
+ #
68
+ # Reduces the given numerator and denominator to their lowest terms. Use
69
+ # Rational() instead.
70
+ #
71
+ def Rational.reduce(num, den = 1)
72
+ raise ZeroDivisionError, "denominator is zero" if den == 0
73
+
74
+ if den < 0
75
+ num = -num
76
+ den = -den
77
+ end
78
+ gcd = num.gcd(den)
79
+ num = num.div(gcd)
80
+ den = den.div(gcd)
81
+ if den == 1 && defined?(Unify)
82
+ num
83
+ else
84
+ new!(num, den)
85
+ end
86
+ end
87
+
88
+ #
89
+ # Implements the constructor. This method does not reduce to lowest terms or
90
+ # check for division by zero. Therefore #Rational() should be preferred in
91
+ # normal use.
92
+ #
93
+ def Rational.new!(num, den = 1)
94
+ new(num, den)
95
+ end
96
+
97
+ private_class_method :new
98
+
99
+ #
100
+ # This method is actually private.
101
+ #
102
+ def initialize(num, den)
103
+ if den < 0
104
+ num = -num
105
+ den = -den
106
+ end
107
+ if num.kind_of?(Integer) and den.kind_of?(Integer)
108
+ @numerator = num
109
+ @denominator = den
110
+ else
111
+ @numerator = num.to_i
112
+ @denominator = den.to_i
113
+ end
114
+ end
115
+
116
+ #
117
+ # Returns the addition of this value and +a+.
118
+ #
119
+ # Examples:
120
+ # r = Rational(3,4) # -> Rational(3,4)
121
+ # r + 1 # -> Rational(7,4)
122
+ # r + 0.5 # -> 1.25
123
+ #
124
+ def + (a)
125
+ if a.kind_of?(Rational)
126
+ num = @numerator * a.denominator
127
+ num_a = a.numerator * @denominator
128
+ Rational(num + num_a, @denominator * a.denominator)
129
+ elsif a.kind_of?(Integer)
130
+ self + Rational.new!(a, 1)
131
+ elsif a.kind_of?(Float)
132
+ Float(self) + a
133
+ else
134
+ x, y = a.coerce(self)
135
+ x + y
136
+ end
137
+ end
138
+
139
+ #
140
+ # Returns the difference of this value and +a+.
141
+ # subtracted.
142
+ #
143
+ # Examples:
144
+ # r = Rational(3,4) # -> Rational(3,4)
145
+ # r - 1 # -> Rational(-1,4)
146
+ # r - 0.5 # -> 0.25
147
+ #
148
+ def - (a)
149
+ if a.kind_of?(Rational)
150
+ num = @numerator * a.denominator
151
+ num_a = a.numerator * @denominator
152
+ Rational(num - num_a, @denominator*a.denominator)
153
+ elsif a.kind_of?(Integer)
154
+ self - Rational.new!(a, 1)
155
+ elsif a.kind_of?(Float)
156
+ Float(self) - a
157
+ else
158
+ x, y = a.coerce(self)
159
+ x - y
160
+ end
161
+ end
162
+
163
+ #
164
+ # Returns the product of this value and +a+.
165
+ #
166
+ # Examples:
167
+ # r = Rational(3,4) # -> Rational(3,4)
168
+ # r * 2 # -> Rational(3,2)
169
+ # r * 4 # -> Rational(3,1)
170
+ # r * 0.5 # -> 0.375
171
+ # r * Rational(1,2) # -> Rational(3,8)
172
+ #
173
+ def * (a)
174
+ if a.kind_of?(Rational)
175
+ num = @numerator * a.numerator
176
+ den = @denominator * a.denominator
177
+ Rational(num, den)
178
+ elsif a.kind_of?(Integer)
179
+ self * Rational.new!(a, 1)
180
+ elsif a.kind_of?(Float)
181
+ Float(self) * a
182
+ else
183
+ x, y = a.coerce(self)
184
+ x * y
185
+ end
186
+ end
187
+
188
+ #
189
+ # Returns the quotient of this value and +a+.
190
+ # r = Rational(3,4) # -> Rational(3,4)
191
+ # r / 2 # -> Rational(3,8)
192
+ # r / 2.0 # -> 0.375
193
+ # r / Rational(1,2) # -> Rational(3,2)
194
+ #
195
+ def / (a)
196
+ if a.kind_of?(Rational)
197
+ num = @numerator * a.denominator
198
+ den = @denominator * a.numerator
199
+ Rational(num, den)
200
+ elsif a.kind_of?(Integer)
201
+ raise ZeroDivisionError, "division by zero" if a == 0
202
+ self / Rational.new!(a, 1)
203
+ elsif a.kind_of?(Float)
204
+ Float(self) / a
205
+ else
206
+ x, y = a.coerce(self)
207
+ x / y
208
+ end
209
+ end
210
+
211
+ #
212
+ # Returns this value raised to the given power.
213
+ #
214
+ # Examples:
215
+ # r = Rational(3,4) # -> Rational(3,4)
216
+ # r ** 2 # -> Rational(9,16)
217
+ # r ** 2.0 # -> 0.5625
218
+ # r ** Rational(1,2) # -> 0.866025403784439
219
+ #
220
+ def ** (other)
221
+ if other.kind_of?(Rational)
222
+ Float(self) ** other
223
+ elsif other.kind_of?(Integer)
224
+ if other > 0
225
+ num = @numerator ** other
226
+ den = @denominator ** other
227
+ elsif other < 0
228
+ num = @denominator ** -other
229
+ den = @numerator ** -other
230
+ elsif other == 0
231
+ num = 1
232
+ den = 1
233
+ end
234
+ Rational.new!(num, den)
235
+ elsif other.kind_of?(Float)
236
+ Float(self) ** other
237
+ else
238
+ x, y = other.coerce(self)
239
+ x ** y
240
+ end
241
+ end
242
+
243
+ def div(other)
244
+ (self / other).floor
245
+ end
246
+
247
+ #
248
+ # Returns the remainder when this value is divided by +other+.
249
+ #
250
+ # Examples:
251
+ # r = Rational(7,4) # -> Rational(7,4)
252
+ # r % Rational(1,2) # -> Rational(1,4)
253
+ # r % 1 # -> Rational(3,4)
254
+ # r % Rational(1,7) # -> Rational(1,28)
255
+ # r % 0.26 # -> 0.19
256
+ #
257
+ def % (other)
258
+ value = (self / other).floor
259
+ return self - other * value
260
+ end
261
+
262
+ #
263
+ # Returns the quotient _and_ remainder.
264
+ #
265
+ # Examples:
266
+ # r = Rational(7,4) # -> Rational(7,4)
267
+ # r.divmod Rational(1,2) # -> [3, Rational(1,4)]
268
+ #
269
+ def divmod(other)
270
+ value = (self / other).floor
271
+ return value, self - other * value
272
+ end
273
+
274
+ #
275
+ # Returns the absolute value.
276
+ #
277
+ def abs
278
+ if @numerator > 0
279
+ self
280
+ else
281
+ Rational.new!(-@numerator, @denominator)
282
+ end
283
+ end
284
+
285
+ #
286
+ # Returns +true+ iff this value is numerically equal to +other+.
287
+ #
288
+ # But beware:
289
+ # Rational(1,2) == Rational(4,8) # -> true
290
+ # Rational(1,2) == Rational.new!(4,8) # -> false
291
+ #
292
+ # Don't use Rational.new!
293
+ #
294
+ def == (other)
295
+ if other.kind_of?(Rational)
296
+ @numerator == other.numerator and @denominator == other.denominator
297
+ elsif other.kind_of?(Integer)
298
+ self == Rational.new!(other, 1)
299
+ elsif other.kind_of?(Float)
300
+ Float(self) == other
301
+ else
302
+ other == self
303
+ end
304
+ end
305
+
306
+ #
307
+ # Standard comparison operator.
308
+ #
309
+ def <=> (other)
310
+ if other.kind_of?(Rational)
311
+ num = @numerator * other.denominator
312
+ num_a = other.numerator * @denominator
313
+ v = num - num_a
314
+ if v > 0
315
+ return 1
316
+ elsif v < 0
317
+ return -1
318
+ else
319
+ return 0
320
+ end
321
+ elsif other.kind_of?(Integer)
322
+ return self <=> Rational.new!(other, 1)
323
+ elsif other.kind_of?(Float)
324
+ return Float(self) <=> other
325
+ elsif defined? other.coerce
326
+ x, y = other.coerce(self)
327
+ return x <=> y
328
+ else
329
+ return nil
330
+ end
331
+ end
332
+
333
+ def coerce(other)
334
+ if other.kind_of?(Float)
335
+ return other, self.to_f
336
+ elsif other.kind_of?(Integer)
337
+ return Rational.new!(other, 1), self
338
+ else
339
+ super
340
+ end
341
+ end
342
+
343
+ #
344
+ # Converts the rational to an Integer. Not the _nearest_ integer, the
345
+ # truncated integer. Study the following example carefully:
346
+ # Rational(+7,4).to_i # -> 1
347
+ # Rational(-7,4).to_i # -> -1
348
+ # (-1.75).to_i # -> -1
349
+ #
350
+ # In other words:
351
+ # Rational(-7,4) == -1.75 # -> true
352
+ # Rational(-7,4).to_i == (-1.75).to_i # -> true
353
+ #
354
+
355
+ def floor
356
+ @numerator.div(@denominator)
357
+ end
358
+
359
+ def ceil
360
+ -((-@numerator).div(@denominator))
361
+ end
362
+
363
+ def truncate
364
+ if @numerator < 0
365
+ return -((-@numerator).div(@denominator))
366
+ end
367
+ @numerator.div(@denominator)
368
+ end
369
+
370
+ alias_method :to_i, :truncate
371
+
372
+ def round
373
+ if @numerator < 0
374
+ num = -@numerator
375
+ num = num * 2 + @denominator
376
+ den = @denominator * 2
377
+ -(num.div(den))
378
+ else
379
+ num = @numerator * 2 + @denominator
380
+ den = @denominator * 2
381
+ num.div(den)
382
+ end
383
+ end
384
+
385
+ #
386
+ # Converts the rational to a Float.
387
+ #
388
+ def to_f
389
+ @numerator.to_f/@denominator.to_f
390
+ end
391
+
392
+ #
393
+ # Returns a string representation of the rational number.
394
+ #
395
+ # Example:
396
+ # Rational(3,4).to_s # "3/4"
397
+ # Rational(8).to_s # "8"
398
+ #
399
+ def to_s
400
+ if @denominator == 1
401
+ @numerator.to_s
402
+ else
403
+ @numerator.to_s+"/"+@denominator.to_s
404
+ end
405
+ end
406
+
407
+ #
408
+ # Returns +self+.
409
+ #
410
+ def to_r
411
+ self
412
+ end
413
+
414
+ #
415
+ # Returns a reconstructable string representation:
416
+ #
417
+ # Rational(5,8).inspect # -> "Rational(5, 8)"
418
+ #
419
+ def inspect
420
+ sprintf("Rational(%s, %s)", @numerator.inspect, @denominator.inspect)
421
+ end
422
+
423
+ #
424
+ # Returns a hash code for the object.
425
+ #
426
+ def hash
427
+ @numerator.hash ^ @denominator.hash
428
+ end
429
+
430
+ attr :numerator
431
+ attr :denominator
432
+
433
+ private :initialize
434
+ end
435
+
436
+ class Integer
437
+ #
438
+ # In an integer, the value _is_ the numerator of its rational equivalent.
439
+ # Therefore, this method returns +self+.
440
+ #
441
+ def numerator
442
+ self
443
+ end
444
+
445
+ #
446
+ # In an integer, the denominator is 1. Therefore, this method returns 1.
447
+ #
448
+ def denominator
449
+ 1
450
+ end
451
+
452
+ #
453
+ # Returns a Rational representation of this integer.
454
+ #
455
+ def to_r
456
+ Rational(self, 1)
457
+ end
458
+
459
+ #
460
+ # Returns the <em>greatest common denominator</em> of the two numbers (+self+
461
+ # and +n+).
462
+ #
463
+ # Examples:
464
+ # 72.gcd 168 # -> 24
465
+ # 19.gcd 36 # -> 1
466
+ #
467
+ # The result is positive, no matter the sign of the arguments.
468
+ #
469
+ def gcd(other)
470
+ min = self.abs
471
+ max = other.abs
472
+ while min > 0
473
+ tmp = min
474
+ min = max % min
475
+ max = tmp
476
+ end
477
+ max
478
+ end
479
+
480
+ #
481
+ # Returns the <em>lowest common multiple</em> (LCM) of the two arguments
482
+ # (+self+ and +other+).
483
+ #
484
+ # Examples:
485
+ # 6.lcm 7 # -> 42
486
+ # 6.lcm 9 # -> 18
487
+ #
488
+ def lcm(other)
489
+ if self.zero? or other.zero?
490
+ 0
491
+ else
492
+ (self.div(self.gcd(other)) * other).abs
493
+ end
494
+ end
495
+
496
+ #
497
+ # Returns the GCD _and_ the LCM (see #gcd and #lcm) of the two arguments
498
+ # (+self+ and +other+). This is more efficient than calculating them
499
+ # separately.
500
+ #
501
+ # Example:
502
+ # 6.gcdlcm 9 # -> [3, 18]
503
+ #
504
+ def gcdlcm(other)
505
+ gcd = self.gcd(other)
506
+ if self.zero? or other.zero?
507
+ [gcd, 0]
508
+ else
509
+ [gcd, (self.div(gcd) * other).abs]
510
+ end
511
+ end
512
+ end
513
+
514
+ class Fixnum
515
+ remove_method :quo
516
+
517
+ # If Rational is defined, returns a Rational number instead of a Fixnum.
518
+ def quo(other)
519
+ Rational.new!(self, 1) / other
520
+ end
521
+ alias rdiv quo
522
+
523
+ # Returns a Rational number if the result is in fact rational (i.e. +other+ < 0).
524
+ def rpower (other)
525
+ if other >= 0
526
+ self.power!(other)
527
+ else
528
+ Rational.new!(self, 1)**other
529
+ end
530
+ end
531
+ end
532
+
533
+ class Bignum
534
+ remove_method :quo
535
+
536
+ # If Rational is defined, returns a Rational number instead of a Float.
537
+ def quo(other)
538
+ Rational.new!(self, 1) / other
539
+ end
540
+ alias rdiv quo
541
+
542
+ # Returns a Rational number if the result is in fact rational (i.e. +other+ < 0).
543
+ def rpower (other)
544
+ if other >= 0
545
+ self.power!(other)
546
+ else
547
+ Rational.new!(self, 1)**other
548
+ end
549
+ end
550
+ end
551
+
552
+ unless 1.respond_to?(:power!)
553
+ class Fixnum
554
+ alias_method :power!, :"**"
555
+ alias_method :"**", :rpower
556
+ end
557
+
558
+ class Bignum
559
+ alias_method :power!, :"**"
560
+ alias_method :"**", :rpower
561
+ end
562
+ end