This repository was archived by the owner on Jul 24, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFracCalc.java
More file actions
165 lines (151 loc) · 4.99 KB
/
FracCalc.java
File metadata and controls
165 lines (151 loc) · 4.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// package com.gradescope.fraccalc;
import java.util.Scanner;
import java.lang.RuntimeException;
/** Fraction class that does all of the math */
class Fraction {
/** Sometimes you need to start out with nothing */
static Fraction NA = new Fraction(0, 1);
/**
* <b>Gets</b> the greatest common denominator
* @param a denominator 1
* @param b denominator 2
*/
static long gcm(int a, int b) {
// Euclidean algorithm using mod
// https://stackoverflow.com/questions/6618994/simplifying-fractions-in-java
return b == 0 ? a : Fraction.gcm(b, a % b);
}
int numerator;
int denominator;
/** Make a new fraction */
Fraction(int nu, int de) {
if (de == 0)
throw new RuntimeException("Tried to divide by zero!");
this.numerator = nu;
this.denominator = de;
if (de < 0)
this.mut_scale(-1);
// fraction times -1/-1
}
/** Scales and mutates the fraction! Does not make a new one! */
void mut_scale(int i) {
this.numerator *= i;
this.denominator *= i;
}
Fraction inverseNumerator() {
return new Fraction(this.numerator * -1, this.denominator);
}
Fraction reciprocal() {
return new Fraction(this.denominator, this.numerator);
}
public Fraction simplify() {
int gcm = (int) Fraction.gcm(this.numerator, this.denominator);
return new Fraction(this.numerator / gcm, this.denominator / gcm);
}
public String toMixedNumber() {
if (this.denominator == 1) {
// if it's a fraction like 5/1, just return 5
return Integer.toString(this.numerator);
}
if (Math.abs(this.numerator) > this.denominator) {
// for stuff like -10 / 2 or 10 / 2
String whole = Integer.toString((int) Math.floor(this.numerator / this.denominator));
String frac = new Fraction(Math.abs(this.numerator % this.denominator),
// why Math.abs? because we don't want -2_-2/3 or something
this.denominator).toString();
if (!(frac.equals(""))) {
whole += "_" + frac;
// if there's no fractional counterpart after converting to mixed number
}
return whole;
}
// otherwise just return the toString
return this.toString();
}
@Override
public String toString() {
return this.numerator + "/" + this.denominator;
}
}
/** Since Java doesn't have namespaces... */
interface Operator {
static Fraction add(Fraction left, Fraction right) {
return new Fraction(
left.numerator * right.denominator + right.numerator * left.denominator,
left.denominator * right.denominator
);
}
static Fraction multiply(Fraction left, Fraction right) {
return new Fraction(
left.numerator * right.numerator,
left.denominator * right.denominator
);
}
}
public class FracCalc {
/** Main is only if this file is used as a command line thingie */
public static void main(String[] a) {
Scanner console = new Scanner(System.in);
while (true) {
System.out.print("$ ");
String input = console.nextLine();
if (input.matches("[qQeE]|quit|exit")) {
console.close();
System.exit(0);
}
System.out.println(produceAnswer(input));
}
}
/** Solves an expression */
public static String produceAnswer(String input) {
System.out.println("inputted: " + input);
String[] leftCenterRight = input.split(" ");
Fraction computedFraction;
if (leftCenterRight.length == 1) {
computedFraction = parseSide(leftCenterRight[0]);
} else {
Fraction left = parseSide(leftCenterRight[0]);
String center = leftCenterRight[1];
Fraction right = parseSide(leftCenterRight[2]);
if (center.length() != 1) {
throw new RuntimeException("The operand must be of length 1!");
}
switch (center.charAt(0)) {
case '+':
computedFraction = Operator.add(left, right);
break;
case '-':
computedFraction = Operator.add(left, right.inverseNumerator());
break;
case '*':
computedFraction = Operator.multiply(left, right);
break;
case '/':
computedFraction = Operator.multiply(left, right.reciprocal());
break;
default:
return "Confused!";
}
}
return computedFraction.simplify().toMixedNumber();
}
/** It parses something like 1_1/3 */
static Fraction parseSide(String input) {
String[] parts = input.split("[/_]");
if (input.contains("_")) {
// mixed number
int wholeNumber = Integer.parseInt(parts[0]);
int numerator = Integer.parseInt(parts[1]) * (wholeNumber < 0 ? -1 : 1);
// that last bit with the ternary operator is Math.sign basically
int denominator = Integer.parseInt(parts[2]);
return new Fraction(wholeNumber * denominator + numerator, denominator);
// 5_1/3 is (5 * 3) + 1 / 3
}
if (input.contains("/")) {
int numerator = Integer.parseInt(parts[0]);
int denominator = Integer.parseInt(parts[1]);
return new Fraction(numerator, denominator);
}
return new Fraction(Integer.parseInt(input), 1);
}
}