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 }