Class: Fractify::Fraction

Inherits:
Object
  • Object
show all
Defined in:
lib/fractify/fraction.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(whole_part: 0, numerator: 0, denominator: 1, string: '', numeric: false) ⇒ Fraction

Returns a new instance of Fraction.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/fractify/fraction.rb', line 10

def initialize(whole_part: 0, numerator: 0, denominator: 1, string: '', numeric: false)
  unless string.strip.empty?
    to_zero!
    parse_fraction_string!(string)
    return
  end

  if numeric.is_a? Numeric
    convert_number!(numeric)
    return
  end
  raise DividingByZeroError if denominator.zero? && numerator != 0

  self.whole_part = whole_part
  self.numerator = numerator
  self.denominator = denominator
  self.negative = false

  fix_negativity!
  simplify!
  to_improper!
end

Instance Attribute Details

#denominatorObject

Returns the value of attribute denominator.



8
9
10
# File 'lib/fractify/fraction.rb', line 8

def denominator
  @denominator
end

#negativeObject

Returns the value of attribute negative.



8
9
10
# File 'lib/fractify/fraction.rb', line 8

def negative
  @negative
end

#numeratorObject

Returns the value of attribute numerator.



8
9
10
# File 'lib/fractify/fraction.rb', line 8

def numerator
  @numerator
end

#whole_partObject

Returns the value of attribute whole_part.



8
9
10
# File 'lib/fractify/fraction.rb', line 8

def whole_part
  @whole_part
end

Class Method Details

.floating_point_part(number) ⇒ Object



255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/fractify/fraction.rb', line 255

def self.floating_point_part(number)
  raise IncorrectArgumentsError unless number.is_a? Numeric

  result = '0.'
  number_string = number.to_s
  past_decimal_separator = false

  number_string.each_char do |c|
    if past_decimal_separator
      result += c
    elsif c == '.'
      past_decimal_separator = true
    end
  end

  result.to_f
end

.greatest_common_divisor(first, second) ⇒ Object



279
280
281
282
283
# File 'lib/fractify/fraction.rb', line 279

def self.greatest_common_divisor(first, second)
  return first if second.zero?

  greatest_common_divisor(second, first % second)
end

.least_common_multiple(first, second) ⇒ Object



273
274
275
276
277
# File 'lib/fractify/fraction.rb', line 273

def self.least_common_multiple(first, second)
  raise IncorrectArgumentsError unless first.is_a?(Numeric) && second.is_a?(Numeric)

  (first * second) / greatest_common_divisor(first, second)
end

.letter?(char) ⇒ Boolean



289
290
291
# File 'lib/fractify/fraction.rb', line 289

def self.letter?(char)
  char =~ /[[:alpha:]]/
end

.numeric?(char) ⇒ Boolean



285
286
287
# File 'lib/fractify/fraction.rb', line 285

def self.numeric?(char)
  char =~ /[[:digit:]]/
end

.valid?(string) ⇒ Boolean



249
250
251
252
253
# File 'lib/fractify/fraction.rb', line 249

def self.valid?(string)
  return false unless string.is_a? String

  validate_fraction_string(string)
end

.validate_float_string(string) ⇒ Object



386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
# File 'lib/fractify/fraction.rb', line 386

def self.validate_float_string(string)
  open_bracket, incorrect_syntax, at_end, digit_present,
  floating_point_present = false
  minus_is_free = true

  string.each_char do |c|
    if at_end || letter?(c)
      incorrect_syntax = true
      break
    end

    if open_bracket
      if c == '-'
        if !minus_is_free || digit_present
          incorrect_syntax = true
          break
        end
        minus_is_free = false
      elsif numeric?(c)
        digit_present = true
      elsif c == '.'
        if floating_point_present || !digit_present
          incorrect_syntax = true
          break
        end
        floating_point_present = true
      elsif c == ')'
        open_bracket = false
        at_end = true
      else
        incorrect_syntax = true
        break
      end
    elsif c == '('
      open_bracket = true
    else
      incorrect_syntax = true
      break
    end
  end

  incorrect_syntax = true if open_bracket

  !incorrect_syntax
end

.validate_fraction_string(string) ⇒ Object



293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# File 'lib/fractify/fraction.rb', line 293

def self.validate_fraction_string(string)
  is_float = false
  string.each_char do |c|
    if c == '.'
      is_float = true
      break
    end
  end

  if is_float
    validate_float_string(string)
  else
    validate_string(string)
  end
end

.validate_string(string) ⇒ Object



309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
# File 'lib/fractify/fraction.rb', line 309

def self.validate_string(string)
  stage = 0
  open_bracket, incorrect_syntax, at_end, digit_present = false
  minus_is_free = true

  string.each_char do |c|
    if at_end || letter?(c)
      incorrect_syntax = true
      break
    end

    if open_bracket
      if stage.zero?
        if c == '-' && minus_is_free
          minus_is_free = false
        elsif numeric?(c)
          digit_present = true
        elsif c == ' ' && digit_present
          stage = 1
          minus_is_free = true
          digit_present = false
        elsif c == '/' && digit_present
          stage = 2
          minus_is_free = true
          digit_present = false
        elsif c == ')' && digit_present
        else
          incorrect_syntax = true
          break
        end
      elsif stage == 1
        if c == '-' && minus_is_free
          minus_is_free = false
        elsif numeric?(c)
          digit_present = true
        elsif c == '/' && digit_present
          stage = 2
          minus_is_free = true
          digit_present
        else
          incorrect_syntax = true
          break
        end
      elsif stage == 2
        if c == '-' && minus_is_free
          minus_is_free = false
        elsif numeric?(c)
          digit_present = true
        elsif c == ')' && digit_present
        else
          incorrect_syntax = true
          break
        end
      end
    end

    if c == '('
      if open_bracket
        incorrect_syntax = true
        break
      end
      open_bracket = true
    elsif c == ')'
      unless open_bracket
        incorrect_syntax = true
        break
      end
      open_bracket = false
      at_end = true
    end
  end

  incorrect_syntax = true if open_bracket

  !incorrect_syntax
end

Instance Method Details

#*(other) ⇒ Object



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/fractify/fraction.rb', line 194

def *(other)
  check_argument(other)

  fraction = dup
  object = if other.is_a? Numeric
             Fractify::Fraction.new(numeric: other)
           else
             other.dup
           end

  fraction.to_improper!
  object.to_improper!

  negative_counter = 0
  negative_counter += 1 if fraction.negative?
  negative_counter += 1 if object.negative?
  fraction.negative = negative_counter.even? ? false : true

  fraction.numerator *= object.numerator
  fraction.denominator *= object.denominator

  fraction.simplify!

  fraction.whole_part = 1 if fraction.zero?

  fraction
end

#**(other) ⇒ Object



239
240
241
242
243
244
245
246
247
# File 'lib/fractify/fraction.rb', line 239

def **(other)
  check_argument(other)
  if other.is_a? Numeric
    power(other)
  else
    x = other.to_f
    power(x)
  end
end

#+(other) ⇒ Object



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/fractify/fraction.rb', line 173

def +(other)
  check_argument(other)

  fraction = dup
  object = if other.is_a? Numeric
             Fractify::Fraction.new(numeric: other)
           else
             other.dup
           end
  fraction.to_common_denominator!(object) unless object.zero?

  fraction.minus_to_numerator!
  object.minus_to_numerator!

  fraction.numerator += object.numerator
  fraction.minus_to_negative_field!
  fraction.simplify!

  fraction
end

#-(other) ⇒ Object



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/fractify/fraction.rb', line 152

def -(other)
  check_argument(other)

  fraction = dup
  object = if other.is_a? Numeric
             Fractify::Fraction.new(numeric: other)
           else
             other.dup
           end
  fraction.to_common_denominator!(object) unless object.zero?

  fraction.minus_to_numerator!
  object.minus_to_numerator!

  fraction.numerator -= object.numerator
  fraction.minus_to_negative_field!
  fraction.simplify!

  fraction
end

#/(other) ⇒ Object



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/fractify/fraction.rb', line 222

def /(other)
  check_argument(other)
  raise DividingByZeroError if other.zero?

  fraction = dup
  object = if other.is_a? Numeric
             Fractify::Fraction.new(numeric: other)
           else
             other.dup
           end

  object.to_reciprocal!
  fraction *= object

  fraction
end

#integer?Boolean



43
44
45
46
47
# File 'lib/fractify/fraction.rb', line 43

def integer?
  return true if denominator == 1 && !zero?

  false
end

#negative?Boolean



33
34
35
# File 'lib/fractify/fraction.rb', line 33

def negative?
  negative
end

#one?Boolean



49
50
51
52
53
# File 'lib/fractify/fraction.rb', line 49

def one?
  return true if numerator == 1 && denominator == 1 && whole_part.zero?

  false
end

#putsObject



97
98
99
# File 'lib/fractify/fraction.rb', line 97

def puts
  puts to_s
end

#simplify!Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/fractify/fraction.rb', line 55

def simplify!
  return true if integer?

  if zero?
    @denominator = 1
    @whole_part = 0
    @negative = false
  else
    greatest_common_divisor = self.class.greatest_common_divisor(numerator, denominator)

    @denominator /= greatest_common_divisor
    @numerator /= greatest_common_divisor
  end

  true
end

#to_common_denominator!(other) ⇒ Object



432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
# File 'lib/fractify/fraction.rb', line 432

def to_common_denominator!(other)
  to_improper!
  other.to_improper!

  least_common_multiple = self.class.least_common_multiple(denominator, other.denominator)

  numerator_multiplication = least_common_multiple / denominator
  @numerator *= numerator_multiplication
  @denominator = least_common_multiple

  numerator_multiplication = least_common_multiple / other.denominator
  other.numerator *= numerator_multiplication
  other.denominator = least_common_multiple

  true
end

#to_fObject



110
111
112
113
114
115
116
117
118
# File 'lib/fractify/fraction.rb', line 110

def to_f
  return 0.0 if zero?

  fraction = dup
  fraction.to_improper!
  fraction.minus_to_numerator!

  fraction.numerator.to_f / fraction.denominator
end

#to_iObject



120
121
122
123
124
125
126
127
128
129
# File 'lib/fractify/fraction.rb', line 120

def to_i
  return 0 if zero?
  fraction = dup
  fraction.to_proper_fraction!

  result = fraction.whole_part
  result = -result if fraction.negative?

  result
end

#to_improper!Object



87
88
89
90
91
92
93
94
95
# File 'lib/fractify/fraction.rb', line 87

def to_improper!
  return true if whole_part.zero?

  @numerator -= 1 if numerator == 1 && denominator == 1
  @numerator += whole_part * denominator
  @whole_part = 0

  true
end

#to_proper_fraction!Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/fractify/fraction.rb', line 72

def to_proper_fraction!
  return true if zero?

  if denominator == 1 && numerator != 1
    @whole_part += numerator
    @numerator = 1
  elsif numerator > denominator
    new_whole_part = numerator / denominator
    @whole_part += new_whole_part
    @numerator %= denominator
  end

  true
end

#to_reciprocal!Object



449
450
451
452
453
454
455
456
# File 'lib/fractify/fraction.rb', line 449

def to_reciprocal!
  to_improper!
  aux = denominator
  @denominator = numerator
  @numerator = aux

  true
end

#to_s(improper = false) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/fractify/fraction.rb', line 131

def to_s(improper = false)
  fraction = dup
  fraction.to_proper_fraction! unless improper
  fraction_string = '('
  fraction_string += '-' if negative?

  if fraction.zero?
    fraction_string += '0'
  elsif fraction.one?
    fraction_string += '1'
  else
    fraction_string += fraction.whole_part.to_s if fraction.whole_part != 0
    if fraction.numerator != 1 || fraction.denominator != 1
      fraction_string += ' ' if fraction.whole_part != 0
      fraction_string += fraction.numerator.to_s + '/' + fraction.denominator.to_s
    end
  end

  fraction_string + ')'
end

#to_zero!Object



101
102
103
104
105
106
107
108
# File 'lib/fractify/fraction.rb', line 101

def to_zero!
  @whole_part = 0
  @numerator = 0
  @denominator = 1
  @negative = false

  true
end

#zero?Boolean



37
38
39
40
41
# File 'lib/fractify/fraction.rb', line 37

def zero?
  return true if numerator.zero?

  false
end