001package 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". 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 // TODO: Fill in this method, then remove the RuntimeException 061 throw new RuntimeException("RatTerm->constructor is not yet implemented"); 062 } 063 064 /** 065 * Gets the coefficient of this RatTerm. 066 * 067 * @return the coefficient of this RatTerm. 068 */ 069 public RatNum getCoeff() { 070 // TODO: Fill in this method, then remove the RuntimeException 071 throw new RuntimeException("RatTerm->getCoeff() is not yet implemented"); 072 } 073 074 /** 075 * Gets the exponent of this RatTerm. 076 * 077 * @return the exponent of this RatTerm. 078 */ 079 public int getExpt() { 080 // TODO: Fill in this method, then remove the RuntimeException 081 throw new RuntimeException("RatTerm->getExpt() is not yet implemented"); 082 } 083 084 /** 085 * Returns true if this RatTerm is not-a-number. 086 * 087 * @return true if and only if this has NaN as a coefficient. 088 */ 089 public boolean isNaN() { 090 // TODO: Fill in this method, then remove the RuntimeException 091 throw new RuntimeException("RatTerm->isNaN() is not yet implemented"); 092 } 093 094 /** 095 * Returns true if this RatTerm is equal to 0. 096 * 097 * @return true if and only if this has zero as a coefficient. 098 */ 099 public boolean isZero() { 100 // TODO: Fill in this method, then remove the RuntimeException 101 throw new RuntimeException("RatTerm->isZero() is not yet implemented"); 102 } 103 104 /** 105 * Returns the value of this RatTerm, evaluated at d. 106 * 107 * @param d The value at which to evaluate this term. 108 * @return the value of this polynomial when evaluated at 'd'. For example, 109 * "3*x^2" evaluated at 2 is 12. if (this.isNaN() == true), return 110 * Double.NaN 111 */ 112 public double eval(double d) { 113 // TODO: Fill in this method, then remove the RuntimeException 114 // Hint: You may find java.lang.Math's pow() method useful. 115 throw new RuntimeException("RatTerm->eval() is not yet implemented"); 116 } 117 118 /** 119 * Negation operation. 120 * 121 * @return a RatTerm equals to (-this). If this is NaN, then returns NaN. 122 */ 123 public RatTerm negate() { 124 // TODO: Fill in this method, then remove the RuntimeException 125 throw new RuntimeException("RatTerm->negate() is not yet implemented"); 126 } 127 128 /** 129 * Addition operation. 130 * 131 * @param p The other value to be added. 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 p) { 140 // TODO: Fill in this method, then remove the RuntimeException 141 throw new RuntimeException("RatTerm->add() is not yet implemented"); 142 } 143 144 /** 145 * Subtraction operation. 146 * 147 * @param p The value to be subtracted. 148 * @requires arg != null 149 * @return a RatTerm equals to (this - arg). If either argument is NaN, then 150 * returns NaN. 151 * @throws IllegalArgumentException 152 * if (this.expt != arg.expt) and neither argument is zero or 153 * NaN. 154 */ 155 public RatTerm sub(RatTerm p) { 156 // TODO: Fill in this method, then remove the RuntimeException 157 throw new RuntimeException("RatTerm->sub() is not yet implemented"); 158 } 159 160 /** 161 * Multiplication operation. 162 * 163 * @param p The other value to be multiplied. 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 p) { 169 // TODO: Fill in this method, then remove the RuntimeException 170 throw new RuntimeException("RatTerm->mul() is not yet implemented"); 171 } 172 173 /** 174 * Division operation. 175 * 176 * @param p The divisor. 177 * @requires arg != null 178 * @return a RatTerm equals to (this / arg). If arg is zero, or if either 179 * argument is NaN, then returns NaN. 180 */ 181 public RatTerm div(RatTerm p) { 182 // TODO: Fill in this method, then remove the RuntimeException 183 throw new RuntimeException("RatTerm->div() is not yet implemented"); 184 } 185 186 /** 187 * Return the derivative of this RatTerm. 188 * 189 * @return a RatTerm that, q, such that q = dy/dx, where this == y. In other 190 * words, q is the derivative of this. If this.isNaN(), then return 191 * some q such that q.isNaN() 192 * <p> 193 * Given a term, a*x^b, the derivative of the term is: (a*b)*x^(b-1) 194 * for b > 0 and 0 for b == 0 (Do not worry about the case when b < 195 * 0. The caller of this function, RatPoly, contains a rep. 196 * invariant stating that b is never less than 0.) 197 */ 198 public RatTerm differentiate() { 199 // TODO: Fill in this method, then remove the RuntimeException 200 throw new RuntimeException("RatTerm->differentiate() is not yet implemented"); 201 } 202 203 /** 204 * Returns the antiderivative of this RatTerm. 205 * 206 * @return a RatTerm, q, such that dq/dx = this where the constant of 207 * intergration is assumed to be 0. In other words, q is the 208 * antiderivative of this. If this.isNaN(), then return some q such 209 * that q.isNaN() 210 * <p> 211 * Given a term, a*x^b, (where b >= 0) the antiderivative of the 212 * term is: a/(b+1)*x^(b+1) (Do not worry about the case when b < 0. 213 * The caller of this function, RatPoly, contains a rep. invariant 214 * stating that b is never less than 0.) 215 */ 216 public RatTerm antiDifferentiate() { 217 // TODO: Fill in this method, then remove the RuntimeException 218 throw new RuntimeException( 219 "RatTerm->antiDifferentiate() unimplemented!"); 220 } 221 222 /** 223 * Returns a string representation of this RatTerm. 224 * 225 * @return A String representation of the expression represented by this. 226 * <p> 227 * There is no whitespace in the returned string. 228 * <p> 229 * If the term is itself zero, the returned string will just be "0". 230 * <p> 231 * If this.isNaN(), then the returned string will be just "NaN" 232 * <p> 233 * 234 * The string for a non-zero, non-NaN RatTerm is in the form "C*x^E" where C 235 * is a valid string representation of a RatNum (see {@link hw3.RatNum}'s 236 * toString method) and E is an integer. UNLESS: (1) the exponent E is zero, 237 * in which case T takes the form "C" (2) the exponent E is one, in which 238 * case T takes the form "C*x" (3) the coefficient C is one, in which case T 239 * takes the form "x^E" or "x" (if E is one) or "1" (if E is zero). 240 * <p> 241 * Valid example outputs include "3/2*x^2", "-1/2", "0", and "NaN". 242 */ 243 @Override 244 public String toString() { 245 if (this.isNaN()) { 246 return "NaN"; 247 } 248 StringBuilder output = new StringBuilder(); 249 RatNum c = coeff; 250 int e = expt; 251 if (c.isNegative()) { 252 output.append("-"); 253 c = c.negate(); 254 } 255 if (c.equals(ONE) && e == 1) { 256 output.append("x"); 257 } else if (e == 0) { 258 output.append(c.toString()); 259 } else if (c.equals(ONE)) { 260 output.append("x^" + e); 261 } else if (e == 1) { 262 output.append(c.toString() + "*x"); 263 } else { 264 output.append(c.toString() + "*x^" + e); 265 } 266 return output.toString(); 267 } 268 269 /** 270 * Builds a new RatTerm, given a descriptive String. 271 * 272 * @param termStr A string of the format described in the @requires clause. 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 * @param obj The object to be compared for equality. 357 * @return true iff 'obj' is an instance of a RatTerm and 'this' and 'obj' 358 * represent the same RatTerm. Note that all NaN RatTerms are equal. 359 */ 360 @Override 361 public boolean equals(/*@Nullable*/ Object obj) { 362 if (obj instanceof RatTerm) { 363 RatTerm rt = (RatTerm) obj; 364 if (this.isNaN() && rt.isNaN()) { 365 return true; 366 } else { 367 return this.expt == rt.expt && this.coeff.equals(rt.coeff); 368 } 369 } else { 370 return false; 371 } 372 } 373 374 /** 375 * Checks that the representation invariant holds (if any). 376 * Throws an exception if the rep invariant is violated. 377 */ 378 private void checkRep() throws RuntimeException { 379 // assert coeff != null: "coeff == null"; 380 // assert !(coeff.equals(RatNum.ZERO) && expt != 0): "coeff is zero while expt == " + expt; 381 382 if (coeff == null) { 383 throw new RuntimeException("coeff == null"); 384 } 385 if (coeff.equals(RatNum.ZERO) && expt != 0) { 386 throw new RuntimeException("coeff is zero while expt == " + expt); 387 } 388 } 389}