time_value 0.1.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b8d062fe004503ddf10aa4868b97ae5de157d066
4
- data.tar.gz: 1bb4988314cb5add83dc1961c433e69933b93bdf
3
+ metadata.gz: 0c6e6b94a394a16cbd8e93aa1af3110fccff9377
4
+ data.tar.gz: 032d98858c34aa563b7d1e7a1407c9fefd6673d7
5
5
  SHA512:
6
- metadata.gz: e9af1844641632a746306d97b8739f08c51ac39fb32934c98c6037a546af7aab600da7cd51ee0806c6ea6dd2822f1a870c1009e36d1521fe9548852f3138e250
7
- data.tar.gz: df779a51ed6d53b9192c33a0fd9f8fda36e5cdd7ddf65d6715d47a99497c95d01e9820e8d6bc8b74b669683154f79ea5652566942bba3d320593ff0a6f4954a4
6
+ metadata.gz: db23d74db7237412e2bc019cfa4859b1239db26d32fabcb1bdd4ebd3dc7b789d7916e5f93d9702fe92f877ad6b26b106e37d95ca77346fe24d8b7c65c7d03be4
7
+ data.tar.gz: 2561d85d74677bbc4a3e77d37716bc8573219e5fb047494e4d632a00e51402b567b6544232b84f3cb7bf41782de4a4d4ecc9240dee7268767045ee5c48696dd0
data/lib/solver.rb CHANGED
@@ -3,20 +3,19 @@ class Solver
3
3
  INTERVAL = 10 ** (-1 * PRECISION)
4
4
  MAX_ITERATIONS = 20
5
5
  attr_reader :time_value, :goal
6
- attr_accessor :guess, :lower_bound, :upper_bound, :upper_cap_met
6
+ attr_accessor :lower_bound, :upper_bound, :upper_cap_met
7
7
 
8
- def initialize(time_value, guess = 10.00, lower_bound = 0.00, upper_bound = 10.00)
9
- @upper_bound = upper_bound
8
+ def initialize(time_value:, lower_bound: 0.00, upper_bound: nil, guess: 0.00)
9
+ @upper_bound = upper_bound || guess
10
10
  @lower_bound = lower_bound
11
- @guess = guess
12
- @time_value = time_value
11
+ @time_value = time_value.dup
12
+ @time_value.i = guess
13
13
  @goal = time_value.fv
14
14
  @upper_cap_met = false
15
15
  end
16
16
 
17
17
  def solve!
18
18
  iteration_count = 0
19
- time_value.i = guess
20
19
  while (upper_bound - lower_bound).round(PRECISION) > INTERVAL &&
21
20
  iteration_count < MAX_ITERATIONS
22
21
  iteration_count += 1
@@ -25,22 +24,33 @@ class Solver
25
24
  rescue FloatDomainError
26
25
  return nil
27
26
  end
28
- adjust_bounds(result)
29
- time_value.i = guess
27
+ adjust_bounds!(result)
28
+ time_value.i = new_guess
30
29
  end
31
- guess.round(2) if iteration_count < MAX_ITERATIONS
30
+ # TODO: This will not handle the case where the 20th iteration
31
+ # finds the solution
32
+ rate if iteration_count < MAX_ITERATIONS
32
33
  end
33
34
 
34
- def adjust_bounds(result)
35
+ private
36
+
37
+ def adjust_bounds!(result)
35
38
  if result > goal
36
39
  # interest rate too high
37
40
  self.upper_cap_met = true
38
- self.upper_bound = guess
41
+ self.upper_bound = rate
39
42
  elsif result < goal
40
43
  # interest rate too low
41
44
  self.upper_bound *= 2 unless upper_cap_met
42
- self.lower_bound = guess
45
+ self.lower_bound = rate
43
46
  end
44
- self.guess = ((upper_bound + lower_bound) / 2).round(PRECISION)
47
+ end
48
+
49
+ def new_guess
50
+ ((upper_bound + lower_bound) / 2).round(PRECISION)
51
+ end
52
+
53
+ def rate
54
+ time_value.i.round(2)
45
55
  end
46
56
  end
data/lib/time_value.rb CHANGED
@@ -1,53 +1,52 @@
1
1
  require 'solver'
2
2
 
3
3
  class TimeValue
4
-
5
- attr_accessor :n, :i, :pv, :pmt, :fv
6
-
7
- def initialize(n = 0, i = 0, pv = 0.0, pmt = 0.0, fv = 0.0)
8
- @n = n
9
- @i = i.to_f
10
- @pv = pv.to_f
11
- @pmt = pmt.to_f
12
- @fv = fv.to_f
13
- end
14
-
15
- #Base formula, ordinary annuity: -PV = [FV/((1+i)^n)] + (PMT/i)*[1-(1/(1+i)^n)]
16
- def calc_pv()
17
- i = @i / 100.0
18
- #Initial contribution
19
- pvf = @fv / ((1 + i) ** @n)
20
- #Present value of annuity
21
- pva = (@pmt/i) * (1-(1/((1+i)**@n)))
22
- @pv = (pvf + pva) * (-1)
23
- #Round
24
- @pv = (@pv*100).round / 100.0
25
- end
26
-
27
- def calc_fv()
28
- i = @i / 100.0
29
- #Growth of initial contribution
30
- fvp = @pv * ((1 + i) ** @n)
31
- #Growth of payments
32
- fva = @pmt * (((1 + i) ** @n)-1) / i
33
- @fv = (fvp + fva) * (-1)
34
- #Round
35
- @fv = (@fv*100).round / 100.0
36
- end
37
-
38
- def calc_n()
39
- i = @i / 100.0
40
- @n = (Math.log((@pmt - (i * @fv))/(@pmt + (i * @pv)))/Math.log(1 + i)).round(0)
41
- end
42
-
43
- def calc_pmt()
44
- i = @i / 100.0
45
- @pmt = (-i*(@fv+(@pv*((1+i)**n))))/(((1+i)**n)-1)
46
- @pmt = (@pmt*100).round / 100.0
47
- end
48
-
49
- def calc_i(guess = 10.0)
50
- solver = Solver.new(self, 10.00, 0.00, 10.00)
51
- solver.solve!
52
- end
4
+ attr_accessor :n, :i, :pv, :pmt, :fv
5
+
6
+ def initialize(n: 0, i: 0, pv: 0.0, pmt: 0.0, fv: 0.0)
7
+ @n = n
8
+ @i = i.to_f
9
+ @pv = pv.to_f
10
+ @pmt = pmt.to_f
11
+ @fv = fv.to_f
12
+ end
13
+
14
+ #Base formula, ordinary annuity: -PV = [FV/((1+i)^n)] + (PMT/i)*[1-(1/(1+i)^n)]
15
+ def calc_pv()
16
+ i = @i / 100.0
17
+ #Initial contribution
18
+ pvf = @fv / ((1 + i) ** @n)
19
+ #Present value of annuity
20
+ pva = (@pmt/i) * (1-(1/((1+i)**@n)))
21
+ @pv = (pvf + pva) * (-1)
22
+ #Round
23
+ @pv = (@pv*100).round / 100.0
24
+ end
25
+
26
+ def calc_fv()
27
+ i = @i / 100.0
28
+ #Growth of initial contribution
29
+ fvp = @pv * ((1 + i) ** @n)
30
+ #Growth of payments
31
+ fva = @pmt * (((1 + i) ** @n)-1) / i
32
+ @fv = (fvp + fva) * (-1)
33
+ #Round
34
+ @fv = (@fv*100).round / 100.0
35
+ end
36
+
37
+ def calc_n()
38
+ i = @i / 100.0
39
+ @n = (Math.log((@pmt - (i * @fv))/(@pmt + (i * @pv)))/Math.log(1 + i)).round(0)
40
+ end
41
+
42
+ def calc_pmt()
43
+ i = @i / 100.0
44
+ @pmt = (-i*(@fv+(@pv*((1+i)**n))))/(((1+i)**n)-1)
45
+ @pmt = (@pmt*100).round / 100.0
46
+ end
47
+
48
+ def calc_i(guess: 10.0)
49
+ solver = Solver.new(time_value: self, lower_bound: 0.00, guess: 10.00)
50
+ solver.solve!
51
+ end
53
52
  end
@@ -1,3 +1,3 @@
1
1
  module TimeValue
2
- VERSION = '0.1.2'
2
+ VERSION = '1.0.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: time_value
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Randall Reed, Jr.