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