Fraction.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. package me.hammerle.snuviscript.math;
  2. import java.util.TreeSet;
  3. public final class Fraction extends Number implements Comparable<Fraction>
  4. {
  5. private final long numerator;
  6. private final long denominator;
  7. public Fraction(long numerator, long denominator)
  8. {
  9. if(denominator == 0)
  10. {
  11. throw new ArithmeticException();
  12. }
  13. if(denominator != 1)
  14. {
  15. long divisor = getGreatestCommonDivisor(numerator, denominator);
  16. if(divisor != 1)
  17. {
  18. denominator /= divisor;
  19. numerator /= divisor;
  20. }
  21. }
  22. // short fraction
  23. if(denominator < 0)
  24. {
  25. this.denominator = -denominator;
  26. this.numerator = -numerator;
  27. }
  28. else
  29. {
  30. this.denominator = denominator;
  31. this.numerator = numerator;
  32. }
  33. }
  34. public Fraction(long numerator)
  35. {
  36. this(numerator, 1);
  37. }
  38. private static final long DOUBLE_FACTOR = 10000000000l;
  39. public static Fraction fromDouble(double d)
  40. {
  41. if(d == (long) d)
  42. {
  43. return new Fraction((long) d);
  44. }
  45. return new Fraction(Math.round(d * DOUBLE_FACTOR), DOUBLE_FACTOR);
  46. }
  47. // -------------------------------------------------------------------------
  48. // constants, chain fractions
  49. // -------------------------------------------------------------------------
  50. public static final Fraction PI = Fraction.getChainFraction(
  51. //3,7,15,1,292,1,1,1,2,1,3,1,14,2,1,1,2,2,2,2,1,84,2,1,1,15,3,13,1,4,2,6,6
  52. 3,7,15,1,292,1,1,1,2,1,3,1,14,2,1);
  53. public static final Fraction E = Fraction.getChainFraction(
  54. //2,1,2,1,1,4,1,1,6,1,1,8,1,1,10,1,1,12,1,1,14,1,1,16,...
  55. 2,1,2,1,1,4,1,1,6,1,1,8,1,1,10,1,1,12,1,1,14);
  56. public static Fraction getChainFraction(int... ints)
  57. {
  58. if(ints.length == 1)
  59. {
  60. return new Fraction(ints[0]);
  61. }
  62. return new Fraction(ints[0]).add(getChainFractionPart(1, ints));
  63. }
  64. private static Fraction getChainFractionPart(int index, int... ints)
  65. {
  66. if(index + 1 == ints.length)
  67. {
  68. return new Fraction(1, ints[index]);
  69. }
  70. return new Fraction(ints[index]).add(getChainFractionPart(index + 1, ints)).invert();
  71. }
  72. // -------------------------------------------------------------------------
  73. // basic calculating
  74. // -------------------------------------------------------------------------
  75. public Fraction add(Fraction f)
  76. {
  77. if(denominator == f.denominator)
  78. {
  79. return new Fraction(Math.addExact(numerator, f.numerator), denominator);
  80. }
  81. else
  82. {
  83. long l = getLeastCommonMultiple(denominator, f.denominator);
  84. return new Fraction(Math.addExact(Math.multiplyExact(numerator, l / denominator),
  85. Math.multiplyExact(f.numerator, l / f.denominator)), l);
  86. }
  87. }
  88. public Fraction mul(Fraction f)
  89. {
  90. return new Fraction(Math.multiplyExact(numerator, f.numerator),
  91. Math.multiplyExact(denominator, f.denominator));
  92. }
  93. public Fraction sub(Fraction f)
  94. {
  95. return add(f.invertSign());
  96. }
  97. public Fraction div(Fraction f)
  98. {
  99. return mul(f.invert());
  100. }
  101. // -------------------------------------------------------------------------
  102. // roots, power
  103. // -------------------------------------------------------------------------
  104. private static long power(long l, long power)
  105. {
  106. if(power == 1)
  107. {
  108. return l;
  109. }
  110. else if(power == 2)
  111. {
  112. return l * l;
  113. }
  114. long factor = 1;
  115. if(l < 0)
  116. {
  117. factor = (power & 1) == 1 ? -1 : 1;
  118. l = -l;
  119. }
  120. long prod = 1;
  121. while(power > 0)
  122. {
  123. if((power & 1) == 1)
  124. {
  125. prod = Math.multiplyExact(prod, l);
  126. }
  127. power = power >> 1;
  128. l = Math.multiplyExact(l, l);
  129. }
  130. if(factor == -1)
  131. {
  132. return -prod;
  133. }
  134. return prod;
  135. }
  136. private static long rootOfLong(long l, long root)
  137. {
  138. if(l == 0 || l == 1)
  139. {
  140. return l;
  141. }
  142. try
  143. {
  144. TreeSet<Long> tree = new TreeSet<>();
  145. long currentValue = l >> 1; // taking half as start value
  146. long an = currentValue;
  147. do
  148. {
  149. tree.add(currentValue);
  150. currentValue = currentValue - (currentValue / root) + an / power(currentValue, root - 1);
  151. }
  152. while(!tree.contains(currentValue));
  153. return currentValue;
  154. }
  155. catch(ArithmeticException ex)
  156. {
  157. return 0;
  158. }
  159. }
  160. private Fraction root(long root)
  161. {
  162. if(root == 1)
  163. {
  164. return this.copy();
  165. }
  166. // Getting nice start value
  167. Fraction currentValue;
  168. Fraction n = new Fraction(root);
  169. Fraction an = this.div(n);
  170. Fraction newFraction = new Fraction(rootOfLong(numerator, root), rootOfLong(denominator, root));
  171. root--;
  172. try
  173. {
  174. do
  175. {
  176. currentValue = newFraction;
  177. newFraction = currentValue.sub(currentValue.div(n)).add(an.div(currentValue.power(root)));
  178. }
  179. while(!newFraction.equals(currentValue));
  180. }
  181. catch(ArithmeticException ex)
  182. {
  183. }
  184. return newFraction;
  185. }
  186. public Fraction power(Fraction f)
  187. {
  188. if(numerator < 0 && f.denominator != 1)
  189. {
  190. throw new ArithmeticException("root of negative fraction");
  191. }
  192. try
  193. {
  194. if(f.numerator == 0)
  195. {
  196. return new Fraction(1);
  197. }
  198. else if(f.numerator < 0)
  199. {
  200. return this.invert().power(-f.numerator).root(f.denominator);
  201. }
  202. return this.power(f.numerator).root(f.denominator);
  203. }
  204. catch(ArithmeticException ex)
  205. {
  206. return fromDouble(Math.pow(this.doubleValue(), f.doubleValue()));
  207. }
  208. }
  209. private Fraction power(long p)
  210. {
  211. if(p < 0)
  212. {
  213. p = -p;
  214. invert();
  215. }
  216. else if(p == 1)
  217. {
  218. return this.copy();
  219. }
  220. long prodn = 1;
  221. long prodd = 1;
  222. long n = numerator;
  223. long d = denominator;
  224. while(p > 0)
  225. {
  226. if((p & 1) == 1)
  227. {
  228. prodn = Math.multiplyExact(prodn, n);
  229. prodd = Math.multiplyExact(prodd, d);
  230. }
  231. p = p >> 1;
  232. n = Math.multiplyExact(n, n);
  233. d = Math.multiplyExact(d, d);
  234. }
  235. return new Fraction(prodn, prodd);
  236. }
  237. // -------------------------------------------------------------------------
  238. // inverting
  239. // -------------------------------------------------------------------------
  240. public Fraction invertSign()
  241. {
  242. return new Fraction(-numerator, denominator);
  243. }
  244. public Fraction invert()
  245. {
  246. if(numerator == 0)
  247. {
  248. throw new ArithmeticException();
  249. }
  250. else if(numerator < 0)
  251. {
  252. return new Fraction(-denominator, -numerator);
  253. }
  254. return new Fraction(denominator, numerator);
  255. }
  256. public boolean isNegative()
  257. {
  258. return numerator < 0;
  259. }
  260. public boolean isLong()
  261. {
  262. return denominator == 1;
  263. }
  264. // -------------------------------------------------------------------------
  265. // functions from math library
  266. // -------------------------------------------------------------------------
  267. public Fraction abs()
  268. {
  269. return new Fraction(Math.abs(numerator), denominator);
  270. }
  271. public Fraction acos()
  272. {
  273. return Fraction.fromDouble(Math.acos(doubleValue()));
  274. }
  275. public Fraction asin()
  276. {
  277. return Fraction.fromDouble(Math.asin(doubleValue()));
  278. }
  279. public Fraction atan()
  280. {
  281. return Fraction.fromDouble(Math.atan(doubleValue()));
  282. }
  283. public Fraction atan2(Fraction f)
  284. {
  285. return Fraction.fromDouble(Math.atan2(doubleValue(), f.doubleValue()));
  286. }
  287. public Fraction cbrt()
  288. {
  289. return this.power(new Fraction(1, 3));
  290. }
  291. public Fraction ceil()
  292. {
  293. return Fraction.fromDouble(Math.ceil(doubleValue()));
  294. }
  295. public Fraction cos()
  296. {
  297. return Fraction.fromDouble(Math.cos(doubleValue()));
  298. }
  299. public Fraction cosh()
  300. {
  301. return Fraction.fromDouble(Math.cosh(doubleValue()));
  302. }
  303. public Fraction floor()
  304. {
  305. return Fraction.fromDouble(Math.floor(doubleValue()));
  306. }
  307. public Fraction log()
  308. {
  309. return Fraction.fromDouble(Math.log(doubleValue()));
  310. }
  311. public Fraction log10()
  312. {
  313. return Fraction.fromDouble(Math.log10(doubleValue()));
  314. }
  315. public Fraction log1p()
  316. {
  317. return Fraction.fromDouble(Math.log1p(doubleValue()));
  318. }
  319. public Fraction max(Fraction f)
  320. {
  321. if(this.compareTo(f) < 0)
  322. {
  323. return f;
  324. }
  325. return this;
  326. }
  327. public Fraction min(Fraction f)
  328. {
  329. if(this.compareTo(f) > 0)
  330. {
  331. return f;
  332. }
  333. return this;
  334. }
  335. public Fraction rint()
  336. {
  337. return Fraction.fromDouble(Math.rint(doubleValue()));
  338. }
  339. public Fraction round()
  340. {
  341. return Fraction.fromDouble(Math.round(doubleValue()));
  342. }
  343. public Fraction round(int times)
  344. {
  345. if(times < 0)
  346. {
  347. throw new IllegalArgumentException("a positive number of decimal points is needed");
  348. }
  349. int factor = 1;
  350. while(times > 0)
  351. {
  352. factor *= 10;
  353. times--;
  354. }
  355. double d = doubleValue() * factor;
  356. return new Fraction(Math.round(d), factor);
  357. }
  358. public Fraction signum()
  359. {
  360. if(numerator < 0)
  361. {
  362. return new Fraction(-1);
  363. }
  364. return new Fraction(1);
  365. }
  366. public Fraction sin()
  367. {
  368. return Fraction.fromDouble(Math.sin(doubleValue()));
  369. }
  370. public Fraction sinh()
  371. {
  372. return Fraction.fromDouble(Math.sinh(doubleValue()));
  373. }
  374. public Fraction tan()
  375. {
  376. return Fraction.fromDouble(Math.tan(doubleValue()));
  377. }
  378. public Fraction tanh()
  379. {
  380. return Fraction.fromDouble(Math.tanh(doubleValue()));
  381. }
  382. public Fraction toDegrees()
  383. {
  384. return Fraction.fromDouble(Math.toDegrees(doubleValue()));
  385. }
  386. public Fraction toRadians()
  387. {
  388. return Fraction.fromDouble(Math.toRadians(doubleValue()));
  389. }
  390. // -------------------------------------------------------------------------
  391. // simplifying
  392. // -------------------------------------------------------------------------
  393. public Fraction simplify(int times)
  394. {
  395. if(denominator == 1)
  396. {
  397. return this.copy();
  398. }
  399. long d = denominator;
  400. long n = numerator;
  401. int switcher = -1;
  402. for(int i = 0; i < times; i++)
  403. {
  404. if(switcher == -1 && d == 1)
  405. {
  406. d = (d & 1) == 1 ? d + 1: d;
  407. n = (n & 1) == 1 ? n + 1 : n;
  408. switcher = -1;
  409. }
  410. else if(switcher == 1 && d == -1)
  411. {
  412. d = (d & 1) == 1 ? d - 1: d;
  413. n = (n & 1) == 1 ? n - 1 : n;
  414. switcher = 1;
  415. }
  416. else
  417. {
  418. d = (d & 1) == 1 ? d + switcher: d;
  419. n = (n & 1) == 1 ? n + switcher : n;
  420. switcher = -switcher;
  421. }
  422. if(d != 1)
  423. {
  424. long divisor = getGreatestCommonDivisor(n, d);
  425. //System.out.println("DIV: " + divisor);
  426. if(divisor != 1)
  427. {
  428. d /= divisor;
  429. n /= divisor;
  430. }
  431. }
  432. }
  433. return new Fraction(n, d);
  434. }
  435. private long getGreatestCommonDivisor(long i, long n)
  436. {
  437. if(i == 0)
  438. {
  439. return n;
  440. }
  441. if(i < 0)
  442. {
  443. i = -i;
  444. }
  445. if(n < 0)
  446. {
  447. n = -n;
  448. }
  449. long helper;
  450. while(true)
  451. {
  452. if(i < n)
  453. {
  454. helper = i;
  455. i = n;
  456. n = helper;
  457. }
  458. i = i % n;
  459. if(i == 0)
  460. {
  461. return n;
  462. }
  463. }
  464. }
  465. private long getLeastCommonMultiple(long i, long n)
  466. {
  467. return Math.abs(Math.multiplyExact(i, n)) / getGreatestCommonDivisor(i, n);
  468. }
  469. // -------------------------------------------------------------------------
  470. // basic stuff
  471. // -------------------------------------------------------------------------
  472. @Override
  473. public String toString()
  474. {
  475. if(denominator == 1)
  476. {
  477. return String.valueOf(numerator);
  478. }
  479. return numerator + " / " + denominator;
  480. }
  481. private Fraction copy()
  482. {
  483. return new Fraction(numerator, denominator);
  484. }
  485. @Override
  486. public boolean equals(Object o)
  487. {
  488. if(o == null)
  489. {
  490. return false;
  491. }
  492. else if(o.getClass() != Fraction.class)
  493. {
  494. return false;
  495. }
  496. Fraction f = (Fraction) o;
  497. return numerator == f.numerator && denominator == f.denominator;
  498. }
  499. @Override
  500. public int hashCode()
  501. {
  502. int hash = 3;
  503. hash = 97 * hash + (int) (this.numerator ^ (this.numerator >>> 32));
  504. hash = 97 * hash + (int) (this.denominator ^ (this.denominator >>> 32));
  505. return hash;
  506. }
  507. @Override
  508. public int compareTo(Fraction f)
  509. {
  510. if(f.numerator < 0 && numerator >= 0)
  511. {
  512. return 1;
  513. }
  514. else if(f.numerator >= 0 && numerator < 0)
  515. {
  516. return -1;
  517. }
  518. else
  519. {
  520. long i = f.sub(this).numerator;
  521. if(i == 0)
  522. {
  523. return 0;
  524. }
  525. else if(i < 0)
  526. {
  527. return 1;
  528. }
  529. else
  530. {
  531. return -1;
  532. }
  533. }
  534. }
  535. // -------------------------------------------------------------------------
  536. // bit stuff
  537. // -------------------------------------------------------------------------
  538. private void noFraction()
  539. {
  540. if(denominator != 1 && numerator != 0)
  541. {
  542. throw new UnsupportedOperationException("the number must not be a fraction");
  543. }
  544. }
  545. public Fraction rightShift(int times)
  546. {
  547. noFraction();
  548. return new Fraction(numerator >> times);
  549. }
  550. public Fraction leftShift(int times)
  551. {
  552. noFraction();
  553. return new Fraction(numerator << times);
  554. }
  555. public Fraction and(Fraction f)
  556. {
  557. noFraction();
  558. return new Fraction(numerator & f.numerator);
  559. }
  560. public Fraction or(Fraction f)
  561. {
  562. noFraction();
  563. return new Fraction(numerator | f.numerator);
  564. }
  565. public Fraction xor(Fraction f)
  566. {
  567. noFraction();
  568. return new Fraction(numerator ^ f.numerator);
  569. }
  570. public Fraction invertBits()
  571. {
  572. noFraction();
  573. return new Fraction(~numerator);
  574. }
  575. public Fraction setBit(int n)
  576. {
  577. noFraction();
  578. return new Fraction(numerator | 1 << n);
  579. }
  580. public Fraction unsetBit(int n)
  581. {
  582. noFraction();
  583. return new Fraction(numerator & ~(1 << n));
  584. }
  585. public boolean getBit(int n)
  586. {
  587. noFraction();
  588. return (numerator & (1 << n)) != 0;
  589. }
  590. // -------------------------------------------------------------------------
  591. // number stuff
  592. // -------------------------------------------------------------------------
  593. @Override
  594. public int intValue()
  595. {
  596. return (int) longValue();
  597. }
  598. @Override
  599. public long longValue()
  600. {
  601. return numerator / denominator;
  602. }
  603. @Override
  604. public float floatValue()
  605. {
  606. return (float) doubleValue();
  607. }
  608. @Override
  609. public double doubleValue()
  610. {
  611. return numerator / (double) denominator;
  612. }
  613. }