rubysl-rational 0.0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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