001 package hw3;
002
003 /**
004 * <b>RatTerm</b> is an immutable representation of a term in a single-variable
005 * polynomial expression. The term has the form C*x^E where C is a rational
006 * number and E is an integer.
007 * <p>
008 *
009 * A RatTerm, t, can be notated by the pair (C . E), where C is the coefficient
010 * of t, and E is the exponent of t.
011 * <p>
012 *
013 * The zero RatTerm, (0 . 0), is the only RatTerm that may have a zero
014 * coefficient. For example, (0 . 7) is an invalid RatTerm and an attempt to
015 * construct such a RatTerm (through the constructor or arithmetic operations on
016 * existing RatTerms) will return the semantically equivalent RatTerm (0 . 0).
017 * For example, (1 . 7) + (-1 . 7) = (0 . 0).
018 * <p>
019 *
020 * (0 . 0), (1 . 0), (1 . 1), (1 . 3), (3/4 . 17), (7/2 . -1), and (NaN . 74)
021 * are all valid RatTerms, corresponding to the polynomial terms "0", "1", "x",
022 * "x^3", "3/4*x^17", "7/2*x^-1" and "NaN*x^74", respectively.
023 */
024 // See RatNum's documentation for a definition of "immutable".
025 public final class RatTerm {
026
027 /** Coefficient of this term. */
028 private final RatNum coeff;
029
030 /** Exponent of this term. */
031 private final int expt;
032
033 // Abstraction Function:
034 // For a given RatTerm t, "coefficient of t" is synonymous with
035 // t.coeff, and, likewise, "exponent of t" is synonymous with t.expt.
036 // All RatTerms with a zero coefficient are represented by the
037 // zero RatTerm, z, which has zero for its coefficient AND exponent.
038 //
039 // Representation Invariant:
040 // coeff != null
041 // coeff.equals(RatNum.ZERO) ==> expt == 0
042
043 /** A constant holding a Not-a-Number (NaN) value of type RatTerm */
044 public static final RatTerm NaN = new RatTerm(RatNum.NaN, 0);
045
046 /** A constant holding a zero value of type RatTerm */
047 public static final RatTerm ZERO = new RatTerm(RatNum.ZERO, 0);
048
049 /**
050 * @requires c != null
051 * @effects Constructs a new RatTerm t, with t.coeff = c, and if
052 * c.equals(RatNum.ZERO), then t.expt = 0, otherwise t.expt = e
053 */
054 public RatTerm(RatNum c, int e) {
055 if (c.equals(RatNum.ZERO)) {
056 // If coefficient is zero, must set exponent to zero.
057 coeff = RatNum.ZERO;
058 expt = 0;
059 } else {
060 coeff = c;
061 expt = e;
062 }
063 checkRep();
064 }
065
066 /**
067 * Gets the coefficient of this RatTerm.
068 *
069 * @return the coefficient of this RatTerm.
070 */
071 public RatNum getCoeff() {
072 // TODO: Fill in this method, then remove the RuntimeException
073 throw new RuntimeException("RatTerm->getCoeff() unimplemented!");
074 }
075
076 /**
077 * Gets the exponent of this RatTerm.
078 *
079 * @return the exponent of this RatTerm.
080 */
081 public int getExpt() {
082 // TODO: Fill in this method, then remove the RuntimeException
083 throw new RuntimeException("RatTerm->getExpt() unimplemented!");
084 }
085
086 /**
087 * Returns true if this RatTerm is not-a-number.
088 *
089 * @return true if and only if this has NaN as a coefficient.
090 */
091 public boolean isNaN() {
092 // TODO: Fill in this method, then remove the RuntimeException
093 throw new RuntimeException("RatTerm->isNaN() unimplemented!");
094 }
095
096 /**
097 * Returns true if this RatTerm is equal to 0.
098 *
099 * @return true if and only if this has zero as a coefficient.
100 */
101 public boolean isZero() {
102 // TODO: Fill in this method, then remove the RuntimeException
103 throw new RuntimeException("RatTerm->isZero() unimplemented!");
104 }
105
106 /**
107 * Returns the value of this RatTerm, evaluated at d.
108 *
109 * @return the value of this polynomial when evaluated at 'd'. For example,
110 * "3*x^2" evaluated at 2 is 12. if (this.isNaN() == true), return
111 * Double.NaN
112 */
113 public double eval(double d) {
114 // TODO: Fill in this method, then remove the RuntimeException
115 // Hint: You may find java.lang.Math's pow() method useful.
116 throw new RuntimeException("RatTerm->eval() unimplemented!");
117 }
118
119 /**
120 * Negation operation.
121 *
122 * @return a RatTerm equals to (-this). If this is NaN, then returns NaN.
123 */
124 public RatTerm negate() {
125 // TODO: Fill in this method, then remove the RuntimeException
126 throw new RuntimeException("RatTerm->negate() unimplemented!");
127 }
128
129 /**
130 * Addition operation.
131 *
132 * @requires arg != null
133 * @return a RatTerm equals to (this + arg). If either argument is NaN, then
134 * returns NaN.
135 * @throws IllegalArgumentException
136 * if (this.expt != arg.expt) and neither argument is zero or
137 * NaN.
138 */
139 public RatTerm add(RatTerm arg) {
140 // TODO: Fill in this method, then remove the RuntimeException
141 throw new RuntimeException("RatTerm->add() unimplemented!");
142 }
143
144 /**
145 * Subtraction operation.
146 *
147 * @requires arg != null
148 * @return a RatTerm equals to (this - arg). If either argument is NaN, then
149 * returns NaN.
150 * @throws IllegalArgumentException
151 * if (this.expt != arg.expt) and neither argument is zero or
152 * NaN.
153 */
154 public RatTerm sub(RatTerm arg) {
155 // TODO: Fill in this method, then remove the RuntimeException
156 throw new RuntimeException("RatTerm->sub() unimplemented!");
157 }
158
159 /**
160 * Multiplication operation.
161 *
162 * @requires arg != null
163 * @return a RatTerm equals to (this * arg). If either argument is NaN, then
164 * returns NaN.
165 */
166 public RatTerm mul(RatTerm arg) {
167 // TODO: Fill in this method, then remove the RuntimeException
168 throw new RuntimeException("RatTerm->mul() unimplemented!");
169 }
170
171 /**
172 * Division operation.
173 *
174 * @requires arg != null
175 * @return a RatTerm equals to (this / arg). If arg is zero, or if either
176 * argument is NaN, then returns NaN.
177 */
178 public RatTerm div(RatTerm arg) {
179 // TODO: Fill in this method, then remove the RuntimeException
180 throw new RuntimeException("RatTerm->div() unimplemented!");
181 }
182
183 /**
184 * Return the derivative of this RatTerm.
185 *
186 * @return a RatTerm that, q, such that q = dy/dx, where this == y. In other
187 * words, q is the derivative of this. If this.isNaN(), then return
188 * some q such that q.isNaN()
189 * <p>
190 * Given a term, a*x^b, the derivative of the term is: (a*b)*x^(b-1)
191 * for b > 0 and 0 for b == 0 (Do not worry about the case when b <
192 * 0. The caller of this function, RatPoly, contains a rep.
193 * invariant stating that b is never less than 0.)
194 */
195 public RatTerm differentiate() {
196 // TODO: Fill in this method, then remove the RuntimeException
197 throw new RuntimeException("RatTerm->differentiate() unimplemented!");
198 }
199
200 /**
201 * Returns the antiderivative of this RatTerm.
202 *
203 * @return a RatTerm, q, such that dq/dx = this where the constant of
204 * intergration is assumed to be 0. In other words, q is the
205 * antiderivative of this. If this.isNaN(), then return some q such
206 * that q.isNaN()
207 * <p>
208 * Given a term, a*x^b, (where b >= 0) the antiderivative of the
209 * term is: a/(b+1)*x^(b+1) (Do not worry about the case when b < 0.
210 * The caller of this function, RatPoly, contains a rep. invariant
211 * stating that b is never less than 0.)
212 */
213 public RatTerm antiDifferentiate() {
214 // TODO: Fill in this method, then remove the RuntimeException
215 throw new RuntimeException(
216 "RatTerm->antiDifferentiate() unimplemented!");
217 }
218
219 private static final RatNum ONE = new RatNum(1);
220
221 /**
222 * Returns a string representation of this RatTerm.
223 *
224 * @return A String representation of the expression represented by this.
225 * <p>
226 * There is no whitespace in the returned string.
227 * <p>
228 * If the term is itself zero, the returned string will just be "0".
229 * <p>
230 * If this.isNaN(), then the returned string will be just "NaN"
231 * <p>
232 *
233 * The string for a non-zero, non-NaN RatTerm is in the form "C*x^E" where C
234 * is a valid string representation of a RatNum (see {@link hw3.RatNum}'s
235 * toString method) and E is an integer. UNLESS: (1) the exponent E is zero,
236 * in which case T takes the form "C" (2) the exponent E is one, in which
237 * case T takes the form "C*x" (3) the coefficient C is one, in which case T
238 * takes the form "x^E" or "x" (if E is one) or "1" (if E is zero).
239 * <p>
240 * Valid example outputs include "3/2*x^2", "-1/2", "0", and "NaN".
241 */
242 @Override
243 public String toString() {
244 if (this.isNaN()) {
245 return "NaN";
246 }
247 StringBuilder output = new StringBuilder();
248 RatNum c = coeff;
249 int e = expt;
250 if (c.isNegative()) {
251 output.append("-");
252 c = c.negate();
253 }
254 if (c.equals(ONE) && e == 1) {
255 output.append("x");
256 } else if (e == 0) {
257 output.append(c.toString());
258 } else if (c.equals(ONE)) {
259 output.append("x^" + e);
260 } else if (e == 1) {
261 output.append(c.toString() + "*x");
262 } else {
263 output.append(c.toString() + "*x^" + e);
264 }
265 return output.toString();
266 }
267
268 /**
269 * Builds a new RatTerm, given a descriptive String.
270 *
271 * @requires 'termStr' is an instance of a string with no spaces that
272 * expresses a RatTerm in the form defined in the toString()
273 * method.
274 * <p>
275 *
276 * Valid inputs include "0", "x", and "-5/3*x^3", and "NaN".
277 *
278 * @return a RatTerm t such that t.toString() = termStr
279 */
280 public static RatTerm valueOf(String termStr) {
281
282 if (termStr.equals("NaN")) {
283 return NaN;
284 }
285
286 // Term is: "R" or "R*x" or "R*x^N" or "x^N" or "x",
287 // where R is a rational num and N is an integer.
288
289 // First we parse the coefficient
290 int multIndex = termStr.indexOf("*");
291 RatNum coeff = null;
292 if (multIndex == -1) {
293 // "R" or "x^N" or "x"
294 int xIndex = termStr.indexOf("x");
295 if (xIndex == -1) {
296 // "R"
297 coeff = RatNum.valueOf(termStr);
298 } else {
299 int negIndex = termStr.indexOf("-");
300 // "x^N" or "x" ==> coeff = 1
301 if (negIndex == -1) {
302 coeff = new RatNum(1);
303 }
304 // "-x^N" or "-x" ==> coeff = -1
305 else if (negIndex == 0) {
306 coeff = new RatNum(-1);
307 } else {
308 throw new RuntimeException(
309 "Minus sign, '-', not allowed in the middle of input string: "
310 + termStr);
311 }
312 }
313 } else {
314 // "R*x" or "R*x^N"
315 coeff = RatNum.valueOf(termStr.substring(0, multIndex));
316 }
317
318 // Second we parse the exponent
319 int powIndex = termStr.indexOf("^");
320 int expt;
321 if (powIndex == -1) {
322 // "R" or "R*x" or "x"
323 int xIndex = termStr.indexOf("x");
324 if (xIndex == -1) {
325 // "R"
326 expt = 0;
327 } else {
328 // "R*x" or "x"
329 expt = 1;
330 }
331 } else {
332 // "R*x^N" or "x^N"
333 expt = Integer.parseInt(termStr.substring(powIndex + 1));
334 }
335 return new RatTerm(coeff, expt);
336 }
337
338 /**
339 * Standard hashCode function.
340 *
341 * @return an int that all objects equal to this will also.
342 */
343 @Override
344 public int hashCode() {
345 if (this.isNaN()) {
346 return 0;
347 }
348 return coeff.hashCode() * 7 + expt * 43;
349 }
350
351 /**
352 * Standard equality operation.
353 *
354 * @return true iff 'obj' is an instance of a RatTerm and 'this' and 'obj'
355 * represent the same RatTerm. Note that all NaN RatTerms are equal.
356 */
357 @Override
358 public boolean equals(/*@Nullable*/ Object obj) {
359 if (obj instanceof RatTerm) {
360 RatTerm rt = (RatTerm) obj;
361 if (this.isNaN() && rt.isNaN()) {
362 return true;
363 } else {
364 return this.expt == rt.expt && this.coeff.equals(rt.coeff);
365 }
366 } else {
367 return false;
368 }
369 }
370
371 /**
372 * Checks that the representation invariant holds (if any).
373 * Throws an exception if the rep invariant is violated.
374 */
375 private void checkRep() throws RuntimeException {
376 // assert coeff != null: "coeff == null";
377 // assert !(coeff.equals(RatNum.ZERO) && expt != 0): "coeff is zero while expt == " + expt;
378
379 if (coeff == null) {
380 throw new RuntimeException("coeff == null");
381 }
382 if (coeff.equals(RatNum.ZERO) && expt != 0) {
383 throw new RuntimeException("coeff is zero while expt == " + expt);
384 }
385 }
386 }