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 22:48:31 +02:00
|
|
|
<input type="submit" value="Calculate" id="submit" />
|
|
|
|
</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>
|
|
|
|
"use strict";
|
|
|
|
|
2019-06-09 22:48:31 +02:00
|
|
|
const xor = (a, b) => (a || b) && !(a && b);
|
2019-06-09 22:28:16 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Determines whether something is an integer.
|
|
|
|
*
|
|
|
|
* @method isInt
|
|
|
|
* @param {Object} any Object.
|
|
|
|
* @return {boolean} true iff given Object is an integer.
|
|
|
|
*/
|
|
|
|
var isInt = function (n) {
|
|
|
|
if (isNaN(n)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
var x = parseFloat(n);
|
|
|
|
return (x | 0) === x;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns array of given integer's prime factors.
|
|
|
|
*
|
|
|
|
* @method primeFactors
|
|
|
|
* @param {number} n an integer.
|
|
|
|
* @return {Array} an array of integers which are the given integer's prime
|
|
|
|
* factors, or undefined if the input is not an integer;
|
|
|
|
* an empty array is returned for inputs below 2.
|
|
|
|
*/
|
|
|
|
var primeFactors = function (n) {
|
|
|
|
// Cast to integer
|
|
|
|
n = +n;
|
|
|
|
|
|
|
|
if (!isInt(n)) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Integers < 2 have no prime factors
|
|
|
|
if (n < 2) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine factors
|
|
|
|
var factors = [];
|
|
|
|
while (n % 2 === 0) {
|
|
|
|
factors.push(2);
|
|
|
|
n /= 2;
|
|
|
|
}
|
|
|
|
while (n % 3 === 0) {
|
|
|
|
factors.push(3);
|
|
|
|
n /= 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var i = 5; i <= n; i += ((i - 1) % 6 === 0) ? 4 : 2) {
|
|
|
|
while (n % i === 0) {
|
|
|
|
factors.push(i);
|
|
|
|
n /= i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return factors;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Minimises a fraction and returns an array of integers
|
|
|
|
* [numerator, denominator].
|
|
|
|
*
|
|
|
|
* @method minimise
|
|
|
|
* @param {number} numer the numerator.
|
|
|
|
* @param {number} denom the denominator.
|
|
|
|
* @return {Array} an array of integers [numerator, denominator]
|
|
|
|
* representing a minimal fraction.
|
|
|
|
*/
|
|
|
|
var minimise = function (numer, denom) {
|
|
|
|
// Cast to integer
|
|
|
|
numer = +numer;
|
|
|
|
denom = +denom;
|
|
|
|
|
|
|
|
if (!isInt(numer) || !isInt(denom) || denom === 0) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Short-circuit
|
|
|
|
if (numer === 0) {
|
|
|
|
return [0, 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Minimise
|
|
|
|
var sign = (xor(numer < 0, denom < 0) ? -1 : 1);
|
|
|
|
var factor, factors = primeFactors(numer);
|
|
|
|
|
|
|
|
if (factors === undefined) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var len = factors.length, i = 0; i < len; i++) {
|
|
|
|
factor = factors[i];
|
|
|
|
if (denom % factor === 0) {
|
|
|
|
numer /= factor;
|
|
|
|
denom /= factor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Return minimised values
|
|
|
|
return [sign * Math.abs(numer), Math.abs(denom)];
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Formats a fraction.
|
|
|
|
*
|
|
|
|
* @method formatFraction
|
|
|
|
* @param {Array} fraction the fraction as an array of integers
|
|
|
|
* [numerator, denominator].
|
|
|
|
* @param {boolean} check false iff the denominator should always be
|
|
|
|
* displayed.
|
|
|
|
* @param {string} prefix the prefix to be put in front of the
|
|
|
|
* formatted fraction, is formatting is
|
|
|
|
* applicable.
|
|
|
|
* @return {string} the formatted fraction.
|
|
|
|
*/
|
|
|
|
var formatFraction = function (fraction, check, prefix) {
|
|
|
|
check = (check === undefined ? true : check);
|
|
|
|
prefix = (prefix === undefined ? "" : prefix);
|
|
|
|
|
|
|
|
var numer = +fraction[0],
|
|
|
|
denom = +fraction[1];
|
|
|
|
|
|
|
|
if (!check || !(numer == denom || numer == "0" || numer == "-0" || denom == "1")) {
|
|
|
|
return prefix + "\\frac{" + numer + "}{" + denom + "}";
|
|
|
|
} else {
|
|
|
|
return prefix + numer;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Formats a fraction in another way.
|
|
|
|
*
|
|
|
|
* @method formatFraction2
|
|
|
|
* @param {Array} fraction the fraction as an array of integers
|
|
|
|
* [numerator, denominator].
|
|
|
|
* @param {string} prefix the prefix to be put in front of the
|
|
|
|
* formatted fraction, is formatting is
|
|
|
|
* applicable.
|
|
|
|
* @return {number} { description_of_the_return_value }
|
|
|
|
*/
|
|
|
|
var formatFraction2 = function (fraction, prefix) {
|
|
|
|
// Default parameter values
|
|
|
|
prefix = (prefix === undefined ? "" : prefix);
|
|
|
|
|
|
|
|
// Cast to integers
|
|
|
|
var numer = +fraction[0],
|
|
|
|
denom = +fraction[1];
|
|
|
|
|
|
|
|
// No formatting needed
|
|
|
|
if (numer <= denom || numer == "0" || numer == "-0" || denom == "1") {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Format
|
|
|
|
var sign = (xor(numer < 0, denom < 0) ? -1 : 1);
|
|
|
|
var base = sign * Math.floor(Math.abs(numer) / Math.abs(denom));
|
|
|
|
var mod = Math.abs(numer) % Math.abs(denom);
|
|
|
|
|
|
|
|
return prefix + base + " + " + formatFraction([Math.abs(mod), Math.abs(denom)]);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Handles input
|
|
|
|
var calculateMinimalFraction = function () {
|
|
|
|
// Cast inputs to integers
|
|
|
|
var numer = +(document.getElementById("numerator").value),
|
|
|
|
denom = +(document.getElementById("denominator").value);
|
|
|
|
var out = document.getElementById("out");
|
|
|
|
|
|
|
|
// Check if both are integers
|
|
|
|
if (!isInt(numer) || !isInt(denom)) {
|
|
|
|
out.innerHTML = "The numerator and denominator must be integers.";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Minimise fraction
|
|
|
|
var fraction = minimise(numer, denom);
|
|
|
|
|
|
|
|
out.innerHTML = "" +
|
|
|
|
"$$" +
|
|
|
|
/*formatFraction([numer, denom], false) + */
|
|
|
|
formatFraction(fraction, true, " = ") +
|
|
|
|
formatFraction2(fraction, " = ") +
|
|
|
|
"$$";
|
|
|
|
|
2019-06-09 22:48:31 +02:00
|
|
|
console.log("DO IT");
|
2019-06-09 22:28:16 +02:00
|
|
|
MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Event listeners
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
|
|
var submit = document.getElementById("submit");
|
|
|
|
|
|
|
|
submit.addEventListener(
|
|
|
|
"click",
|
|
|
|
function (e) {
|
|
|
|
e.preventDefault();
|
|
|
|
calculateMinimalFraction();
|
|
|
|
},
|
|
|
|
false
|
|
|
|
);
|
|
|
|
}, false);
|
|
|
|
document.onkeypress = function (e) {
|
|
|
|
if (!e) {
|
|
|
|
e = window.event;
|
|
|
|
}
|
|
|
|
|
|
|
|
var keyCode = +(e.keyCode || e.which);
|
|
|
|
|
|
|
|
switch (keyCode) {
|
|
|
|
case 13:
|
|
|
|
// Calculate
|
|
|
|
document.getElementById("numerator").focus();
|
|
|
|
document.getElementById("numerator").select();
|
|
|
|
|
|
|
|
calculateMinimalFraction();
|
|
|
|
e.preventDefault();
|
|
|
|
break;
|
|
|
|
case 47:
|
|
|
|
// Select denominator
|
|
|
|
document.getElementById("denominator").focus();
|
|
|
|
document.getElementById("denominator").select();
|
|
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
</script>
|
2019-06-09 22:13:46 +02:00
|
|
|
</body>
|
|
|
|
</html>
|