001 package ps1;
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 RatNum */
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) && ((this.expt == arg.expt) || (this.isZero() ||
133 * arg.isZero() || this.isNaN() || arg.isNaN())).
134 * @return a RatTerm equals to (this + arg). If either argument is NaN, then
135 * returns NaN.
136 * @throws IllegalArgumentException
137 * if (this.expt != arg.expt) and neither argument is zero or
138 * NaN.
139 */
140 public RatTerm add(RatTerm arg) {
141 // TODO: Fill in this method, then remove the RuntimeException
142 throw new RuntimeException("RatTerm->add() unimplemented!");
143 }
144
145 /**
146 * Subtraction operation.
147 *
148 * @requires (arg != null) && ((this.expt == arg.expt) || (this.isZero() ||
149 * arg.isZero() || this.isNaN() || arg.isNaN())).
150 * @return a RatTerm equals to (this - arg). If either argument is NaN, then
151 * returns NaN.
152 * @throws IllegalArgumentException
153 * if (this.expt != arg.expt) and neither argument is zero or
154 * NaN.
155 */
156 public RatTerm sub(RatTerm arg) {
157 // TODO: Fill in this method, then remove the RuntimeException
158 throw new RuntimeException("RatTerm->sub() unimplemented!");
159 }
160
161 /**
162 * Multiplication operation.
163 *
164 * @requires arg != null
165 * @return a RatTerm equals to (this * arg). If either argument is NaN, then
166 * returns NaN.
167 */
168 public RatTerm mul(RatTerm arg) {
169 // TODO: Fill in this method, then remove the RuntimeException
170 throw new RuntimeException("RatTerm->mul() unimplemented!");
171 }
172
173 /**
174 * Division operation.
175 *
176 * @requires arg != null
177 * @return a RatTerm equals to (this / arg). If arg is zero, or if either
178 * argument is NaN, then returns NaN.
179 */
180 public RatTerm div(RatTerm arg) {
181 // TODO: Fill in this method, then remove the RuntimeException
182 throw new RuntimeException("RatTerm->div() unimplemented!");
183 }
184
185 /**
186 * Return the derivative of this RatTerm.
187 *
188 * @return a RatTerm that, q, such that q = dy/dx, where this == y. In other
189 * words, q is the derivative of this. If this.isNaN(), then return
190 * some q such that q.isNaN()
191 * <p>
192 * Given a term, a*x^b, the derivative of the term is: (a*b)*x^(b-1)
193 * for b > 0 and 0 for b == 0 (Do not worry about the case when b <
194 * 0. The caller of this function, RatPoly, contains a rep.
195 * invariant stating that b is never less than 0.)
196 */
197 public RatTerm differentiate() {
198 // TODO: Fill in this method, then remove the RuntimeException
199 throw new RuntimeException("RatTerm->differentiate() unimplemented!");
200 }
201
202 /**
203 * Returns the antiderivative of this RatTerm.
204 *
205 * @return a RatTerm, q, such that dq/dx = this where the constant of
206 * intergration is assumed to be 0. In other words, q is the
207 * antiderivative of this. If this.isNaN(), then return some q such
208 * that q.isNaN()
209 * <p>
210 * Given a term, a*x^b, (where b >= 0) the antiderivative of the
211 * term is: a/(b+1)*x^(b+1) (Do not worry about the case when b < 0.
212 * The caller of this function, RatPoly, contains a rep. invariant
213 * stating that b is never less than 0.)
214 */
215 public RatTerm antiDifferentiate() {
216 // TODO: Fill in this method, then remove the RuntimeException
217 throw new RuntimeException(
218 "RatTerm->antiDifferentiate() unimplemented!");
219 }
220
221 private static final RatNum ONE = new RatNum(1);
222
223 /**
224 * Returns a string representation of this RatTerm.
225 *
226 * @return A String representation of the expression represented by this.
227 * <p>
228 * There is no whitespace in the returned string.
229 * <p>
230 * If the term is itself zero, the returned string will just be "0".
231 * <p>
232 * If this.isNaN(), then the returned string will be just "NaN"
233 * <p>
234 *
235 * The string for a non-zero, non-NaN RatTerm is in the form "C*x^E" where C
236 * is a valid string representation of a RatNum (see {@link ps1.RatNum}'s
237 * toString method) and E is an integer. UNLESS: (1) the exponent E is zero,
238 * in which case T takes the form "C" (2) the exponent E is one, in which
239 * case T takes the form "C*x" (3) the coefficient C is one, in which case T
240 * takes the form "x^E" or "x" (if E is one) or "1" (if E is zero).
241 * <p>
242 * Valid example outputs include "3/2*x^2", "-1/2", "0", and "NaN".
243 */
244 @Override
245 public String toString() {
246 if (this.isNaN()) {
247 return "NaN";
248 }
249 StringBuilder output = new StringBuilder();
250 RatNum c = coeff;
251 int e = expt;
252 if (c.isNegative()) {
253 output.append("-");
254 c = c.negate();
255 }
256 if (c.equals(ONE) && e == 1) {
257 output.append("x");
258 } else if (e == 0) {
259 output.append(c.toString());
260 } else if (c.equals(ONE)) {
261 output.append("x^" + e);
262 } else if (e == 1) {
263 output.append(c.toString() + "*x");
264 } else {
265 output.append(c.toString() + "*x^" + e);
266 }
267 return output.toString();
268 }
269
270 /**
271 * Builds a new RatTerm, given a descriptive String.
272 *
273 * @requires 'termStr' is an instance of a string with no spaces that
274 * expresses a RatTerm in the form defined in the toString()
275 * method.
276 * <p>
277 *
278 * Valid inputs include "0", "x", and "-5/3*x^3", and "NaN".
279 *
280 * @return a RatTerm t such that t.toString() = termStr
281 */
282 public static RatTerm valueOf(String termStr) {
283
284 if (termStr.equals("NaN")) {
285 return NaN;
286 }
287
288 // Term is: "R" or "R*x" or "R*x^N" or "x^N" or "x",
289 // where R is a rational num and N is an integer.
290
291 // First we parse the coefficient
292 int multIndex = termStr.indexOf("*");
293 RatNum coeff = null;
294 if (multIndex == -1) {
295 // "R" or "x^N" or "x"
296 int xIndex = termStr.indexOf("x");
297 if (xIndex == -1) {
298 // "R"
299 coeff = RatNum.valueOf(termStr);
300 } else {
301 int negIndex = termStr.indexOf("-");
302 // "x^N" or "x" ==> coeff = 1
303 if (negIndex == -1) {
304 coeff = new RatNum(1);
305 }
306 // "-x^N" or "-x" ==> coeff = -1
307 else if (negIndex == 0) {
308 coeff = new RatNum(-1);
309 } else {
310 throw new RuntimeException(
311 "Minus sign, '-', not allowed in the middle of input string: "
312 + termStr);
313 }
314 }
315 } else {
316 // "R*x" or "R*x^N"
317 coeff = RatNum.valueOf(termStr.substring(0, multIndex));
318 }
319
320 // Second we parse the exponent
321 int powIndex = termStr.indexOf("^");
322 int expt;
323 if (powIndex == -1) {
324 // "R" or "R*x" or "x"
325 int xIndex = termStr.indexOf("x");
326 if (xIndex == -1) {
327 // "R"
328 expt = 0;
329 } else {
330 // "R*x" or "x"
331 expt = 1;
332 }
333 } else {
334 // "R*x^N" or "x^N"
335 expt = Integer.parseInt(termStr.substring(powIndex + 1));
336 }
337 return new RatTerm(coeff, expt);
338 }
339
340 /**
341 * Standard hashCode function.
342 *
343 * @return an int that all objects equal to this will also.
344 */
345 @Override
346 public int hashCode() {
347 if (this.isNaN()) {
348 return 0;
349 }
350 return coeff.hashCode() * 7 + expt * 43;
351 }
352
353 /**
354 * Standard equality operation.
355 *
356 * @return true iff 'obj' is an instance of a RatTerm and 'this' and 'obj'
357 * represent the same RatTerm. Note that all NaN RatTerms are equal.
358 */
359 @Override
360 public boolean equals(Object obj) {
361 if (obj instanceof RatTerm) {
362 RatTerm rt = (RatTerm) obj;
363 if (this.isNaN() && rt.isNaN()) {
364 return true;
365 } else {
366 return this.expt == rt.expt && this.coeff.equals(rt.coeff);
367 }
368 } else {
369 return false;
370 }
371 }
372
373 /**
374 * Checks that the representation invariant holds (if any).
375 */
376 // Throws a RuntimeException if the rep invariant is violated.
377 private void checkRep() throws RuntimeException {
378 if (coeff == null) {
379 throw new RuntimeException("coeff == null");
380 }
381 if (coeff.equals(RatNum.ZERO) && expt != 0) {
382 throw new RuntimeException("coeff is zero while expt == " + expt);
383 }
384 }
385 }