bigfraction.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895
  1. /**
  2. * @license Fraction.js v4.2.0 23/05/2021
  3. * https://www.xarg.org/2014/03/rational-numbers-in-javascript/
  4. *
  5. * Copyright (c) 2021, Robert Eisele (robert@xarg.org)
  6. * Dual licensed under the MIT or GPL Version 2 licenses.
  7. **/
  8. /**
  9. *
  10. * This class offers the possibility to calculate fractions.
  11. * You can pass a fraction in different formats. Either as array, as double, as string or as an integer.
  12. *
  13. * Array/Object form
  14. * [ 0 => <nominator>, 1 => <denominator> ]
  15. * [ n => <nominator>, d => <denominator> ]
  16. *
  17. * Integer form
  18. * - Single integer value
  19. *
  20. * Double form
  21. * - Single double value
  22. *
  23. * String form
  24. * 123.456 - a simple double
  25. * 123/456 - a string fraction
  26. * 123.'456' - a double with repeating decimal places
  27. * 123.(456) - synonym
  28. * 123.45'6' - a double with repeating last place
  29. * 123.45(6) - synonym
  30. *
  31. * Example:
  32. *
  33. * let f = new Fraction("9.4'31'");
  34. * f.mul([-4, 3]).div(4.9);
  35. *
  36. */
  37. (function(root) {
  38. "use strict";
  39. // Set Identity function to downgrade BigInt to Number if needed
  40. if (!BigInt) BigInt = function(n) { if (isNaN(n)) throw new Error(""); return n; };
  41. const C_ONE = BigInt(1);
  42. const C_ZERO = BigInt(0);
  43. const C_TEN = BigInt(10);
  44. const C_TWO = BigInt(2);
  45. const C_FIVE = BigInt(5);
  46. // Maximum search depth for cyclic rational numbers. 2000 should be more than enough.
  47. // Example: 1/7 = 0.(142857) has 6 repeating decimal places.
  48. // If MAX_CYCLE_LEN gets reduced, long cycles will not be detected and toString() only gets the first 10 digits
  49. const MAX_CYCLE_LEN = 2000;
  50. // Parsed data to avoid calling "new" all the time
  51. const P = {
  52. "s": C_ONE,
  53. "n": C_ZERO,
  54. "d": C_ONE
  55. };
  56. function assign(n, s) {
  57. try {
  58. n = BigInt(n);
  59. } catch (e) {
  60. throw Fraction['InvalidParameter'];
  61. }
  62. return n * s;
  63. }
  64. // Creates a new Fraction internally without the need of the bulky constructor
  65. function newFraction(n, d) {
  66. if (d === C_ZERO) {
  67. throw Fraction['DivisionByZero'];
  68. }
  69. const f = Object.create(Fraction.prototype);
  70. f["s"] = n < C_ZERO ? -C_ONE : C_ONE;
  71. n = n < C_ZERO ? -n : n;
  72. const a = gcd(n, d);
  73. f["n"] = n / a;
  74. f["d"] = d / a;
  75. return f;
  76. }
  77. function factorize(num) {
  78. const factors = {};
  79. let n = num;
  80. let i = C_TWO;
  81. let s = C_FIVE - C_ONE;
  82. while (s <= n) {
  83. while (n % i === C_ZERO) {
  84. n/= i;
  85. factors[i] = (factors[i] || C_ZERO) + C_ONE;
  86. }
  87. s+= C_ONE + C_TWO * i++;
  88. }
  89. if (n !== num) {
  90. if (n > 1)
  91. factors[n] = (factors[n] || C_ZERO) + C_ONE;
  92. } else {
  93. factors[num] = (factors[num] || C_ZERO) + C_ONE;
  94. }
  95. return factors;
  96. }
  97. const parse = function(p1, p2) {
  98. let n = C_ZERO, d = C_ONE, s = C_ONE;
  99. if (p1 === undefined || p1 === null) {
  100. /* void */
  101. } else if (p2 !== undefined) {
  102. n = BigInt(p1);
  103. d = BigInt(p2);
  104. s = n * d;
  105. if (n % C_ONE !== C_ZERO || d % C_ONE !== C_ZERO) {
  106. throw Fraction['NonIntegerParameter'];
  107. }
  108. } else if (typeof p1 === "object") {
  109. if ("d" in p1 && "n" in p1) {
  110. n = BigInt(p1["n"]);
  111. d = BigInt(p1["d"]);
  112. if ("s" in p1)
  113. n*= BigInt(p1["s"]);
  114. } else if (0 in p1) {
  115. n = BigInt(p1[0]);
  116. if (1 in p1)
  117. d = BigInt(p1[1]);
  118. } else if (p1 instanceof BigInt) {
  119. n = BigInt(p1);
  120. } else {
  121. throw Fraction['InvalidParameter'];
  122. }
  123. s = n * d;
  124. } else if (typeof p1 === "bigint") {
  125. n = p1;
  126. s = p1;
  127. d = BigInt(1);
  128. } else if (typeof p1 === "number") {
  129. if (isNaN(p1)) {
  130. throw Fraction['InvalidParameter'];
  131. }
  132. if (p1 < 0) {
  133. s = -C_ONE;
  134. p1 = -p1;
  135. }
  136. if (p1 % 1 === 0) {
  137. n = BigInt(p1);
  138. } else if (p1 > 0) { // check for != 0, scale would become NaN (log(0)), which converges really slow
  139. let z = 1;
  140. let A = 0, B = 1;
  141. let C = 1, D = 1;
  142. let N = 10000000;
  143. if (p1 >= 1) {
  144. z = 10 ** Math.floor(1 + Math.log10(p1));
  145. p1/= z;
  146. }
  147. // Using Farey Sequences
  148. while (B <= N && D <= N) {
  149. let M = (A + C) / (B + D);
  150. if (p1 === M) {
  151. if (B + D <= N) {
  152. n = A + C;
  153. d = B + D;
  154. } else if (D > B) {
  155. n = C;
  156. d = D;
  157. } else {
  158. n = A;
  159. d = B;
  160. }
  161. break;
  162. } else {
  163. if (p1 > M) {
  164. A+= C;
  165. B+= D;
  166. } else {
  167. C+= A;
  168. D+= B;
  169. }
  170. if (B > N) {
  171. n = C;
  172. d = D;
  173. } else {
  174. n = A;
  175. d = B;
  176. }
  177. }
  178. }
  179. n = BigInt(n) * BigInt(z);
  180. d = BigInt(d);
  181. }
  182. } else if (typeof p1 === "string") {
  183. let ndx = 0;
  184. let v = C_ZERO, w = C_ZERO, x = C_ZERO, y = C_ONE, z = C_ONE;
  185. let match = p1.match(/\d+|./g);
  186. if (match === null)
  187. throw Fraction['InvalidParameter'];
  188. if (match[ndx] === '-') {// Check for minus sign at the beginning
  189. s = -C_ONE;
  190. ndx++;
  191. } else if (match[ndx] === '+') {// Check for plus sign at the beginning
  192. ndx++;
  193. }
  194. if (match.length === ndx + 1) { // Check if it's just a simple number "1234"
  195. w = assign(match[ndx++], s);
  196. } else if (match[ndx + 1] === '.' || match[ndx] === '.') { // Check if it's a decimal number
  197. if (match[ndx] !== '.') { // Handle 0.5 and .5
  198. v = assign(match[ndx++], s);
  199. }
  200. ndx++;
  201. // Check for decimal places
  202. if (ndx + 1 === match.length || match[ndx + 1] === '(' && match[ndx + 3] === ')' || match[ndx + 1] === "'" && match[ndx + 3] === "'") {
  203. w = assign(match[ndx], s);
  204. y = C_TEN ** BigInt(match[ndx].length);
  205. ndx++;
  206. }
  207. // Check for repeating places
  208. if (match[ndx] === '(' && match[ndx + 2] === ')' || match[ndx] === "'" && match[ndx + 2] === "'") {
  209. x = assign(match[ndx + 1], s);
  210. z = C_TEN ** BigInt(match[ndx + 1].length) - C_ONE;
  211. ndx+= 3;
  212. }
  213. } else if (match[ndx + 1] === '/' || match[ndx + 1] === ':') { // Check for a simple fraction "123/456" or "123:456"
  214. w = assign(match[ndx], s);
  215. y = assign(match[ndx + 2], C_ONE);
  216. ndx+= 3;
  217. } else if (match[ndx + 3] === '/' && match[ndx + 1] === ' ') { // Check for a complex fraction "123 1/2"
  218. v = assign(match[ndx], s);
  219. w = assign(match[ndx + 2], s);
  220. y = assign(match[ndx + 4], C_ONE);
  221. ndx+= 5;
  222. }
  223. if (match.length <= ndx) { // Check for more tokens on the stack
  224. d = y * z;
  225. s = /* void */
  226. n = x + d * v + z * w;
  227. } else {
  228. throw Fraction['InvalidParameter'];
  229. }
  230. } else {
  231. throw Fraction['InvalidParameter'];
  232. }
  233. if (d === C_ZERO) {
  234. throw Fraction['DivisionByZero'];
  235. }
  236. P["s"] = s < C_ZERO ? -C_ONE : C_ONE;
  237. P["n"] = n < C_ZERO ? -n : n;
  238. P["d"] = d < C_ZERO ? -d : d;
  239. };
  240. function modpow(b, e, m) {
  241. let r = C_ONE;
  242. for (; e > C_ZERO; b = (b * b) % m, e >>= C_ONE) {
  243. if (e & C_ONE) {
  244. r = (r * b) % m;
  245. }
  246. }
  247. return r;
  248. }
  249. function cycleLen(n, d) {
  250. for (; d % C_TWO === C_ZERO;
  251. d/= C_TWO) {
  252. }
  253. for (; d % C_FIVE === C_ZERO;
  254. d/= C_FIVE) {
  255. }
  256. if (d === C_ONE) // Catch non-cyclic numbers
  257. return C_ZERO;
  258. // If we would like to compute really large numbers quicker, we could make use of Fermat's little theorem:
  259. // 10^(d-1) % d == 1
  260. // However, we don't need such large numbers and MAX_CYCLE_LEN should be the capstone,
  261. // as we want to translate the numbers to strings.
  262. let rem = C_TEN % d;
  263. let t = 1;
  264. for (; rem !== C_ONE; t++) {
  265. rem = rem * C_TEN % d;
  266. if (t > MAX_CYCLE_LEN)
  267. return C_ZERO; // Returning 0 here means that we don't print it as a cyclic number. It's likely that the answer is `d-1`
  268. }
  269. return BigInt(t);
  270. }
  271. function cycleStart(n, d, len) {
  272. let rem1 = C_ONE;
  273. let rem2 = modpow(C_TEN, len, d);
  274. for (let t = 0; t < 300; t++) { // s < ~log10(Number.MAX_VALUE)
  275. // Solve 10^s == 10^(s+t) (mod d)
  276. if (rem1 === rem2)
  277. return BigInt(t);
  278. rem1 = rem1 * C_TEN % d;
  279. rem2 = rem2 * C_TEN % d;
  280. }
  281. return 0;
  282. }
  283. function gcd(a, b) {
  284. if (!a)
  285. return b;
  286. if (!b)
  287. return a;
  288. while (1) {
  289. a%= b;
  290. if (!a)
  291. return b;
  292. b%= a;
  293. if (!b)
  294. return a;
  295. }
  296. }
  297. /**
  298. * Module constructor
  299. *
  300. * @constructor
  301. * @param {number|Fraction=} a
  302. * @param {number=} b
  303. */
  304. function Fraction(a, b) {
  305. parse(a, b);
  306. if (this instanceof Fraction) {
  307. a = gcd(P["d"], P["n"]); // Abuse a
  308. this["s"] = P["s"];
  309. this["n"] = P["n"] / a;
  310. this["d"] = P["d"] / a;
  311. } else {
  312. return newFraction(P['s'] * P['n'], P['d']);
  313. }
  314. }
  315. Fraction['DivisionByZero'] = new Error("Division by Zero");
  316. Fraction['InvalidParameter'] = new Error("Invalid argument");
  317. Fraction['NonIntegerParameter'] = new Error("Parameters must be integer");
  318. Fraction.prototype = {
  319. "s": C_ONE,
  320. "n": C_ZERO,
  321. "d": C_ONE,
  322. /**
  323. * Calculates the absolute value
  324. *
  325. * Ex: new Fraction(-4).abs() => 4
  326. **/
  327. "abs": function() {
  328. return newFraction(this["n"], this["d"]);
  329. },
  330. /**
  331. * Inverts the sign of the current fraction
  332. *
  333. * Ex: new Fraction(-4).neg() => 4
  334. **/
  335. "neg": function() {
  336. return newFraction(-this["s"] * this["n"], this["d"]);
  337. },
  338. /**
  339. * Adds two rational numbers
  340. *
  341. * Ex: new Fraction({n: 2, d: 3}).add("14.9") => 467 / 30
  342. **/
  343. "add": function(a, b) {
  344. parse(a, b);
  345. return newFraction(
  346. this["s"] * this["n"] * P["d"] + P["s"] * this["d"] * P["n"],
  347. this["d"] * P["d"]
  348. );
  349. },
  350. /**
  351. * Subtracts two rational numbers
  352. *
  353. * Ex: new Fraction({n: 2, d: 3}).add("14.9") => -427 / 30
  354. **/
  355. "sub": function(a, b) {
  356. parse(a, b);
  357. return newFraction(
  358. this["s"] * this["n"] * P["d"] - P["s"] * this["d"] * P["n"],
  359. this["d"] * P["d"]
  360. );
  361. },
  362. /**
  363. * Multiplies two rational numbers
  364. *
  365. * Ex: new Fraction("-17.(345)").mul(3) => 5776 / 111
  366. **/
  367. "mul": function(a, b) {
  368. parse(a, b);
  369. return newFraction(
  370. this["s"] * P["s"] * this["n"] * P["n"],
  371. this["d"] * P["d"]
  372. );
  373. },
  374. /**
  375. * Divides two rational numbers
  376. *
  377. * Ex: new Fraction("-17.(345)").inverse().div(3)
  378. **/
  379. "div": function(a, b) {
  380. parse(a, b);
  381. return newFraction(
  382. this["s"] * P["s"] * this["n"] * P["d"],
  383. this["d"] * P["n"]
  384. );
  385. },
  386. /**
  387. * Clones the actual object
  388. *
  389. * Ex: new Fraction("-17.(345)").clone()
  390. **/
  391. "clone": function() {
  392. return newFraction(this['s'] * this['n'], this['d']);
  393. },
  394. /**
  395. * Calculates the modulo of two rational numbers - a more precise fmod
  396. *
  397. * Ex: new Fraction('4.(3)').mod([7, 8]) => (13/3) % (7/8) = (5/6)
  398. **/
  399. "mod": function(a, b) {
  400. if (a === undefined) {
  401. return newFraction(this["s"] * this["n"] % this["d"], C_ONE);
  402. }
  403. parse(a, b);
  404. if (0 === P["n"] && 0 === this["d"]) {
  405. throw Fraction['DivisionByZero'];
  406. }
  407. /*
  408. * First silly attempt, kinda slow
  409. *
  410. return that["sub"]({
  411. "n": num["n"] * Math.floor((this.n / this.d) / (num.n / num.d)),
  412. "d": num["d"],
  413. "s": this["s"]
  414. });*/
  415. /*
  416. * New attempt: a1 / b1 = a2 / b2 * q + r
  417. * => b2 * a1 = a2 * b1 * q + b1 * b2 * r
  418. * => (b2 * a1 % a2 * b1) / (b1 * b2)
  419. */
  420. return newFraction(
  421. this["s"] * (P["d"] * this["n"]) % (P["n"] * this["d"]),
  422. P["d"] * this["d"]
  423. );
  424. },
  425. /**
  426. * Calculates the fractional gcd of two rational numbers
  427. *
  428. * Ex: new Fraction(5,8).gcd(3,7) => 1/56
  429. */
  430. "gcd": function(a, b) {
  431. parse(a, b);
  432. // gcd(a / b, c / d) = gcd(a, c) / lcm(b, d)
  433. return newFraction(gcd(P["n"], this["n"]) * gcd(P["d"], this["d"]), P["d"] * this["d"]);
  434. },
  435. /**
  436. * Calculates the fractional lcm of two rational numbers
  437. *
  438. * Ex: new Fraction(5,8).lcm(3,7) => 15
  439. */
  440. "lcm": function(a, b) {
  441. parse(a, b);
  442. // lcm(a / b, c / d) = lcm(a, c) / gcd(b, d)
  443. if (P["n"] === C_ZERO && this["n"] === C_ZERO) {
  444. return newFraction(C_ZERO, C_ONE);
  445. }
  446. return newFraction(P["n"] * this["n"], gcd(P["n"], this["n"]) * gcd(P["d"], this["d"]));
  447. },
  448. /**
  449. * Gets the inverse of the fraction, means numerator and denominator are exchanged
  450. *
  451. * Ex: new Fraction([-3, 4]).inverse() => -4 / 3
  452. **/
  453. "inverse": function() {
  454. return newFraction(this["s"] * this["d"], this["n"]);
  455. },
  456. /**
  457. * Calculates the fraction to some integer exponent
  458. *
  459. * Ex: new Fraction(-1,2).pow(-3) => -8
  460. */
  461. "pow": function(a, b) {
  462. parse(a, b);
  463. // Trivial case when exp is an integer
  464. if (P['d'] === C_ONE) {
  465. if (P['s'] < C_ZERO) {
  466. return newFraction((this['s'] * this["d"]) ** P['n'], this["n"] ** P['n']);
  467. } else {
  468. return newFraction((this['s'] * this["n"]) ** P['n'], this["d"] ** P['n']);
  469. }
  470. }
  471. // Negative roots become complex
  472. // (-a/b)^(c/d) = x
  473. // <=> (-1)^(c/d) * (a/b)^(c/d) = x
  474. // <=> (cos(pi) + i*sin(pi))^(c/d) * (a/b)^(c/d) = x
  475. // <=> (cos(c*pi/d) + i*sin(c*pi/d)) * (a/b)^(c/d) = x # DeMoivre's formula
  476. // From which follows that only for c=0 the root is non-complex
  477. if (this['s'] < C_ZERO) return null;
  478. // Now prime factor n and d
  479. let N = factorize(this['n']);
  480. let D = factorize(this['d']);
  481. // Exponentiate and take root for n and d individually
  482. let n = C_ONE;
  483. let d = C_ONE;
  484. for (let k in N) {
  485. if (k === '1') continue;
  486. if (k === '0') {
  487. n = C_ZERO;
  488. break;
  489. }
  490. N[k]*= P['n'];
  491. if (N[k] % P['d'] === C_ZERO) {
  492. N[k]/= P['d'];
  493. } else return null;
  494. n*= BigInt(k) ** N[k];
  495. }
  496. for (let k in D) {
  497. if (k === '1') continue;
  498. D[k]*= P['n'];
  499. if (D[k] % P['d'] === C_ZERO) {
  500. D[k]/= P['d'];
  501. } else return null;
  502. d*= BigInt(k) ** D[k];
  503. }
  504. if (P['s'] < C_ZERO) {
  505. return newFraction(d, n);
  506. }
  507. return newFraction(n, d);
  508. },
  509. /**
  510. * Check if two rational numbers are the same
  511. *
  512. * Ex: new Fraction(19.6).equals([98, 5]);
  513. **/
  514. "equals": function(a, b) {
  515. parse(a, b);
  516. return this["s"] * this["n"] * P["d"] === P["s"] * P["n"] * this["d"]; // Same as compare() === 0
  517. },
  518. /**
  519. * Check if two rational numbers are the same
  520. *
  521. * Ex: new Fraction(19.6).equals([98, 5]);
  522. **/
  523. "compare": function(a, b) {
  524. parse(a, b);
  525. let t = (this["s"] * this["n"] * P["d"] - P["s"] * P["n"] * this["d"]);
  526. return (C_ZERO < t) - (t < C_ZERO);
  527. },
  528. /**
  529. * Calculates the ceil of a rational number
  530. *
  531. * Ex: new Fraction('4.(3)').ceil() => (5 / 1)
  532. **/
  533. "ceil": function(places) {
  534. places = C_TEN ** BigInt(places || 0);
  535. return newFraction(this["s"] * places * this["n"] / this["d"] +
  536. (places * this["n"] % this["d"] > C_ZERO && this["s"] >= C_ZERO ? C_ONE : C_ZERO),
  537. places);
  538. },
  539. /**
  540. * Calculates the floor of a rational number
  541. *
  542. * Ex: new Fraction('4.(3)').floor() => (4 / 1)
  543. **/
  544. "floor": function(places) {
  545. places = C_TEN ** BigInt(places || 0);
  546. return newFraction(this["s"] * places * this["n"] / this["d"] -
  547. (places * this["n"] % this["d"] > C_ZERO && this["s"] < C_ZERO ? C_ONE : C_ZERO),
  548. places);
  549. },
  550. /**
  551. * Rounds a rational numbers
  552. *
  553. * Ex: new Fraction('4.(3)').round() => (4 / 1)
  554. **/
  555. "round": function(places) {
  556. places = C_TEN ** BigInt(places || 0);
  557. /* Derivation:
  558. s >= 0:
  559. round(n / d) = trunc(n / d) + (n % d) / d >= 0.5 ? 1 : 0
  560. = trunc(n / d) + 2(n % d) >= d ? 1 : 0
  561. s < 0:
  562. round(n / d) =-trunc(n / d) - (n % d) / d > 0.5 ? 1 : 0
  563. =-trunc(n / d) - 2(n % d) > d ? 1 : 0
  564. =>:
  565. round(s * n / d) = s * trunc(n / d) + s * (C + 2(n % d) > d ? 1 : 0)
  566. where C = s >= 0 ? 1 : 0, to fix the >= for the positve case.
  567. */
  568. return newFraction(this["s"] * places * this["n"] / this["d"] +
  569. this["s"] * ((this["s"] >= C_ZERO ? C_ONE : C_ZERO) + C_TWO * (places * this["n"] % this["d"]) > this["d"] ? C_ONE : C_ZERO),
  570. places);
  571. },
  572. /**
  573. * Check if two rational numbers are divisible
  574. *
  575. * Ex: new Fraction(19.6).divisible(1.5);
  576. */
  577. "divisible": function(a, b) {
  578. parse(a, b);
  579. return !(!(P["n"] * this["d"]) || ((this["n"] * P["d"]) % (P["n"] * this["d"])));
  580. },
  581. /**
  582. * Returns a decimal representation of the fraction
  583. *
  584. * Ex: new Fraction("100.'91823'").valueOf() => 100.91823918239183
  585. **/
  586. 'valueOf': function() {
  587. // Best we can do so far
  588. return Number(this["s"] * this["n"]) / Number(this["d"]);
  589. },
  590. /**
  591. * Creates a string representation of a fraction with all digits
  592. *
  593. * Ex: new Fraction("100.'91823'").toString() => "100.(91823)"
  594. **/
  595. 'toString': function(dec) {
  596. let N = this["n"];
  597. let D = this["d"];
  598. dec = dec || 15; // 15 = decimal places when no repitation
  599. let cycLen = cycleLen(N, D); // Cycle length
  600. let cycOff = cycleStart(N, D, cycLen); // Cycle start
  601. let str = this['s'] < C_ZERO ? "-" : "";
  602. // Append integer part
  603. str+= N / D;
  604. N%= D;
  605. N*= C_TEN;
  606. if (N)
  607. str+= ".";
  608. if (cycLen) {
  609. for (let i = cycOff; i--;) {
  610. str+= N / D;
  611. N%= D;
  612. N*= C_TEN;
  613. }
  614. str+= "(";
  615. for (let i = cycLen; i--;) {
  616. str+= N / D;
  617. N%= D;
  618. N*= C_TEN;
  619. }
  620. str+= ")";
  621. } else {
  622. for (let i = dec; N && i--;) {
  623. str+= N / D;
  624. N%= D;
  625. N*= C_TEN;
  626. }
  627. }
  628. return str;
  629. },
  630. /**
  631. * Returns a string-fraction representation of a Fraction object
  632. *
  633. * Ex: new Fraction("1.'3'").toFraction() => "4 1/3"
  634. **/
  635. 'toFraction': function(excludeWhole) {
  636. let n = this["n"];
  637. let d = this["d"];
  638. let str = this['s'] < C_ZERO ? "-" : "";
  639. if (d === C_ONE) {
  640. str+= n;
  641. } else {
  642. let whole = n / d;
  643. if (excludeWhole && whole > C_ZERO) {
  644. str+= whole;
  645. str+= " ";
  646. n%= d;
  647. }
  648. str+= n;
  649. str+= '/';
  650. str+= d;
  651. }
  652. return str;
  653. },
  654. /**
  655. * Returns a latex representation of a Fraction object
  656. *
  657. * Ex: new Fraction("1.'3'").toLatex() => "\frac{4}{3}"
  658. **/
  659. 'toLatex': function(excludeWhole) {
  660. let n = this["n"];
  661. let d = this["d"];
  662. let str = this['s'] < C_ZERO ? "-" : "";
  663. if (d === C_ONE) {
  664. str+= n;
  665. } else {
  666. let whole = n / d;
  667. if (excludeWhole && whole > C_ZERO) {
  668. str+= whole;
  669. n%= d;
  670. }
  671. str+= "\\frac{";
  672. str+= n;
  673. str+= '}{';
  674. str+= d;
  675. str+= '}';
  676. }
  677. return str;
  678. },
  679. /**
  680. * Returns an array of continued fraction elements
  681. *
  682. * Ex: new Fraction("7/8").toContinued() => [0,1,7]
  683. */
  684. 'toContinued': function() {
  685. let a = this['n'];
  686. let b = this['d'];
  687. let res = [];
  688. do {
  689. res.push(a / b);
  690. let t = a % b;
  691. a = b;
  692. b = t;
  693. } while (a !== C_ONE);
  694. return res;
  695. },
  696. "simplify": function(eps) {
  697. eps = eps || 0.001;
  698. const thisABS = this['abs']();
  699. const cont = thisABS['toContinued']();
  700. for (let i = 1; i < cont.length; i++) {
  701. let s = newFraction(cont[i - 1], C_ONE);
  702. for (let k = i - 2; k >= 0; k--) {
  703. s = s['inverse']()['add'](cont[k]);
  704. }
  705. if (s['sub'](thisABS)['abs']().valueOf() < eps) {
  706. return s['mul'](this['s']);
  707. }
  708. }
  709. return this;
  710. }
  711. };
  712. if (typeof define === "function" && define["amd"]) {
  713. define([], function() {
  714. return Fraction;
  715. });
  716. } else if (typeof exports === "object") {
  717. Object.defineProperty(exports, "__esModule", { 'value': true });
  718. Fraction['default'] = Fraction;
  719. Fraction['Fraction'] = Fraction;
  720. module['exports'] = Fraction;
  721. } else {
  722. root['Fraction'] = Fraction;
  723. }
  724. })(this);