2019-06-09 22:13:46 +02:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<html lang="en">
|
|
|
|
<head>
|
|
|
|
<meta charset="utf-8">
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
2019-06-09 22:48:31 +02:00
|
|
|
<meta name="author" content="Felix W. Dekker" />
|
|
|
|
<meta name="application-name" content="Dice probabilities" />
|
|
|
|
<meta name="description" content="Calculates the probability of throwing a value given a combination of dice." />
|
|
|
|
<meta name="theme-color" content="#0033cc" />
|
2019-06-09 22:13:46 +02:00
|
|
|
|
2019-06-09 22:48:31 +02:00
|
|
|
<title>Simplify fractions | FWDekker</title>
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css"
|
|
|
|
integrity="sha256-l85OmPOjvil/SOvVt3HnSSjzF1TUMyT9eV0c2BzEGzU=" crossorigin="anonymous" />
|
|
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.3.0/milligram.min.css"
|
|
|
|
integrity="sha256-Ro/wP8uUi8LR71kwIdilf78atpu8bTEwrK5ZotZo+Zc=" crossorigin="anonymous" />
|
2019-06-09 22:13:46 +02:00
|
|
|
|
|
|
|
<style>
|
|
|
|
body {
|
2019-06-09 22:48:31 +02:00
|
|
|
margin-top: 50px;
|
|
|
|
margin-bottom: 50px;
|
2019-06-09 22:13:46 +02:00
|
|
|
}
|
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div class="container">
|
2019-06-09 22:48:31 +02:00
|
|
|
<h1>Simplify fractions</h1>
|
|
|
|
<blockquote>
|
|
|
|
<p><em>Simplify a fraction to eliminate common factors.</em></p>
|
|
|
|
</blockquote>
|
2019-06-09 22:13:46 +02:00
|
|
|
|
2019-06-09 22:48:31 +02:00
|
|
|
<form>
|
|
|
|
<fieldset>
|
|
|
|
<label for="numerator">Numerator</label>
|
|
|
|
<input type="number" id="numerator" min="-2147483647" max="2147483647" autofocus />
|
2019-06-09 22:13:46 +02:00
|
|
|
|
2019-06-09 22:48:31 +02:00
|
|
|
<label for="denominator">Denominator</label>
|
|
|
|
<input type="number" id="denominator" min="-2147483647" max="2147483647" />
|
2019-06-09 22:13:46 +02:00
|
|
|
|
2019-06-09 23:13:17 +02:00
|
|
|
<button type="button" id="submit">Calculator</button>
|
2019-06-09 22:48:31 +02:00
|
|
|
</fieldset>
|
|
|
|
</form>
|
2019-06-09 22:13:46 +02:00
|
|
|
|
2019-06-09 22:48:31 +02:00
|
|
|
<span id="out"></span>
|
|
|
|
</div>
|
2019-06-09 22:13:46 +02:00
|
|
|
|
2019-06-09 22:48:31 +02:00
|
|
|
|
|
|
|
<!-- Scripts -->
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML"
|
|
|
|
integrity="sha256-nvJJv9wWKEm88qvoQl9ekL2J+k/RWIsaSScxxlsrv8k=" crossorigin="anonymous"></script>
|
2019-06-09 22:28:16 +02:00
|
|
|
<script>
|
2019-06-10 00:40:29 +02:00
|
|
|
class Fraction {
|
|
|
|
constructor(numerator, denominator) {
|
|
|
|
if (!isInt(numerator) || !isInt(denominator))
|
|
|
|
throw new Error("Numerator and denominator must be integer-like.");
|
|
|
|
|
2019-06-10 00:42:45 +02:00
|
|
|
this.sign = xor(numerator < 0, denominator < 0) ? -1 : 1;
|
2019-06-10 00:40:29 +02:00
|
|
|
this.numerator = Math.abs(+numerator);
|
|
|
|
this.denominator = Math.abs(+denominator);
|
|
|
|
}
|
2019-06-09 23:13:17 +02:00
|
|
|
|
2019-06-10 00:40:29 +02:00
|
|
|
|
|
|
|
simplify() {
|
|
|
|
const common = gcd(this.numerator, this.denominator);
|
|
|
|
return new Fraction(this.sign * this.numerator / common, this.denominator / common);
|
|
|
|
}
|
|
|
|
|
|
|
|
toString() {
|
|
|
|
let frac = `\\frac{${this.numerator}}{${this.denominator}}`;
|
|
|
|
if (this.sign === -1)
|
|
|
|
frac = `-${frac}`;
|
|
|
|
|
|
|
|
return frac;
|
|
|
|
}
|
|
|
|
|
|
|
|
toReducedString() {
|
|
|
|
if (this.numerator === 0)
|
|
|
|
return "0";
|
|
|
|
|
|
|
|
let frac;
|
|
|
|
if (this.denominator === 1)
|
|
|
|
frac = `${this.numerator}`;
|
|
|
|
else
|
|
|
|
frac = `\\frac{${this.numerator}}{${this.denominator}}`;
|
|
|
|
|
|
|
|
if (this.sign === -1)
|
|
|
|
frac = `-${frac}`;
|
|
|
|
|
|
|
|
return frac;
|
|
|
|
}
|
|
|
|
}
|
2019-06-09 22:28:16 +02:00
|
|
|
|
2019-06-09 22:48:31 +02:00
|
|
|
const xor = (a, b) => (a || b) && !(a && b);
|
2019-06-09 22:28:16 +02:00
|
|
|
|
2019-06-09 23:13:17 +02:00
|
|
|
// noinspection EqualityComparisonWithCoercionJS
|
|
|
|
const isInt = n => n == parseInt(n);
|
2019-06-09 22:28:16 +02:00
|
|
|
|
2019-06-09 23:59:45 +02:00
|
|
|
const factorize = n => {
|
2019-06-09 23:13:17 +02:00
|
|
|
if (!isInt(n))
|
|
|
|
return undefined;
|
2019-06-09 22:28:16 +02:00
|
|
|
|
|
|
|
n = +n;
|
|
|
|
|
2019-06-09 23:59:45 +02:00
|
|
|
if (n <= 0)
|
|
|
|
return undefined;
|
|
|
|
|
2019-06-10 00:08:24 +02:00
|
|
|
if (n === 1)
|
|
|
|
return [1];
|
2019-06-09 22:28:16 +02:00
|
|
|
|
2019-06-09 23:59:45 +02:00
|
|
|
|
2019-06-09 23:13:17 +02:00
|
|
|
const factors = [];
|
2019-06-09 22:28:16 +02:00
|
|
|
while (n % 2 === 0) {
|
|
|
|
factors.push(2);
|
|
|
|
n /= 2;
|
|
|
|
}
|
|
|
|
while (n % 3 === 0) {
|
|
|
|
factors.push(3);
|
|
|
|
n /= 3;
|
|
|
|
}
|
|
|
|
|
2019-06-09 23:13:17 +02:00
|
|
|
for (let i = 5; i <= n; i += ((i - 1) % 6 === 0) ? 4 : 2) {
|
2019-06-09 22:28:16 +02:00
|
|
|
while (n % i === 0) {
|
|
|
|
factors.push(i);
|
|
|
|
n /= i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return factors;
|
|
|
|
};
|
|
|
|
|
2019-06-09 23:59:45 +02:00
|
|
|
const defactorize = factors => {
|
|
|
|
let accumulator = 1;
|
|
|
|
for (let i = 0; i < factors.length; i++)
|
|
|
|
accumulator *= factors[i];
|
2019-06-09 22:28:16 +02:00
|
|
|
|
2019-06-09 23:59:45 +02:00
|
|
|
return accumulator;
|
|
|
|
};
|
2019-06-09 22:28:16 +02:00
|
|
|
|
2019-06-09 23:59:45 +02:00
|
|
|
const gcd = (a, b) => {
|
|
|
|
const aFactors = factorize(a);
|
|
|
|
const bFactors = factorize(b);
|
2019-06-09 22:28:16 +02:00
|
|
|
|
2019-06-09 23:59:45 +02:00
|
|
|
const overlap = [];
|
2019-06-09 22:28:16 +02:00
|
|
|
|
2019-06-09 23:59:45 +02:00
|
|
|
for (let aIndex = 0; aIndex < aFactors.length; aIndex++) {
|
|
|
|
const bIndex = bFactors.indexOf(aFactors[aIndex]);
|
|
|
|
if (bIndex >= 0) {
|
|
|
|
overlap.push(aFactors[aIndex]);
|
|
|
|
bFactors.splice(bIndex, 1);
|
2019-06-09 22:28:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-09 23:59:45 +02:00
|
|
|
return defactorize(overlap);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2019-06-10 00:40:29 +02:00
|
|
|
const $ = (query) => document.querySelector(query);
|
2019-06-09 23:59:45 +02:00
|
|
|
|
2019-06-10 00:40:29 +02:00
|
|
|
const numeratorInput = $("#numerator");
|
|
|
|
const denominatorInput = $("#denominator");
|
|
|
|
const submitButton = $("#submit");
|
|
|
|
const outputField = $("#out");
|
2019-06-09 22:28:16 +02:00
|
|
|
|
2019-06-10 00:40:29 +02:00
|
|
|
const outputSimplifiedFraction = () => {
|
|
|
|
let numerator = numeratorInput.value;
|
|
|
|
let denominator = denominatorInput.value;
|
2019-06-09 23:59:45 +02:00
|
|
|
|
2019-06-10 00:43:44 +02:00
|
|
|
if (!isInt(numerator) || !isInt(denominator)) {
|
2019-06-10 00:40:29 +02:00
|
|
|
outputField.innerText = "The numerator and denominator must be integers.";
|
2019-06-10 00:43:44 +02:00
|
|
|
return;
|
|
|
|
}
|
2019-06-09 22:28:16 +02:00
|
|
|
|
2019-06-10 00:40:29 +02:00
|
|
|
const fraction = new Fraction(numerator, denominator);
|
|
|
|
outputField.innerText = "$$" + fraction.toString() + " = " + fraction.simplify().toReducedString() + "$$";
|
2019-06-09 22:28:16 +02:00
|
|
|
|
|
|
|
MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
|
|
|
|
};
|
|
|
|
|
2019-06-10 00:40:29 +02:00
|
|
|
submitButton.onclick = () => {
|
|
|
|
outputSimplifiedFraction();
|
|
|
|
numeratorInput.select();
|
|
|
|
};
|
2019-06-09 23:59:45 +02:00
|
|
|
|
2019-06-10 00:40:29 +02:00
|
|
|
numeratorInput.addEventListener("keydown", event => {
|
|
|
|
if (event.key === "Enter") {
|
|
|
|
if (denominatorInput.value === "") {
|
|
|
|
denominatorInput.select();
|
|
|
|
} else {
|
|
|
|
outputSimplifiedFraction();
|
|
|
|
numeratorInput.select();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
denominatorInput.addEventListener("keydown", event => {
|
|
|
|
if (event.key === "Enter") {
|
|
|
|
if (numeratorInput.value === "") {
|
|
|
|
numeratorInput.select();
|
|
|
|
} else {
|
|
|
|
outputSimplifiedFraction();
|
|
|
|
denominatorInput.select();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2019-06-09 22:28:16 +02:00
|
|
|
</script>
|
2019-06-09 22:13:46 +02:00
|
|
|
</body>
|
|
|
|
</html>
|