1 package com.github.mygreen.cellformatter.number;
2
3
4
5
6
7
8
9
10 public class SimpleFraction {
11
12
13 private final int denominator;
14
15
16 private final int numerator;
17
18
19
20
21
22
23 public SimpleFraction(final int numerator, final int denominator) {
24 if(denominator == 0) {
25 throw new IllegalArgumentException("denominator should not be zero.");
26 }
27
28 this.numerator = numerator;
29 this.denominator = denominator;
30 }
31
32
33
34
35
36
37
38
39 public static SimpleFraction createFractionExactDenominator(final double val, final int exactDenom){
40 int num = (int)Math.round(val*(double)exactDenom);
41 return new SimpleFraction(num,exactDenom);
42 }
43
44
45
46
47
48
49
50
51
52
53
54 public static SimpleFraction createFractionMaxDenominator(final double value, final int maxDenominator){
55 return buildFractionMaxDenominator(value, 0, maxDenominator, 100);
56 }
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 private static SimpleFraction buildFractionMaxDenominator(final double value, final double epsilon,
81 final int maxDenominator, final int maxIterations) {
82
83 final long overflow = Integer.MAX_VALUE;
84 double r0 = value;
85 long a0 = (long)Math.floor(r0);
86 if (a0 > overflow) {
87 throw new IllegalArgumentException("Overflow trying to convert "+value+" to fraction ("+a0+"/"+1l+")");
88 }
89
90
91
92 if (Math.abs(a0 - value) < epsilon) {
93 return new SimpleFraction((int)a0, 1);
94 }
95
96 long p0 = 1;
97 long q0 = 0;
98 long p1 = a0;
99 long q1 = 1;
100
101 long p2;
102 long q2;
103
104 int n = 0;
105 boolean stop = false;
106 do {
107 ++n;
108 double r1 = 1.0 / (r0 - a0);
109 long a1 = (long)Math.floor(r1);
110 p2 = (a1 * p1) + p0;
111 q2 = (a1 * q1) + q0;
112
113 if (epsilon == 0.0f && maxDenominator > 0 && Math.abs(q2) > maxDenominator &&
114 Math.abs(q1) < maxDenominator){
115
116 return new SimpleFraction((int)p1, (int)q1);
117 }
118 if ((p2 > overflow) || (q2 > overflow)) {
119 throw new RuntimeException("Overflow trying to convert "+value+" to fraction ("+p2+"/"+q2+")");
120 }
121
122 double convergent = (double)p2 / (double)q2;
123 if (n < maxIterations && Math.abs(convergent - value) > epsilon && q2 < maxDenominator) {
124 p0 = p1;
125 p1 = p2;
126 q0 = q1;
127 q1 = q2;
128 a0 = a1;
129 r0 = r1;
130 } else {
131 stop = true;
132 }
133 } while (!stop);
134
135 if (n >= maxIterations) {
136 throw new RuntimeException("Unable to convert "+value+" to fraction after "+maxIterations+" iterations");
137 }
138
139 if (q2 < maxDenominator) {
140 return new SimpleFraction((int) p2, (int)q2);
141 } else {
142 return new SimpleFraction((int)p1, (int)q1);
143 }
144
145 }
146
147
148
149
150
151
152 public int getDenominator() {
153 return denominator;
154 }
155
156
157
158
159
160
161 public int getNumerator() {
162 return numerator;
163 }
164 }