Changeset 13061 in josm for trunk/src/com/drew/lang/Rational.java
- Timestamp:
- 2017-10-30T22:46:09+01:00 (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/com/drew/lang/Rational.java
r10862 r13061 1 1 /* 2 * Copyright 2002-201 6Drew Noakes2 * Copyright 2002-2017 Drew Noakes 3 3 * 4 4 * Licensed under the Apache License, Version 2.0 (the "License"); … … 36 36 * @author Drew Noakes https://drewnoakes.com 37 37 */ 38 public class Rational extends java.lang.Number implements Serializable 38 @SuppressWarnings("WeakerAccess") 39 public class Rational extends java.lang.Number implements Comparable<Rational>, Serializable 39 40 { 40 41 private static final long serialVersionUID = 510688928138848770L; … … 173 174 (_denominator != 0 && (_numerator % _denominator == 0)) || 174 175 (_denominator == 0 && _numerator == 0); 176 } 177 178 /** Checks if either the numerator or denominator are zero. */ 179 public boolean isZero() 180 { 181 return _numerator == 0 || _denominator == 0; 175 182 } 176 183 … … 212 219 213 220 /** 214 * Decides whether a brute-force simplification calculation should be avoided 215 * by comparing the maximum number of possible calculations with some threshold. 216 * 217 * @return true if the simplification should be performed, otherwise false 218 */ 219 private boolean tooComplexForSimplification() 220 { 221 double maxPossibleCalculations = (((double) (Math.min(_denominator, _numerator) - 1) / 5d) + 2); 222 final int maxSimplificationCalculations = 1000; 223 return maxPossibleCalculations > maxSimplificationCalculations; 221 * Compares two {@link Rational} instances, returning true if they are mathematically 222 * equivalent (in consistence with {@link Rational#equals(Object)} method). 223 * 224 * @param that the {@link Rational} to compare this instance to. 225 * @return the value {@code 0} if this {@link Rational} is 226 * equal to the argument {@link Rational} mathematically; a value less 227 * than {@code 0} if this {@link Rational} is less 228 * than the argument {@link Rational}; and a value greater 229 * than {@code 0} if this {@link Rational} is greater than the argument 230 * {@link Rational}. 231 */ 232 public int compareTo(@NotNull Rational that) { 233 return Double.compare(this.doubleValue(), that.doubleValue()); 234 } 235 236 /** 237 * Indicates whether this instance and <code>other</code> are numerically equal, 238 * even if their representations differ. 239 * 240 * For example, 1/2 is equal to 10/20 by this method. 241 * Similarly, 1/0 is equal to 100/0 by this method. 242 * To test equal representations, use EqualsExact. 243 * 244 * @param other The rational value to compare with 245 */ 246 public boolean equals(Rational other) { 247 return other.doubleValue() == doubleValue(); 248 } 249 250 /** 251 * Indicates whether this instance and <code>other</code> have identical 252 * Numerator and Denominator. 253 * <p> 254 * For example, 1/2 is not equal to 10/20 by this method. 255 * Similarly, 1/0 is not equal to 100/0 by this method. 256 * To test numerically equivalence, use Equals(Rational).</p> 257 * 258 * @param other The rational value to compare with 259 */ 260 public boolean equalsExact(Rational other) { 261 return getDenominator() == other.getDenominator() && getNumerator() == other.getNumerator(); 224 262 } 225 263 … … 249 287 /** 250 288 * <p> 251 * Simplifies the {@link Rational} number.</p>289 * Simplifies the representation of this {@link Rational} number.</p> 252 290 * <p> 253 * Prime number series: 1, 2, 3, 5, 7, 9, 11, 13, 17</p> 291 * For example, 5/10 simplifies to 1/2 because both Numerator 292 * and Denominator share a common factor of 5.</p> 254 293 * <p> 255 * To reduce a rational, need to see if both numerator and denominator are divisible 256 * by a common factor. Using the prime number series in ascending order guarantees 257 * the minimum number of checks required.</p> 258 * <p> 259 * However, generating the prime number series seems to be a hefty task. Perhaps 260 * it's simpler to check if both d & n are divisible by all numbers from 2 {@literal ->} 261 * (Math.min(denominator, numerator) / 2). In doing this, one can check for 2 262 * and 5 once, then ignore all even numbers, and all numbers ending in 0 or 5. 263 * This leaves four numbers from every ten to check.</p> 264 * <p> 265 * Therefore, the max number of pairs of modulus divisions required will be:</p> 266 * <pre><code> 267 * 4 Math.min(denominator, numerator) - 1 268 * -- * ------------------------------------ + 2 269 * 10 2 270 * 271 * Math.min(denominator, numerator) - 1 272 * = ------------------------------------ + 2 273 * 5 274 * </code></pre> 275 * 276 * @return a simplified instance, or if the Rational could not be simplified, 277 * returns itself (unchanged) 294 * Uses the Euclidean Algorithm to find the greatest common divisor.</p> 295 * 296 * @return A simplified instance if one exists, otherwise a copy of the original value. 278 297 */ 279 298 @NotNull 280 299 public Rational getSimplifiedInstance() 281 300 { 282 if (tooComplexForSimplification()) { 283 return this; 301 long gcd = GCD(_numerator, _denominator); 302 303 return new Rational(_numerator / gcd, _denominator / gcd); 304 } 305 306 private static long GCD(long a, long b) 307 { 308 if (a < 0) 309 a = -a; 310 if (b < 0) 311 b = -b; 312 313 while (a != 0 && b != 0) 314 { 315 if (a > b) 316 a %= b; 317 else 318 b %= a; 284 319 } 285 for (int factor = 2; factor <= Math.min(_denominator, _numerator); factor++) { 286 if ((factor % 2 == 0 && factor > 2) || (factor % 5 == 0 && factor > 5)) { 287 continue; 288 } 289 if (_denominator % factor == 0 && _numerator % factor == 0) { 290 // found a common factor 291 return new Rational(_numerator / factor, _denominator / factor); 292 } 293 } 294 return this; 320 321 return a == 0 ? b : a; 295 322 } 296 323 }
Note:
See TracChangeset
for help on using the changeset viewer.