RosettaCodeData/Task/Convert-decimal-number-to-rational/JavaScript/convert-decimal-number-to-rational.js

77 lines
1.7 KiB
JavaScript
Raw Permalink Normal View History

2023-07-01 11:58:00 -04:00
(() => {
2023-10-02 18:11:16 -07:00
"use strict";
2023-07-01 11:58:00 -04:00
2023-10-02 18:11:16 -07:00
// ---------------- APPROXIMATE RATIO ----------------
// approxRatio :: Real -> Real -> Ratio
const approxRatio = epsilon =>
n => {
const
c = gcdApprox(
0 < epsilon
? epsilon
: (1 / 10000)
)(1, n);
return Ratio(
Math.floor(n / c),
Math.floor(1 / c)
);
};
// gcdApprox :: Real -> (Real, Real) -> Real
const gcdApprox = epsilon =>
(x, y) => {
const _gcd = (a, b) =>
b < epsilon
? a
: _gcd(b, a % b);
return _gcd(Math.abs(x), Math.abs(y));
};
// ---------------------- TEST -----------------------
// main :: IO ()
2023-07-01 11:58:00 -04:00
const main = () =>
2023-10-02 18:11:16 -07:00
// Using a tolerance of 1/10000
[0.9054054, 0.518518, 0.75]
.map(
compose(
showRatio,
approxRatio(0.0001)
2023-07-01 11:58:00 -04:00
)
2023-10-02 18:11:16 -07:00
)
.join("\n");
2023-07-01 11:58:00 -04:00
2023-10-02 18:11:16 -07:00
// ---------------- GENERIC FUNCTIONS ----------------
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
const compose = (...fs) =>
// A function defined by the right-to-left
// composition of all the functions in fs.
fs.reduce(
(f, g) => x => f(g(x)),
x => x
2023-07-01 11:58:00 -04:00
);
// Ratio :: Int -> Int -> Ratio
const Ratio = (n, d) => ({
2023-10-02 18:11:16 -07:00
type: "Ratio",
n,
d
2023-07-01 11:58:00 -04:00
});
// showRatio :: Ratio -> String
const showRatio = nd =>
2023-10-02 18:11:16 -07:00
`${nd.n.toString()}/${nd.d.toString()}`;
2023-07-01 11:58:00 -04:00
// MAIN ---
return main();
})();