website/content/blog/2015-11-15-fractions-js.md

129 lines
7.4 KiB
Markdown
Raw Normal View History

2020-01-15 21:51:49 -05:00
---
id: 398
title: Math with Fractions.js
date: 2015-11-15T12:46:14+00:00
author: Brandon Rozek
layout: post
guid: https://brandonrozek.com/?p=398
aliases:
- /2015/11/fractions-js/
2020-01-15 21:51:49 -05:00
permalink: /2015/11/fractions-js/
medium_post:
- 'O:11:"Medium_Post":11:{s:16:"author_image_url";N;s:10:"author_url";N;s:11:"byline_name";N;s:12:"byline_email";N;s:10:"cross_link";N;s:2:"id";N;s:21:"follower_notification";N;s:7:"license";N;s:14:"publication_id";N;s:6:"status";N;s:3:"url";N;}'
- 'O:11:"Medium_Post":11:{s:16:"author_image_url";s:74:"https://cdn-images-1.medium.com/fit/c/200/200/1*dmbNkD5D-u45r44go_cf0g.png";s:10:"author_url";s:32:"https://medium.com/@brandonrozek";s:11:"byline_name";N;s:12:"byline_email";N;s:10:"cross_link";s:2:"no";s:2:"id";s:12:"dd3b15d9d3c9";s:21:"follower_notification";s:2:"no";s:7:"license";s:19:"all-rights-reserved";s:14:"publication_id";s:2:"-1";s:6:"status";s:6:"public";s:3:"url";s:68:"https://medium.com/@brandonrozek/math-with-fractions-js-dd3b15d9d3c9";}'
- 'O:11:"Medium_Post":11:{s:16:"author_image_url";s:74:"https://cdn-images-1.medium.com/fit/c/200/200/1*dmbNkD5D-u45r44go_cf0g.png";s:10:"author_url";s:32:"https://medium.com/@brandonrozek";s:11:"byline_name";N;s:12:"byline_email";N;s:10:"cross_link";s:2:"no";s:2:"id";s:12:"dd3b15d9d3c9";s:21:"follower_notification";s:2:"no";s:7:"license";s:19:"all-rights-reserved";s:14:"publication_id";s:2:"-1";s:6:"status";s:6:"public";s:3:"url";s:68:"https://medium.com/@brandonrozek/math-with-fractions-js-dd3b15d9d3c9";}'
mf2_cite:
- 'a:1:{s:6:"author";a:0:{}}'
- 'a:1:{s:6:"author";a:0:{}}'
tumblr_post_id:
- "135657739439"
- "135657739439"
kind:
- article
2022-01-02 14:24:29 -05:00
tags: ["JS"]
2020-01-15 21:51:49 -05:00
---
Last week I published my first library over on Github called [Fractions.js](https://github.com/brandonrozek/Fractions.js). Fractions.js is a library to help avoid the [mathmatetical errors](http://floating-point-gui.de/) in floating point arithmetic. What do you mean by floating point artihmetic errors? Here is an example: <code class="language-javascript">.1 * .2</code> outputs <code class="language-javascript">0.020000000000000004</code> even though the correct answer is <code class="language-javascript">.02</code>
<!--more-->
## <a href="#purpose" name="purpose"></a>Purpose {#purpose}
My team and I are currently working on a new game for Math I/O. One of the levels is testing whether the player can add, subtract, multiply, and divide fractions correctly. I didnt want to implement a solution where we check if the input entered is within a range of the answer. So I asked the team, how do you add, subtract, multiply, and divide fractions in your head? As we were working through it together, I realized that this is a common problem over at Math I/O. So I decided to make a library dedicated to this.
## <a href="#how-it-works" name="how-it-works"></a>How it works {#how-it-works}
I broke up each fraction into two things, a numerator and a denominator. With these two numbers, I can figure out all of the most common operations.
### <a href="#addition" name="addition"></a>Addition {#addition}
For addition, if two fractions have the same denominator, then you just need to add the numerators.
1/3 + 1/3 = 2/3
2020-01-15 21:51:49 -05:00
If not, then you need to change it to have a common denominator. We can do this by multiply each fractions numerator and denominator by the other fractions denominator.
1/2 + 1/3 = (1 * 3)/ (2 * 3) + (1 * 2)/ (2 * 3) = 3/6 + 2/6 = 5/6
2020-01-15 21:51:49 -05:00
### <a href="#subtraction" name="subtraction"></a>Subtraction {#subtraction}
Works the same as addition, except the second fraction is subtracted (taken away) from the first.
### <a href="#multiplication" name="multiplication"></a>Multiplication {#multiplication}
To multiply two fractions, just multiply the numerators by each other, and the denominators by each other.
2/3 * 1/2 = 2/6
2020-01-15 21:51:49 -05:00
### <a href="#division" name="division"></a>Division {#division}
Treated similar to multiplication since dividing a number is the same thing as multiplying by its [reciprocal](https://www.mathsisfun.com/reciprocal.html).
1 / (1 / 2) = 1 * 2 = 2
2020-01-15 21:51:49 -05:00
### <a href="#simplification" name="simplification"></a>Simplification {#simplification}
Sometimes with the operations above, itll produce fractions in an unsimplified form. To avoid any confusion, I created a simplify function. It was challanging trying to figure out a way to code this. While I was browsing around for an implementation, I knocked into Eucliders algorithm for finding the greatest common factor. Straight from the [Wikipedia article](https://en.wikipedia.org/wiki/Euclidean_algorithm) (where a is greater than b):
2020-01-15 21:51:49 -05:00
function gcd(a, b)
while b ≠ 0
t := b;
b := a mod b;
a := t;
return a;
2020-01-15 21:51:49 -05:00
I can then simplify the fraction by dividing the numerator and denominator by the greatest common factor.
## <a href="#the-api" name="the-api"></a>The API {#the-api}
I decided to provide as much flexibility as I can in the API. You have several ways to create a new Fraction.
<pre><code class="language-javascript">
var oneHalf = new Fraction(1,2);
var oneHalf = new Fraction(.5);
var oneHalf = new Fraction("1/2");
var oneHalf = new Fraction("1", "2")
</code></pre>
All of these results will return a Fraction with a numerator of <code class="language-javascript">1</code> and a denominator of <code class="language-javascript">2</code>. You also have two different ways to do the most common operations.
<pre><code class="language-javascript">
var fiveThirds = Fraction.add("1/3", "4/3");
var fiveThirds = new Fraction("1/3").add("4/3");
</code></pre>
The second style came from how jQuery implements its library. That way you can chain operations.
<pre><code class="language-javascript">
new Fraction("1/2").add("2/3").divide("5/6").subtract("7/8").multiply("6/5").toString()
</code></pre>
Outputs <code class="language-javascript">'63/100'</code> This is accomplished in the code through [prototypes](http://javascriptissexy.com/javascript-prototype-in-plain-detailed-language/).
<pre><code class="language-javascript">
Fraction.add = function(frac1, frac2) {
Fraction.correctArgumentLength(2, arguments.length);
frac1 = Fraction.toFraction(frac1)
frac2 = Fraction.toFraction(frac2)
var newFrac = frac1;
newFrac.numerator = frac1.numerator * frac2.denominator + frac1.denominator * frac2.numerator;
newFrac.denominator = frac1.denominator * frac2.denominator;
return Fraction.simplify(newFrac);
}
Fraction.prototype.add = function(frac) {
Fraction.correctArgumentLength(1, arguments.length);
return Fraction.change(this, Fraction.add(this, frac));
}
</code></pre>
In the code, the add prototype calls the Fraction.add function within it to avoid code duplication.
## <a href="#conclusion" name="conclusion"></a>Conclusion {#conclusion}
After I coded this up, I looked online for different implementations and found [fraction.js](https://github.com/ekg/fraction.js) by [Erik Garrison](http://hypervolu.me/~erik/). Its important to look at different implementations and see which matches your needs better. This post isnt meant to go fully into detail of the library. To know what else the library can do, visit the [readme page](https://github.com/brandonrozek/Fractions.js/blob/master/README.md). If youre curious in how its implemented, check out the [code](https://github.com/brandonrozek/Fractions.js/blob/master/Fraction.js). [Email me](mailto:hello@brandonrozek.com) if you have any questions/criticisms 🙂