I've been working though Project Euler problems using JavaScript, and along the way I've found it useful to create "classes" for different types of numbers (like an integer that can be arbitrarily large). I recently decided to create a sort of class for Fractions to avoid floating point error.
I wrote the code using a more functional/procedural approach; however, I'm concerned that since JavaScript can't use types to distinguish functions that the function names will overlap with other code I write. I'm also looking for shorter names or better syntax to simplify how messy the math can get as shown in my tests. Here's a JSFiddle if you'd like to see the code in action.
General Global Functions
// Calculates the greatest common factor of two positive integers
function gcf(p, q) {
if (p > q) return gcf(q, p);
else if (p === 0) return q;
else return gcf(q % p, p);
}
// Reduces two numbers by their greatest common factor
function gcd(p, q) {
var f = gcf(p, q);
return [
p / f,
q / f
];
}
Fraction Constructor
function createFraction(n, d) {
if (d < 0) {
n *= -1;
d *= -1;
}
var f0 = reduce({
n: n,
d: d
});
return f0;
}
Fraction Utility Functions
function reduce(f0) {
var f = gcf(Math.abs(f0.n), f0.d);
f0.n /= f;
f0.d /= f;
return f0;
}
function invert(f0) {
return createFraction(
f0.d,
f0.n
);
}
function negate(f0) {
return createFraction(
f0.n * -1,
f0.d
);
}
Fraction Basic Math Functions
function multiply(f1, f2) {
return createFraction(
f1.n * f2.n,
f1.d * f2.d
);
}
function divide(f1, f2) {
return multiply(f1, invert(f2));
}
function add(f1, f2) {
var r = gcd(f1.d, f2.d);
return createFraction(
f1.n * r[1] + f2.n * r[0],
f1.d * r[1]
);
}
function subtract(f1, f2) {
return add(f1, negate(f2));
}
Testing Code
function equals(f1, f2) {
return f1.n === f2.n &&
f1.d === f2.d;
}
function toString(f0) {
return f0.n + "/" + f0.d;
}
function testEquals(line, f1, f2) {
if (!equals(f1, f2)) console.log(line + " failed: " + toString(f1) + " !== " + toString(f2));
else console.log(line + " good: " + toString(f1));
}
var line = 0;
testEquals(line++, add(createFraction(10, 40), createFraction(3, 30)), createFraction(7, 20));
testEquals(line++, subtract(createFraction(8, 3), createFraction(11, 30)), createFraction(69, 30));
testEquals(line++, multiply(createFraction(8, 3), createFraction(11, 30)), createFraction(88, 90));
testEquals(line++, divide(createFraction(8, 3), createFraction(11, 30)), createFraction(240, 33));
testEquals(line++, add(createFraction(-5, 8), createFraction(-1, -2)), createFraction(-1, 8));
testEquals(line++, subtract(createFraction(10, 40), createFraction(-3, 30)), createFraction(7, 20));
testEquals(line++, multiply(createFraction(-8, 3), createFraction(-11, 30)), createFraction(88, 90));
testEquals(line++, divide(createFraction(8, -3), createFraction(11, -30)), createFraction(240, 33));