001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.math.fraction; 018 019 import org.apache.commons.math.ConvergenceException; 020 import org.apache.commons.math.TestUtils; 021 022 import junit.framework.TestCase; 023 024 /** 025 * @version $Revision: 795903 $ $Date: 2009-07-20 12:29:46 -0400 (Mon, 20 Jul 2009) $ 026 */ 027 public class FractionTest extends TestCase { 028 029 private void assertFraction(int expectedNumerator, int expectedDenominator, Fraction actual) { 030 assertEquals(expectedNumerator, actual.getNumerator()); 031 assertEquals(expectedDenominator, actual.getDenominator()); 032 } 033 034 public void testConstructor() { 035 assertFraction(0, 1, new Fraction(0, 1)); 036 assertFraction(0, 1, new Fraction(0, 2)); 037 assertFraction(0, 1, new Fraction(0, -1)); 038 assertFraction(1, 2, new Fraction(1, 2)); 039 assertFraction(1, 2, new Fraction(2, 4)); 040 assertFraction(-1, 2, new Fraction(-1, 2)); 041 assertFraction(-1, 2, new Fraction(1, -2)); 042 assertFraction(-1, 2, new Fraction(-2, 4)); 043 assertFraction(-1, 2, new Fraction(2, -4)); 044 045 // overflow 046 try { 047 new Fraction(Integer.MIN_VALUE, -1); 048 fail(); 049 } catch (ArithmeticException ex) { 050 // success 051 } 052 try { 053 new Fraction(1, Integer.MIN_VALUE); 054 fail(); 055 } catch (ArithmeticException ex) { 056 // success 057 } 058 try { 059 assertFraction(0, 1, new Fraction(0.00000000000001)); 060 assertFraction(2, 5, new Fraction(0.40000000000001)); 061 assertFraction(15, 1, new Fraction(15.0000000000001)); 062 063 } catch (ConvergenceException ex) { 064 fail(ex.getMessage()); 065 } 066 } 067 068 public void testGoldenRatio() { 069 try { 070 // the golden ratio is notoriously a difficult number for continuous fraction 071 new Fraction((1 + Math.sqrt(5)) / 2, 1.0e-12, 25); 072 fail("an exception should have been thrown"); 073 } catch (ConvergenceException ce) { 074 // expected behavior 075 } catch (Exception e) { 076 fail("wrong exception caught"); 077 } 078 } 079 080 // MATH-179 081 public void testDoubleConstructor() throws ConvergenceException { 082 assertFraction(1, 2, new Fraction((double)1 / (double)2)); 083 assertFraction(1, 3, new Fraction((double)1 / (double)3)); 084 assertFraction(2, 3, new Fraction((double)2 / (double)3)); 085 assertFraction(1, 4, new Fraction((double)1 / (double)4)); 086 assertFraction(3, 4, new Fraction((double)3 / (double)4)); 087 assertFraction(1, 5, new Fraction((double)1 / (double)5)); 088 assertFraction(2, 5, new Fraction((double)2 / (double)5)); 089 assertFraction(3, 5, new Fraction((double)3 / (double)5)); 090 assertFraction(4, 5, new Fraction((double)4 / (double)5)); 091 assertFraction(1, 6, new Fraction((double)1 / (double)6)); 092 assertFraction(5, 6, new Fraction((double)5 / (double)6)); 093 assertFraction(1, 7, new Fraction((double)1 / (double)7)); 094 assertFraction(2, 7, new Fraction((double)2 / (double)7)); 095 assertFraction(3, 7, new Fraction((double)3 / (double)7)); 096 assertFraction(4, 7, new Fraction((double)4 / (double)7)); 097 assertFraction(5, 7, new Fraction((double)5 / (double)7)); 098 assertFraction(6, 7, new Fraction((double)6 / (double)7)); 099 assertFraction(1, 8, new Fraction((double)1 / (double)8)); 100 assertFraction(3, 8, new Fraction((double)3 / (double)8)); 101 assertFraction(5, 8, new Fraction((double)5 / (double)8)); 102 assertFraction(7, 8, new Fraction((double)7 / (double)8)); 103 assertFraction(1, 9, new Fraction((double)1 / (double)9)); 104 assertFraction(2, 9, new Fraction((double)2 / (double)9)); 105 assertFraction(4, 9, new Fraction((double)4 / (double)9)); 106 assertFraction(5, 9, new Fraction((double)5 / (double)9)); 107 assertFraction(7, 9, new Fraction((double)7 / (double)9)); 108 assertFraction(8, 9, new Fraction((double)8 / (double)9)); 109 assertFraction(1, 10, new Fraction((double)1 / (double)10)); 110 assertFraction(3, 10, new Fraction((double)3 / (double)10)); 111 assertFraction(7, 10, new Fraction((double)7 / (double)10)); 112 assertFraction(9, 10, new Fraction((double)9 / (double)10)); 113 assertFraction(1, 11, new Fraction((double)1 / (double)11)); 114 assertFraction(2, 11, new Fraction((double)2 / (double)11)); 115 assertFraction(3, 11, new Fraction((double)3 / (double)11)); 116 assertFraction(4, 11, new Fraction((double)4 / (double)11)); 117 assertFraction(5, 11, new Fraction((double)5 / (double)11)); 118 assertFraction(6, 11, new Fraction((double)6 / (double)11)); 119 assertFraction(7, 11, new Fraction((double)7 / (double)11)); 120 assertFraction(8, 11, new Fraction((double)8 / (double)11)); 121 assertFraction(9, 11, new Fraction((double)9 / (double)11)); 122 assertFraction(10, 11, new Fraction((double)10 / (double)11)); 123 } 124 125 // MATH-181 126 public void testDigitLimitConstructor() throws ConvergenceException { 127 assertFraction(2, 5, new Fraction(0.4, 9)); 128 assertFraction(2, 5, new Fraction(0.4, 99)); 129 assertFraction(2, 5, new Fraction(0.4, 999)); 130 131 assertFraction(3, 5, new Fraction(0.6152, 9)); 132 assertFraction(8, 13, new Fraction(0.6152, 99)); 133 assertFraction(510, 829, new Fraction(0.6152, 999)); 134 assertFraction(769, 1250, new Fraction(0.6152, 9999)); 135 } 136 137 public void testIntegerOverflow() { 138 checkIntegerOverflow(0.75000000001455192); 139 checkIntegerOverflow(1.0e10); 140 } 141 142 private void checkIntegerOverflow(double a) { 143 try { 144 new Fraction(a, 1.0e-12, 1000); 145 fail("an exception should have been thrown"); 146 } catch (ConvergenceException ce) { 147 // expected behavior 148 } catch (Exception e) { 149 fail("wrong exception caught"); 150 } 151 } 152 153 public void testEpsilonLimitConstructor() throws ConvergenceException { 154 assertFraction(2, 5, new Fraction(0.4, 1.0e-5, 100)); 155 156 assertFraction(3, 5, new Fraction(0.6152, 0.02, 100)); 157 assertFraction(8, 13, new Fraction(0.6152, 1.0e-3, 100)); 158 assertFraction(251, 408, new Fraction(0.6152, 1.0e-4, 100)); 159 assertFraction(251, 408, new Fraction(0.6152, 1.0e-5, 100)); 160 assertFraction(510, 829, new Fraction(0.6152, 1.0e-6, 100)); 161 assertFraction(769, 1250, new Fraction(0.6152, 1.0e-7, 100)); 162 } 163 164 public void testCompareTo() { 165 Fraction first = new Fraction(1, 2); 166 Fraction second = new Fraction(1, 3); 167 Fraction third = new Fraction(1, 2); 168 169 assertEquals(0, first.compareTo(first)); 170 assertEquals(0, first.compareTo(third)); 171 assertEquals(1, first.compareTo(second)); 172 assertEquals(-1, second.compareTo(first)); 173 174 // these two values are different approximations of PI 175 // the first one is approximately PI - 3.07e-18 176 // the second one is approximately PI + 1.936e-17 177 Fraction pi1 = new Fraction(1068966896, 340262731); 178 Fraction pi2 = new Fraction( 411557987, 131002976); 179 assertEquals(-1, pi1.compareTo(pi2)); 180 assertEquals( 1, pi2.compareTo(pi1)); 181 assertEquals(0.0, pi1.doubleValue() - pi2.doubleValue(), 1.0e-20); 182 } 183 184 public void testDoubleValue() { 185 Fraction first = new Fraction(1, 2); 186 Fraction second = new Fraction(1, 3); 187 188 assertEquals(0.5, first.doubleValue(), 0.0); 189 assertEquals(1.0 / 3.0, second.doubleValue(), 0.0); 190 } 191 192 public void testFloatValue() { 193 Fraction first = new Fraction(1, 2); 194 Fraction second = new Fraction(1, 3); 195 196 assertEquals(0.5f, first.floatValue(), 0.0f); 197 assertEquals((float)(1.0 / 3.0), second.floatValue(), 0.0f); 198 } 199 200 public void testIntValue() { 201 Fraction first = new Fraction(1, 2); 202 Fraction second = new Fraction(3, 2); 203 204 assertEquals(0, first.intValue()); 205 assertEquals(1, second.intValue()); 206 } 207 208 public void testLongValue() { 209 Fraction first = new Fraction(1, 2); 210 Fraction second = new Fraction(3, 2); 211 212 assertEquals(0L, first.longValue()); 213 assertEquals(1L, second.longValue()); 214 } 215 216 public void testConstructorDouble() { 217 try { 218 assertFraction(1, 2, new Fraction(0.5)); 219 assertFraction(1, 3, new Fraction(1.0 / 3.0)); 220 assertFraction(17, 100, new Fraction(17.0 / 100.0)); 221 assertFraction(317, 100, new Fraction(317.0 / 100.0)); 222 assertFraction(-1, 2, new Fraction(-0.5)); 223 assertFraction(-1, 3, new Fraction(-1.0 / 3.0)); 224 assertFraction(-17, 100, new Fraction(17.0 / -100.0)); 225 assertFraction(-317, 100, new Fraction(-317.0 / 100.0)); 226 } catch (ConvergenceException ex) { 227 fail(ex.getMessage()); 228 } 229 } 230 231 public void testAbs() { 232 Fraction a = new Fraction(10, 21); 233 Fraction b = new Fraction(-10, 21); 234 Fraction c = new Fraction(10, -21); 235 236 assertFraction(10, 21, a.abs()); 237 assertFraction(10, 21, b.abs()); 238 assertFraction(10, 21, c.abs()); 239 } 240 241 public void testReciprocal() { 242 Fraction f = null; 243 244 f = new Fraction(50, 75); 245 f = f.reciprocal(); 246 assertEquals(3, f.getNumerator()); 247 assertEquals(2, f.getDenominator()); 248 249 f = new Fraction(4, 3); 250 f = f.reciprocal(); 251 assertEquals(3, f.getNumerator()); 252 assertEquals(4, f.getDenominator()); 253 254 f = new Fraction(-15, 47); 255 f = f.reciprocal(); 256 assertEquals(-47, f.getNumerator()); 257 assertEquals(15, f.getDenominator()); 258 259 f = new Fraction(0, 3); 260 try { 261 f = f.reciprocal(); 262 fail("expecting ArithmeticException"); 263 } catch (ArithmeticException ex) {} 264 265 // large values 266 f = new Fraction(Integer.MAX_VALUE, 1); 267 f = f.reciprocal(); 268 assertEquals(1, f.getNumerator()); 269 assertEquals(Integer.MAX_VALUE, f.getDenominator()); 270 } 271 272 public void testNegate() { 273 Fraction f = null; 274 275 f = new Fraction(50, 75); 276 f = f.negate(); 277 assertEquals(-2, f.getNumerator()); 278 assertEquals(3, f.getDenominator()); 279 280 f = new Fraction(-50, 75); 281 f = f.negate(); 282 assertEquals(2, f.getNumerator()); 283 assertEquals(3, f.getDenominator()); 284 285 // large values 286 f = new Fraction(Integer.MAX_VALUE-1, Integer.MAX_VALUE); 287 f = f.negate(); 288 assertEquals(Integer.MIN_VALUE+2, f.getNumerator()); 289 assertEquals(Integer.MAX_VALUE, f.getDenominator()); 290 291 f = new Fraction(Integer.MIN_VALUE, 1); 292 try { 293 f = f.negate(); 294 fail("expecting ArithmeticException"); 295 } catch (ArithmeticException ex) {} 296 } 297 298 public void testAdd() { 299 Fraction a = new Fraction(1, 2); 300 Fraction b = new Fraction(2, 3); 301 302 assertFraction(1, 1, a.add(a)); 303 assertFraction(7, 6, a.add(b)); 304 assertFraction(7, 6, b.add(a)); 305 assertFraction(4, 3, b.add(b)); 306 307 Fraction f1 = new Fraction(Integer.MAX_VALUE - 1, 1); 308 Fraction f2 = Fraction.ONE; 309 Fraction f = f1.add(f2); 310 assertEquals(Integer.MAX_VALUE, f.getNumerator()); 311 assertEquals(1, f.getDenominator()); 312 f = f1.add(1); 313 assertEquals(Integer.MAX_VALUE, f.getNumerator()); 314 assertEquals(1, f.getDenominator()); 315 316 f1 = new Fraction(-1, 13*13*2*2); 317 f2 = new Fraction(-2, 13*17*2); 318 f = f1.add(f2); 319 assertEquals(13*13*17*2*2, f.getDenominator()); 320 assertEquals(-17 - 2*13*2, f.getNumerator()); 321 322 try { 323 f.add(null); 324 fail("expecting IllegalArgumentException"); 325 } catch (IllegalArgumentException ex) {} 326 327 // if this fraction is added naively, it will overflow. 328 // check that it doesn't. 329 f1 = new Fraction(1,32768*3); 330 f2 = new Fraction(1,59049); 331 f = f1.add(f2); 332 assertEquals(52451, f.getNumerator()); 333 assertEquals(1934917632, f.getDenominator()); 334 335 f1 = new Fraction(Integer.MIN_VALUE, 3); 336 f2 = new Fraction(1,3); 337 f = f1.add(f2); 338 assertEquals(Integer.MIN_VALUE+1, f.getNumerator()); 339 assertEquals(3, f.getDenominator()); 340 341 f1 = new Fraction(Integer.MAX_VALUE - 1, 1); 342 f2 = Fraction.ONE; 343 f = f1.add(f2); 344 assertEquals(Integer.MAX_VALUE, f.getNumerator()); 345 assertEquals(1, f.getDenominator()); 346 347 try { 348 f = f.add(Fraction.ONE); // should overflow 349 fail("expecting ArithmeticException but got: " + f.toString()); 350 } catch (ArithmeticException ex) {} 351 352 // denominator should not be a multiple of 2 or 3 to trigger overflow 353 f1 = new Fraction(Integer.MIN_VALUE, 5); 354 f2 = new Fraction(-1,5); 355 try { 356 f = f1.add(f2); // should overflow 357 fail("expecting ArithmeticException but got: " + f.toString()); 358 } catch (ArithmeticException ex) {} 359 360 try { 361 f= new Fraction(-Integer.MAX_VALUE, 1); 362 f = f.add(f); 363 fail("expecting ArithmeticException"); 364 } catch (ArithmeticException ex) {} 365 366 try { 367 f= new Fraction(-Integer.MAX_VALUE, 1); 368 f = f.add(f); 369 fail("expecting ArithmeticException"); 370 } catch (ArithmeticException ex) {} 371 372 f1 = new Fraction(3,327680); 373 f2 = new Fraction(2,59049); 374 try { 375 f = f1.add(f2); // should overflow 376 fail("expecting ArithmeticException but got: " + f.toString()); 377 } catch (ArithmeticException ex) {} 378 } 379 380 public void testDivide() { 381 Fraction a = new Fraction(1, 2); 382 Fraction b = new Fraction(2, 3); 383 384 assertFraction(1, 1, a.divide(a)); 385 assertFraction(3, 4, a.divide(b)); 386 assertFraction(4, 3, b.divide(a)); 387 assertFraction(1, 1, b.divide(b)); 388 389 Fraction f1 = new Fraction(3, 5); 390 Fraction f2 = Fraction.ZERO; 391 try { 392 f1.divide(f2); 393 fail("expecting ArithmeticException"); 394 } catch (ArithmeticException ex) {} 395 396 f1 = new Fraction(0, 5); 397 f2 = new Fraction(2, 7); 398 Fraction f = f1.divide(f2); 399 assertSame(Fraction.ZERO, f); 400 401 f1 = new Fraction(2, 7); 402 f2 = Fraction.ONE; 403 f = f1.divide(f2); 404 assertEquals(2, f.getNumerator()); 405 assertEquals(7, f.getDenominator()); 406 407 f1 = new Fraction(1, Integer.MAX_VALUE); 408 f = f1.divide(f1); 409 assertEquals(1, f.getNumerator()); 410 assertEquals(1, f.getDenominator()); 411 412 f1 = new Fraction(Integer.MIN_VALUE, Integer.MAX_VALUE); 413 f2 = new Fraction(1, Integer.MAX_VALUE); 414 f = f1.divide(f2); 415 assertEquals(Integer.MIN_VALUE, f.getNumerator()); 416 assertEquals(1, f.getDenominator()); 417 418 try { 419 f.divide(null); 420 fail("IllegalArgumentException"); 421 } catch (IllegalArgumentException ex) {} 422 423 try { 424 f1 = new Fraction(1, Integer.MAX_VALUE); 425 f = f1.divide(f1.reciprocal()); // should overflow 426 fail("expecting ArithmeticException"); 427 } catch (ArithmeticException ex) {} 428 try { 429 f1 = new Fraction(1, -Integer.MAX_VALUE); 430 f = f1.divide(f1.reciprocal()); // should overflow 431 fail("expecting ArithmeticException"); 432 } catch (ArithmeticException ex) {} 433 434 f1 = new Fraction(6, 35); 435 f = f1.divide(15); 436 assertEquals(2, f.getNumerator()); 437 assertEquals(175, f.getDenominator()); 438 439 } 440 441 public void testMultiply() { 442 Fraction a = new Fraction(1, 2); 443 Fraction b = new Fraction(2, 3); 444 445 assertFraction(1, 4, a.multiply(a)); 446 assertFraction(1, 3, a.multiply(b)); 447 assertFraction(1, 3, b.multiply(a)); 448 assertFraction(4, 9, b.multiply(b)); 449 450 Fraction f1 = new Fraction(Integer.MAX_VALUE, 1); 451 Fraction f2 = new Fraction(Integer.MIN_VALUE, Integer.MAX_VALUE); 452 Fraction f = f1.multiply(f2); 453 assertEquals(Integer.MIN_VALUE, f.getNumerator()); 454 assertEquals(1, f.getDenominator()); 455 456 try { 457 f.multiply(null); 458 fail("expecting IllegalArgumentException"); 459 } catch (IllegalArgumentException ex) {} 460 461 f1 = new Fraction(6, 35); 462 f = f1.multiply(15); 463 assertEquals(18, f.getNumerator()); 464 assertEquals(7, f.getDenominator()); 465 } 466 467 public void testSubtract() { 468 Fraction a = new Fraction(1, 2); 469 Fraction b = new Fraction(2, 3); 470 471 assertFraction(0, 1, a.subtract(a)); 472 assertFraction(-1, 6, a.subtract(b)); 473 assertFraction(1, 6, b.subtract(a)); 474 assertFraction(0, 1, b.subtract(b)); 475 476 Fraction f = new Fraction(1,1); 477 try { 478 f.subtract(null); 479 fail("expecting IllegalArgumentException"); 480 } catch (IllegalArgumentException ex) {} 481 482 // if this fraction is subtracted naively, it will overflow. 483 // check that it doesn't. 484 Fraction f1 = new Fraction(1,32768*3); 485 Fraction f2 = new Fraction(1,59049); 486 f = f1.subtract(f2); 487 assertEquals(-13085, f.getNumerator()); 488 assertEquals(1934917632, f.getDenominator()); 489 490 f1 = new Fraction(Integer.MIN_VALUE, 3); 491 f2 = new Fraction(1,3).negate(); 492 f = f1.subtract(f2); 493 assertEquals(Integer.MIN_VALUE+1, f.getNumerator()); 494 assertEquals(3, f.getDenominator()); 495 496 f1 = new Fraction(Integer.MAX_VALUE, 1); 497 f2 = Fraction.ONE; 498 f = f1.subtract(f2); 499 assertEquals(Integer.MAX_VALUE-1, f.getNumerator()); 500 assertEquals(1, f.getDenominator()); 501 f = f1.subtract(1); 502 assertEquals(Integer.MAX_VALUE-1, f.getNumerator()); 503 assertEquals(1, f.getDenominator()); 504 505 try { 506 f1 = new Fraction(1, Integer.MAX_VALUE); 507 f2 = new Fraction(1, Integer.MAX_VALUE - 1); 508 f = f1.subtract(f2); 509 fail("expecting ArithmeticException"); //should overflow 510 } catch (ArithmeticException ex) {} 511 512 // denominator should not be a multiple of 2 or 3 to trigger overflow 513 f1 = new Fraction(Integer.MIN_VALUE, 5); 514 f2 = new Fraction(1,5); 515 try { 516 f = f1.subtract(f2); // should overflow 517 fail("expecting ArithmeticException but got: " + f.toString()); 518 } catch (ArithmeticException ex) {} 519 520 try { 521 f= new Fraction(Integer.MIN_VALUE, 1); 522 f = f.subtract(Fraction.ONE); 523 fail("expecting ArithmeticException"); 524 } catch (ArithmeticException ex) {} 525 526 try { 527 f= new Fraction(Integer.MAX_VALUE, 1); 528 f = f.subtract(Fraction.ONE.negate()); 529 fail("expecting ArithmeticException"); 530 } catch (ArithmeticException ex) {} 531 532 f1 = new Fraction(3,327680); 533 f2 = new Fraction(2,59049); 534 try { 535 f = f1.subtract(f2); // should overflow 536 fail("expecting ArithmeticException but got: " + f.toString()); 537 } catch (ArithmeticException ex) {} 538 } 539 540 public void testEqualsAndHashCode() { 541 Fraction zero = new Fraction(0,1); 542 Fraction nullFraction = null; 543 assertTrue( zero.equals(zero)); 544 assertFalse(zero.equals(nullFraction)); 545 assertFalse(zero.equals(Double.valueOf(0))); 546 Fraction zero2 = new Fraction(0,2); 547 assertTrue(zero.equals(zero2)); 548 assertEquals(zero.hashCode(), zero2.hashCode()); 549 Fraction one = new Fraction(1,1); 550 assertFalse((one.equals(zero) ||zero.equals(one))); 551 } 552 553 public void testGetReducedFraction() { 554 Fraction threeFourths = new Fraction(3, 4); 555 assertTrue(threeFourths.equals(Fraction.getReducedFraction(6, 8))); 556 assertTrue(Fraction.ZERO.equals(Fraction.getReducedFraction(0, -1))); 557 try { 558 Fraction.getReducedFraction(1, 0); 559 fail("expecting ArithmeticException"); 560 } catch (ArithmeticException ex) { 561 // expected 562 } 563 assertEquals(Fraction.getReducedFraction 564 (2, Integer.MIN_VALUE).getNumerator(),-1); 565 assertEquals(Fraction.getReducedFraction 566 (1, -1).getNumerator(), -1); 567 } 568 569 public void testToString() { 570 assertEquals("0", new Fraction(0, 3).toString()); 571 assertEquals("3", new Fraction(6, 2).toString()); 572 assertEquals("2 / 3", new Fraction(18, 27).toString()); 573 } 574 575 public void testSerial() throws FractionConversionException { 576 Fraction[] fractions = { 577 new Fraction(3, 4), Fraction.ONE, Fraction.ZERO, 578 new Fraction(17), new Fraction(Math.PI, 1000), 579 new Fraction(-5, 2) 580 }; 581 for (Fraction fraction : fractions) { 582 assertEquals(fraction, TestUtils.serializeAndRecover(fraction)); 583 } 584 } 585 586 }