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    }