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