By Zevan | February 4, 2010
Today's quiz is not multiple choice. Instead, your task is to write a lisp style math parser. This may sound tricky, but it's surprisingly simple. (well... not simple exactly, it's just simple compared to what one might assume).
Lisp uses prefix notation... where the operator is placed before the operands:
10 * 10
becomes:
* 10 10
You could think of this as a function "*" with two arguments (10, 10). In Lisp this is enclosed with parens:
(* 10 10)
Let's see a few more examples:
100 / 2 + 10
becomes:
(+ (/ 100 2) 10)
...
2 * 4 * 6 * 7
becomes:
(* 2 4 6 7)
...
(2 + 2) * (10 - 2) * 2
becomes
(* (+ 2 2) (- 10 2) 2)
Remember, thinking "functions" really helps. The above can be though of as:
multiply( add(2, 2), subtract(10 , 2), 2)
You should create a function called parsePrefix() that takes a string and returns a number:
Here is some code to test if your parser works properly:
Actionscript:
-
trace(parsePrefix("(* 10 10)"));
-
-
trace(parsePrefix("(* 1 (+ 20 2 (* 2 7) 1) 2)"));
-
-
trace(parsePrefix("(/ 22 7)"));
-
-
trace(parsePrefix("(+ (/ 1 1) (/ 1 2) (/ 1 3) (/ 1 4))"));
-
-
/* Should trace out:
-
100
-
74
-
3.142857142857143
-
2.083333333333333
-
*/
I highly recommend giving this a try, it was one of those cases where I assumed it would be much trickier than it was.
I've posted my solution here.
Also posted in Quiz | Tagged actionscript, as3, flash, Lisp, Quiz |
By Zevan | November 29, 2009
Actionscript:
-
// print some floats as fractions
-
printFraction(0.5);
-
printFraction(0.75);
-
printFraction(0.48);
-
-
// try something a little more complex
-
var float:Number = 0.98765432;
-
trace("\na more complex example:");
-
printFraction(float);
-
var frac:Array = asFraction(float);
-
trace("double check it:");
-
trace(frac[0] + "/" + frac[1] +" = " + frac[0] / frac[1]);
-
-
/* outputs:
-
0.5 = 1/2
-
0.75 = 3/4
-
0.48 = 12/25
-
-
a more complex example:
-
0.98765432 = 12345679/12500000
-
double check it:
-
12345679/12500000 = 0.98765432
-
*/
-
-
-
function printFraction(n:Number):void{
-
var frac:Array = asFraction(n);
-
trace(n + " = " + frac[0] + "/" + frac[1]);
-
}
-
-
// takes any value less than one and returns an array
-
// with the numerator at index 0 and the denominator at index 1
-
function asFraction(num:Number):Array{
-
var decimalPlaces:int = num.toString().split(".")[1].length;
-
var denom:Number = Math.pow(10, decimalPlaces);
-
return reduceFraction(num * denom, denom);
-
}
-
-
// divide the numerator and denominator by the GCF
-
function reduceFraction(numerator:int, denominator:Number):Array{
-
// divide by the greatest common factor
-
var divisor:int = gcf(numerator, denominator);
-
if (divisor){
-
numerator /= divisor;
-
denominator /= divisor;
-
}
-
return [numerator, denominator];
-
}
-
-
// get the greatest common factor of two integers
-
function gcf(a:int, b:int):int{
-
var remainder:int;
-
var factor:Number = 0;
-
var maxIter:int = 100;
-
var i:int = 0;
-
while (1){
-
if (b> a){
-
var swap:int = a;
-
a = b;
-
b = swap;
-
}
-
remainder = a % b;
-
a = b;
-
b = remainder
-
if (remainder == 0){
-
factor = a;
-
break;
-
}else if (remainder==1){
-
break;
-
}else if (i> maxIter){
-
trace("failed to calculate gcf");
-
break;
-
}
-
i++;
-
}
-
return factor;
-
}
This snippet contains a few functions for calculating fractions based on float values. Writing this brought back some memories from grade school math.
Also posted in misc | Tagged actionscript, as3, flash |
By Zevan | November 28, 2009
Actionscript:
-
trace(gcf(75,145));
-
-
// outputs 5
-
-
function gcf(a:int, b:int):int{
-
var remainder:int;
-
var factor:Number = 0;
-
while (1){
-
if (b> a){
-
var swap:int = a;
-
a = b;
-
b = swap;
-
}
-
remainder = a % b;
-
a = b;
-
b = remainder
-
if (remainder == 0){
-
factor = a;
-
break;
-
}else if (remainder==1){
-
-
break;
-
}
-
}
-
return factor;
-
}
I was messing around with Egyptian Fractions and found myself in need of some interesting functions. The first function I realized I would be needing was for a greatest common factor (GCF or GCD).
The above snippet is a quick implementation of Euclid's algorithm. It will return 0 if no GCF is found...
I wrote a few helper functions while working with Egyptian fractions... will post them over the next few days.
Posted in Math | Tagged actionscript, as3, flash |
By Zevan | November 27, 2009
Actionscript:
-
egyptianMultiply(12, 99);
-
-
// trace(12 * 99) // test to make sure it works
-
-
/* outputs:
-
/64 768
-
/32 384
-
16 192
-
8 96
-
4 48
-
/2 24
-
/1 12
-
---
-
1188
-
*/
-
-
-
function egyptianMultiply(valueA:Number, valueB:Number):void {
-
-
var left:Array = [];
-
var right:Array = []
-
-
// swap if valueB is smaller than value A
-
if (valueB <valueA){
-
var swap:int = valueB;
-
valueB = valueA;
-
valueA = swap;
-
}
-
-
// create left and right columns
-
var currentLeft:int = 1;
-
var currentRight:int = valueA;
-
-
while (currentLeft <valueB){
-
left.push(currentLeft);
-
right.push(currentRight);
-
currentRight += currentRight;
-
currentLeft += currentLeft;
-
}
-
-
-
// add up the right column based on the left
-
currentLeft = 0;
-
var rightSum:int;
-
var leftSum:int;
-
var i:int = left.length - 1;
-
-
while (currentLeft != valueB){
-
-
leftSum = currentLeft + left[i];
-
// if the next number causes the sum
-
// to go above valueB, skip it
-
if (leftSum <= valueB){
-
currentLeft = leftSum;
-
rightSum += right[i];
-
trace("/" + left[i] + " " + right[i]);
-
} else {
-
trace(" " + left[i] + " " + right[i]);
-
}
-
i--;
-
}
-
trace("---");
-
trace(rightSum);
-
}
Someone mentioned egyptian multiplication to me yesterday... So read a little about it here and whipped up this example. For some reason I decided to do it in processing ... once it worked I ported it to ActionScript.
The above link describing the technique I used is from http://www.jimloy.com/... I haven't spent much time digging around the site, but it appears to have some pretty nice stuff on it...
If you're curious, here is the original processing version:
JAVA:
-
-
-
-
int valueA = 10;
-
int valueB = 8;
-
-
if (valueB <valueA){
-
int swap = valueB;
-
valueB = valueA;
-
valueA = swap;
-
}
-
-
int currentLeft = 1;
-
int currentRight = valueA;
-
while (currentLeft <valueB){
-
left.add(currentLeft);
-
right.add(currentRight);
-
currentRight += currentRight;
-
currentLeft += currentLeft;
-
}
-
-
currentLeft = 0;
-
-
int result = 0;
-
int i = left.size() - 1;
-
while (currentLeft != valueB){
-
-
int temp
= currentLeft
+ (Integer) left.
get(i
);
-
if (temp <= valueB){
-
-
currentLeft = temp;
-
-
println("/" + left.get(i) + " " + right.get(i));
-
} else {
-
println(" " + left.get(i) + " " + right.get(i));
-
}
-
-
i--;
-
}
-
println("---");
-
println(result);
After writing, this I took a look at the wikipedia entry... I also found myself on this short page about a scribe called Ahmes. (I recommend reading this if you are interested in PI)