Basic Arithmetic on Fractions
I've been trying to find some code that does basic arithmetic on fractions in PHP but never found any. I spent my Sunday afternoon writing a class that performs addition, subtraction, multiplication and division on two fractions (as strings).
Here's the code if you're interested (and if you have some time, please give it a look over and let me know what ya think), and here's an award winning interface where you can test it out.
Let me know what ya think of it
JeevesBond posted this at 11:19 — 29th September 2008.
He has: 3,956 posts
Joined: Jun 2002
Nice one! I had brief look at your code, and played with the award winning interface. Looks good!
Abhishek Reddy posted this at 23:04 — 30th September 2008.
He has: 3,348 posts
Joined: Jul 2001
I'd try to find some way of not repeating the parse() and format() work in every operation. Specifically I would try:
You could then do stuff like:
$x = new Fraction(1, 2);
$y = new Fraction(71, 44);
$prod = Fractions::multiply($x, $y);
$z = new Fraction(111, 3);
echo Fractions::add($prod, $z, $x); // 3327/8
And it won't have to pack and unpack strings in every operation, but instead just access pairs of integers.
teammatt3 posted this at 23:36 — 30th September 2008.
He has: 2,102 posts
Joined: Sep 2003
I was hoping you would chime in Abhishek Great suggestions. I'll try them out and update the post.
pr0gr4mm3r posted this at 16:31 — 1st October 2008.
He has: 1,502 posts
Joined: Sep 2006
Pretty cool, well documented, and very efficient. It took me a minute to understand the lcm() and gcf() functions.
I'm wondering if it would be better to accept the different numbers instead of parsing a string. It would leave less room for user error if you accept the num, den, and whole number separately.
teammatt3 posted this at 19:24 — 1st October 2008.
He has: 2,102 posts
Joined: Sep 2003
I made some heavy revisions:
I wrote this class specifically for parsing input from the user from a textbox so I started with the string as input. But with the latest revision there are two ways to parse non-fraction objects, parseArray() (from your suggestion) and parseString() which I need for my app.
Thanks for comments and input guys . The new code has been posted.
Abhishek Reddy posted this at 06:39 — 2nd October 2008.
He has: 3,348 posts
Joined: Jul 2001
These are good improvements.
I'm not entirely in agreement with the parse functions:
Parse functions are conventionally named after the result type, with the assumption that a string is the input. Hence intval() in PHP, or parseInt()/parseInteger()/parse-integer in other languages. So parseString() could be renamed parseFraction().
As for parseArray(), it might be better not to explicitly represent different forms of fractions as arrays. Why not just overload the new Fraction() call? parseArray(array(1)) could be written new Fraction(1). parseArray(array(1, 2)) could be written new Fraction(1, 2). parseArray(array(1, 2, 3)) could be written new Fraction(1, 2, 3). Just provide three different constructors in Fraction to handle those cases.
Abhishek Reddy posted this at 10:12 — 2nd October 2008.
He has: 3,348 posts
Joined: Jul 2001
Incidentally, Python 2.6 was marked stable today, and I noticed it has a fractions module you could compare with. http://docs.python.org/dev/library/fractions.html
Their fraction constructor can accept a string representation and parse it as a fraction, instead of separately exposing the parse function.
There are some other differences that you probably can't adopt due to limitations in PHP. e.g. they overload native arithmetic operators where you need a Fractions class.
teammatt3 posted this at 02:59 — 3rd October 2008.
He has: 2,102 posts
Joined: Sep 2003
So should I have one constructor for Fraction that handles all the possible types: strings, integers, floats, kitchen sinks and arrays? So when ever a fraction is instantiated I will have to run some logic like:
if the parameters are integers
else if the parameter are strings
else if they are arrays
else blah?
The constructor would pretty much turn into the parser (is handler a better term since we're not just taking about strings anymore?) for all those data types (or pass control over to a specific parse function). I can see the benefit in that, because the programmer won't have to write his own logic to handle all those types. He can just send Fraction anything and it can handle it for him.
I downloaded the Python source and I'm at their fraction code right now...
Abhishek Reddy posted this at 13:22 — 3rd October 2008.
He has: 3,348 posts
Joined: Jul 2001
I've given it a bit more thought and I guess it's not as simple in PHP as I'd hoped.
The idea is twofold:
In PHP (5), you can't overload the constructor in a single class easily, so you'd have to specify a small tree of classes to model this.
But first, you can handle the case of the implicit denominator with an optional argument, like so:
function __construct ($numerator, $denominator = 1) {
This lets us say new Fraction(4) when we mean new Fraction(4, 1).
For strings, you could have one conditional upon the type of the first argument, to parse a single string input. That would look ugly. I'd suggest keeping to a parseFraction method in Fractions.
Here is as far as Python and other languages' rational support goes, usually. Mixed fractions are represented by adding a normal integer to a fraction, rather than passing the integer as an argument, always returning either a proper or improper fraction. This makes life considerably simpler.
To allow a 3-argument mixed fraction representation would require (at least in PHP), you could provide a convenience method in Fractions, perhaps called toImproperFraction(), taking 3 arguments but returning an improper fraction. Actually, since this is really about adding integers to fractions, a Fractions::addIntegers() method could be more useful.
If you wanted richer support for mixed fractions, you could define a MixedFractions class with its own constructor. It could be a subclass of Fraction, or merely have a $fraction field -- whichever you choose, just keep the semantics consistent. But this is probably more complicated than you'd want for an easy-to-use library.
Ultimately, you'll find it very hard to incorporate fractions into PHP as if it was native and first-class. PHP is not itself a programmable programming language, so the best you can do besides bolted-on libraries like this, is wait for the language implementers to add the feature (like the Python people did).
Want to join the discussion? Create an account or log in if you already have one. Joining is fast, free and painless! We’ll even whisk you back here when you’ve finished.