diff options
-rw-r--r-- | complexfunctions.html | 89 | ||||
-rw-r--r-- | css/styleNew.css | 25 | ||||
-rw-r--r-- | js/complex.js | 282 | ||||
-rw-r--r-- | js/complexfunctions.js | 86 |
4 files changed, 482 insertions, 0 deletions
diff --git a/complexfunctions.html b/complexfunctions.html new file mode 100644 index 0000000..f815b41 --- /dev/null +++ b/complexfunctions.html @@ -0,0 +1,89 @@ +<!-- +Graph complex functions (C->C) +--> +<!DOCTYPE html> +<html> + <head> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> + <link rel="stylesheet" href="css/styleNew.css"> + <link rel="shortcut icon" type="image/png" href="favicon.png"> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script> + <script src="http://www.numericjs.com/lib/numeric-1.2.6.min.js"></script> + <script src="js/complex.js"></script> + <script src="js/complexfunctions.js"></script> + <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script> + <script type="text/x-mathjax-config"> + MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$']]}}); + </script> + <title>Complex Functions</title> + </head> + <body> + + <div class="container-fluid"> + <div id="navbar"></div> + <script src="navbar.js"></script> + + <h2>Graph <a href="https://en.wikipedia.org/wiki/Reverse_Polish_notation">reverse polish notation</a> + <a href="https://en.wikipedia.org/wiki/Complex_number">complex</a> functions</h2> + + See explanation below. + + + <br> + + <div class="container-fluid row"> + <div class="input-group input-group-md col-lg-3 col-md-6 col-sm-8 col-xs-10"> + <span class="input-group-addon">Function</span> + <input id="function" class="form-control" type="text" value="x exp"> + </div> + </div> + <br> + <button id="animate" class="btn btn-default">Animate</button> + <div id="canvas"></div> + </div> + + <div class="container-fluid"> + + <div class="col-lg-6 col-md-8 col-sm-10 col-xs-12" id="explanation"> + <h3>Explanation</h3> + The x axis represents the real component, and the y axis represents the imaginary component. + Complex numbers are numbers with both real and imaginary parts: + $$z = a + b\sqrt{-1} = a + bi$$ + Reverse Polish Notation, or <i>postfix</i> notation is a way of writing functions. Normally, most people would write functions using + <i>infix</i> notation like this: + $$a + b + \sin c$$ + Postfix notation looks like this: + $$a\ b + c \sin +$$ + For a more simple example, $a + b$ would be $a\ b\ +$, and $\sin x$ would be $x \sin$. + <h3>List of all functions and constants</h3> + <table class='table table-bordered table-hover'> + <tr><th>Function or constant</th> <th>What it means</th></tr> + <tr><td>x</td> <td>The input to the function.</td></tr> + <tr><td>i</td> <td>$i = \sqrt{-1}$</td></tr> + <tr><td>n (e.g. 5, 4, 3.1, -32.123)</td> <td> A real number. </td></tr> + <tr><td>ni (e.g. 5i, 4i, 3.1i, -32.123i)</td> <td>$i$ ($\sqrt{-1}$) times a certain real number.</td></tr> + <tr><td>+</td> <td>Addition</td></tr> + <tr><td>-</td> <td>Subtraction</td></tr> + <tr><td>*</td> <td>Multiplication</td></tr> + <tr><td>/</td> <td>Division</td></tr> + <tr><td>^</td> <td>Exponentiation ($a^b$)</td></tr> + <tr><td>re</td> <td>Real component. If $z = a+bi$, $\textrm{Re}(z) = a$</td></tr> + <tr><td>im</td> <td>Imaginary component. If $z = a+bi$, $\textrm{Im}(z) = b$</td></tr> + <tr><td>pi</td> <td>$\pi = 3.14159265...$</td></tr> + <tr><td>e</td> <td>$e = 2.7182818...$</td></tr> + <tr><td>sqrt</td> <td>$\sqrt{x}$</td></tr> + <tr><td>exp</td> <td>$e^x$</td></tr> + <tr><td>sin</td> <td>Sine</td></tr> + <tr><td>cos</td> <td>Cosine</td></tr> + <tr><td>tan</td> <td>Tangent</td></tr> + <tr><td>sinh</td> <td>Hyperbolic sine</td></tr> + <tr><td>cosh</td> <td>Hyperbolic cosine</td></tr> + <tr><td>tanh</td> <td>Hyperbolic tangent</td></tr> + + </table> + </div> + + </div> + </body> +</html> diff --git a/css/styleNew.css b/css/styleNew.css new file mode 100644 index 0000000..467e428 --- /dev/null +++ b/css/styleNew.css @@ -0,0 +1,25 @@ +#navbar +{ + margin-top: 10px; +} + +footer +{ + font-size:12px; +} + +.project-title +{ + font-size: 22px; +} + +.checkbox +{ + width: 20px; + height: 20px; +} + +.with-margin +{ + margin-bottom: 5px; +} diff --git a/js/complex.js b/js/complex.js new file mode 100644 index 0000000..3f009bd --- /dev/null +++ b/js/complex.js @@ -0,0 +1,282 @@ +/* + complex.js + Client-side complex numbers in JavaScript +*/ +var complex = {}; + +complex.i = [0, 1]; +complex.logi = [0, 0.682188177]; +complex.PI = [Math.PI, 0]; +complex.E = [Math.E, 0]; + +complex.lnAccuracy = 20; + + +complex.re = function (a) +{ + return a[0]; +} + +complex.im = function (a) +{ + return a[1]; +} + +// Create a complex number from a real number +complex.reToC = function (a) +{ + return [a, 0]; +} + +complex.reC = function (a) +{ + return complex.reToC(complex.re(a)); +} + +complex.imC = function (a) +{ + return complex.reToC(complex.im(a)); +} + + + +complex.show = function (a) +{ + var im = complex.im(a); + var re = complex.re(a); + if (im == 1 && re == 0) + return "i"; + if (im == 0) + return re.toString(); + if (im == 1) + return re + " + i"; + if (re == 0) + return im + "i"; + return re + " + " + im + "i"; +} + +complex.add = function (a, b) +{ + return [complex.re(a) + complex.re(b), complex.im(a) + complex.im(b)]; +} + +complex.neg = function (a) +{ + return [-complex.re(a), -complex.im(a)]; +} + +complex.sub = function (a, b) +{ + return complex.add(a, complex.neg(b)); +} + +complex.mult = function (a, b) +{ + var a_Re, a_Im, b_Re, b_Im; + a_Re = complex.re(a); + a_Im = complex.im(a); + b_Re = complex.re(b); + b_Im = complex.im(b); + return [a_Re * b_Re - a_Im * b_Im, a_Re * b_Im + a_Im * b_Re]; +} + +complex.recip = function (a) +{ + var re = complex.re(a); + var im = complex.im(a); + var divBy = re*re + im*im; + return [re/divBy, -im/divBy] +} + +complex.div = function (a, b) +{ + return complex.mult(a, complex.recip(b)); +} + +complex.exp = function (a) +{ + var re = complex.re(a); + var im = complex.im(a); + var expRe = Math.exp(re); + return [expRe * Math.cos(im), expRe * Math.sin(im)]; +} + +complex.theta = function (a) +{ + return Math.atan(complex.im(a) / complex.re(a)); +} + +complex.abs = function (a) +{ + var re = complex.re(a); + var im = complex.im(a); + return Math.sqrt(re*re + im*im); +} + +complex.polar = function (a) +{ + return [complex.abs(a), complex.theta(a)]; +} + +complex.arg = function (a) +{ + var x = complex.re(a); + var y = complex.im(a); + var theta = complex.theta(a); + if (x > 0) + return theta; + if (x < 0 && y >= 0) + return theta + Math.PI; + if (x < 0 && y < 0) + return theta - Math.PI; + if (x == 0 && y > 0) + return Math.PI / 2; + if (x == 0 && y < 0) + return -Math.PI / 2; + return 1 / 0; +} + +complex.ln = function (a) +{ + return [Math.log(complex.abs(a)), complex.arg(a)]; +} + +complex.log = function (base, a) +{ + return complex.div(complex.ln(a), complex.ln(base)); +} + +complex.pow = function (a, b) +{ + return complex.exp(complex.mult(b, complex.ln(a))); +} + +complex.sin = function (a) +{ + var ia = complex.mult(complex.i, a); + return complex.mult([0, 0.5], complex.sub(complex.exp(complex.neg(ia)), complex.exp(ia))); +} + +complex.cos = function (a) +{ + return complex.sin(complex.sub(complex.reToC(Math.PI / 2), a)); +} + +complex.tan = function (a) +{ + return complex.div(complex.sin(a), complex.cos(a)); +} + +complex.sqrt = function (a) +{ + return complex.pow(a, complex.reToC(0.5)); +} + +complex.sinh = function (a) +{ + return complex.mult([0.5, 0], complex.sub(complex.exp(a), complex.exp(complex.neg(a)))); +} + +complex.cosh = function (a) +{ + return complex.mult([0.5, 0], complex.add(complex.exp(a), complex.exp(complex.neg(a)))) +} + +complex.tanh = function (a) +{ + return complex.div(complex.sinh(a), complex.cosh(a)); +} + +complex.rpn = function (s) +{ + // complex.rpn :: String -> (Complex -> Complex) + + + var tokens = s.split(" "); + + return function(x) + { + var token; + var stack = []; + for (var i = 0; i < tokens.length; i++) + { + token = tokens[i]; + switch (token) + { + case "+": + stack.push(complex.add(stack.pop(), stack.pop())); + break; + case "*": + stack.push(complex.mult(stack.pop(), stack.pop())); + break; + case "-": + var val2 = stack.pop(); + var val1 = stack.pop(); + stack.push(complex.sub(val1, val2)); + break; + case "/": + var val2 = stack.pop(); + var val1 = stack.pop(); + stack.push(complex.div(val1, val2)); + break; + case "^": + var val2 = stack.pop(); + var val1 = stack.pop(); + stack.push(complex.pow(val1, val2)); + break; + case "sqrt": + stack.push(complex.sqrt(stack.pop())); + break; + case "exp": + stack.push(complex.exp(stack.pop())); + break; + case "sin": + stack.push(complex.sin(stack.pop())); + break; + case "cos": + stack.push(complex.cos(stack.pop())); + break; + case "tan": + stack.push(complex.tan(stack.pop())); + break; + case "sinh": + stack.push(complex.sinh(stack.pop())); + break; + case "cosh": + stack.push(complex.cosh(stack.pop())); + break; + case "tanh": + stack.push(complex.tanh(stack.pop())); + break; + case "re": + stack.push(complex.reC(stack.pop())); + break; + case "im": + stack.push(complex.imC(stack.pop())); + break; + case "x": + stack.push(x); + break; + case "i": + stack.push(complex.i); + break; + case "e": + stack.push(complex.E); + break; + case "pi": + stack.push(complex.PI); + break; + default: + if (token[token.length-1] == "i") + { + stack.push([0, parseFloat(token.substring(0, token.length-1))]); + } + else + { + stack.push(complex.reToC(parseFloat(token))); + } + } + } + return stack.pop(); + }; +} diff --git a/js/complexfunctions.js b/js/complexfunctions.js new file mode 100644 index 0000000..fce70a6 --- /dev/null +++ b/js/complexfunctions.js @@ -0,0 +1,86 @@ +var domainPoints; +var rangePoints; +var animating = false; +var t = 0; +var SCALE = 5; + +function drawPoints(points) +{ + background(255); + for (var i = 0; i < points.length; i++) + { + point((points[i][0]/SCALE+0.5)*width, (points[i][1]/SCALE+0.5)*height); + } +} + + +function mapFunc(func) +{ + var f = complex.rpn(func); + rangePoints = []; + for (var i = 0; i < domainPoints.length; i++) + { + rangePoints.push(f(domainPoints[i])); + } +} + +function drawFunc(func) +{ + mapFunc(func); + animating = true; +} + +function draw() +{ + + if (animating) + { + var midpoints = []; + for (var i = 0; i < domainPoints.length; i++) + midpoints.push(complex.add(complex.mult(domainPoints[i], complex.reToC(1-t)), complex.mult(rangePoints[i], complex.reToC(t)))); + + drawPoints(midpoints); + + t += 0.01; + if (t >= 1) + { + animating = false; + drawPoints(rangePoints); + } + + + } +} + +function setup() +{ + var canvas = createCanvas(750, 750); + canvas.parent("canvas"); + stroke(0,0,100); + domainPoints = []; + for (var i = 10; i < width; i += 50) + { + for (var j = 0; j < height; j++) + { + domainPoints.push([(j/width-0.5)*SCALE, (i/height-0.5)*SCALE]); + domainPoints.push([(i/width-0.5)*SCALE, (j/height-0.5)*SCALE]); + } + } + drawPoints(domainPoints); +} + +$(function() +{ + $("#animate").click(function() + { + t = 0; + animating = false; + var func = $("#function").val(); + drawFunc(func); + }); + $("#function").keydown(function(e) + { + if (e.keyCode == 13) + $("#animate").click(); + }); +}); |