JavaScript fractal generation algorithms - why is one so much faster? - javascript

I'm trying to write a JavaScript fractal generation algorithm from first principles. I'm aware that there are many examples out there but I wanted to incorporate additional functionality to support both Mandelbrot and 'spinning' Julia with variants such as 'Burning Ship' and 'Tricorn'. With this in mind I implemented a lightweight Complex maths library (again, I'm aware there are standard Complex js libraries out there but I wanted to build one from scratch as a learning exercise).
I tested two alternate functions, one fractal using standard maths functions and the other fractalComplex using my Complex library methods. They both work fine, but I was surprised to find that the standard version is almost twice as fast as the Complex version. I was expecting some additional overhead but not that much!
Can anyone explain why? The Complex library is using the same maths constructs 'under the covers'. Is the additional overhead purely down to object creation?
The code is reproduced below (the input parms z and c are objects of the form {re, im}).
function fractal(z, c, maxiter) {
var i, za, re, im, re2, im2;
c = (settype === JULIA ? c : z);
// Iterate until abs(z) exceeds escape radius
for (i = 0; i < maxiter; i += 1) {
if (setvar === BURNING_SHIP) {
re = Math.abs(z.re);
im = -Math.abs(z.im);
}
else if (setvar === TRICORN) {
re = z.re
im = -z.im; // conjugate z
}
else { // Mandelbrot
re = z.re;
im = z.im;
}
re2 = re * re;
im2 = im * im;
z = { // z = z² + c
re: re2 - im2 + c.re,
im: 2 * im * re + c.im
};
za = re2 + im2 // abs(z)²
if (za > 4) { // abs(z)² > radius²
break;
}
}
za = Math.sqrt(za); // abs(z)
return { i, za };
}
function fractalComplex(z, c, maxiter, n, radius) {
var i, za;
c = (settype === JULIA ? c : z);
// Iterate until abs(z) exceeds escape radius
for (i = 0; i < maxiter; i += 1) {
if (setvar === BURNING_SHIP) {
z = new Complex(Math.abs(z.re), -Math.abs(z.im))
}
if (setvar === TRICORN) {
z = z.conjugate()
}
z = z.quad(n, c); // z = zⁿ + c
za = z.abs();
if (za > radius) {
break;
}
}
return { i, za };
}
My "Complex lite" library is as follows:
// ------------------------------------------------------------------------
// A basic complex number library which implements the methods used for
// Mandelbrot and Julia Set generation.
// ------------------------------------------------------------------------
'use strict';
// Instantiate complex number object.
function Complex(re, im) {
this.re = re; // real
this.im = im; // imaginary
}
Complex.prototype = {
're': 0,
'im': 0,
// Set value.
'set': function (re, im) {
this.re = re;
this.im = im;
},
// Get magnitude.
'abs': function () {
return Math.sqrt(this.re * this.re + this.im * this.im);
},
// Get polar representation (r, θ); angle in radians.
'polar': function () {
return { r: this.abs(), θ: Math.atan2(this.im, this.re) };
},
// Get square.
'sqr': function () {
var re2 = this.re * this.re - this.im * this.im;
var im2 = 2 * this.im * this.re;
return new Complex(re2, im2);
},
// Get complex number to the real power n.
'pow': function (n) {
if (n === 0) { return new Complex(1, 0); }
if (n === 1) { return this; }
if (n === 2) { return this.sqr(); }
var pol = this.polar();
var rn = Math.pow(pol.r, n);
var θn = n * pol.θ;
return cart(rn, θn);
},
// Get conjugate.
'conjugate': function () {
return new Complex(this.re, -this.im);
},
// Get quadratic zⁿ + c.
'quad': function (n, c) {
var zn = this.pow(n);
return new Complex(zn.re + c.re, zn.im + c.im);
},
// Rotate by angle in radians.
'rotate': function (angle) {
var pol = this.polar();
angle += pol.θ;
return new Complex(pol.r * Math.cos(angle), pol.r * Math.sin(angle));
},
// String in exponent format to specified significant figures.
'toString': function (sig = 9) {
return this.re.toExponential(sig) + " + " + this.im.toExponential(sig) + "i";
},
}
// Convert polar (r, θ) to cartesian representation (re, im).
function cart(r, θ) {
var re = r * Math.cos(θ);
var im = r * Math.sin(θ);
return new Complex(re, im);
}
Additional edit 22/12/2021 11:52:
For what it's worth, this is what I eventually settled on...
function fractal(p, c, n, maxiter, radius) {
var i, za, zre, zim, tre, cre, cim, r, θ;
var lastre = 0;
var lastim = 0;
var per = 0;
if (setmode === JULIA) {
cre = c.re;
cim = c.im;
zre = p.re;
zim = p.im;
}
else { // Mandelbrot mode
cre = p.re;
cim = p.im;
zre = 0;
zim = 0;
}
// Iterate until abs(z) exceeds escape radius
for (i = 0; i < maxiter; i += 1) {
if (setvar === BURNING_SHIP) {
zre = Math.abs(zre);
zim = -Math.abs(zim);
}
else if (setvar === TRICORN) {
zim = -zim; // conjugate z
}
// z = z² + c
if (n == 2) {
tre = zre * zre - zim * zim + cre;
zim = 2 * zre * zim + cim;
zre = tre;
}
else { // z = zⁿ + c, where n is integer > 2
r = powi(Math.sqrt(zre * zre + zim * zim), n); // radiusⁿ
//r = Math.pow(Math.sqrt(zre * zre + zim * zim), n); // radiusⁿ
θ = n * Math.atan2(zim, zre); // angleⁿ
zre = r * Math.cos(θ) + cre;
zim = r * Math.sin(θ) + cim;
}
// Optimisation - periodicity check speeds
// up processing of points within set
if (PERIODCHECK) {
if (zre === lastre && zim === lastim) {
i = maxiter;
break;
}
per += 1;
if (per > 20) {
per = 0;
lastre = zre;
lastim = zim;
}
}
// ... end of optimisation
za = zre * zre + zim * zim // abs(z)²
if (za > radius) { // abs(z)² > radius²
break;
}
}
return { i, za };
}
// Optimised pow() function for integer exponents
// using 'halving and squaring'.
function powi(base, n) {
var res = 1;
while (n) {
if (n & 1) { // if n is odd
res *= base;
}
n >>= 1; // n * 2
base *= base;
}
return res;
}

The following class might satisfy both performance concerns and proper encapsulation of the Complex object...
Notables:
Where applicable, always return the this Complex object (ie, the instantiated object), which facilitates chaining. Eg,
x = new Complex( 10, 5 ).sqrThis().powThis( 1 );
For every Complex method that returns a Complex object, configure two (2) methods:
A method, dubbed <method>This that operates directly on the this object and contains the function logic.
A method, dubbed <method> that clones a new Complex object from the this object, and then calls <method>This to execute the function logic on the clone.
This provides the developer the choice of methods that either updates the existing object or returns a new object.
Internal calls to other Complex methods generally should use the <method>This version, as the initial call establishes whether to use the existing this object in-place, or to clone it. From there, all internal calls to the other Complex methods will either continue to operate on the this object or the clone.
// ------------------------------------------------------------------------
// A basic complex number library which implements the methods used for
// Mandelbrot and Julia Set generation.
// ------------------------------------------------------------------------
'use strict';
class Complex {
constructor( reOrComplex, im ) {
this.set( reOrComplex, im );
}
set( reOrComplex, im ) {
if ( reOrComplex instanceof Complex ) {
this.re = reOrComplex.re;
this.im = reOrComplex.im;
} else {
this.re = reOrComplex;
this.im = im;
}
return this;
}
abs() {
return Math.sqrt(this.re * this.re + this.im * this.im);
}
toPolar() {
return { r: this.abs(), θ: Math.atan2(this.im, this.re) };
}
sqrThis() {
return this.set( this.re * this.re - this.im * this.im, 2 * this.im * this.re );
}
sqr() {
return new Complex( this ).sqrThis();
}
powThis( n ) {
if ( n === 0 ) { return this.set( 1, 0 ) };
if ( n === 1 ) { return this; }
if ( n === 2 ) { return this.sqrThis(); }
let polar = this.toPolar();
return this.toCartesianThis( Math.pow(polar.r, n), n * polar.θ );
}
pow( n ) {
return new Complex( this ).powThis( n );
}
conjugateThis() {
return this.set( this.re, -this.im);
}
conjugate() {
return new Complex( this ).conjugateThis();
}
quadraticThis( n, c ) {
let zn = this.powThis( n );
return this.set( zn.re + c.re, zn.im + c.im );
}
quadratic( n, c ) {
return new Complex( this ).quadraticThis( n, c );
}
rotateThis( deltaAngle ) {
let polar = this.toPolar();
let angle = polar.θ + deltaAngle;
return this.set( polar.r * Math.cos(angle), polar.r * Math.sin(angle) );
}
rotate( deltaAngle ) {
return new Complex( this ).rotateThis( deltaAngle );
}
toString( sig = 9 ) {
return this.re.toExponential( sig ) + " + " + this.im.toExponential( sig ) + "i";
}
toCartesianThis( r, θ ) {
return this.set( r * Math.cos( θ ), r * Math.sin( θ ) );
}
}
// Convert polar (r, θ) to cartesian representation (re, im).
Complex.toCartesian = function ( r, θ ) {
return new Complex().toCartesianThis( r, θ );
}
let x = new Complex( 10, 5 ).sqrThis();
console.log( 'x = new Complex( 10, 5 ).sqrThis()' );
console.log( 'x is ', x );
let y = x.pow( 3 );
console.log ( 'y = x.pow( 3 )' );
console.log ( 'y is ', y );
x.sqr();
console.log ( 'x.sqr()' );
console.log ( 'x is still', x );
x.sqrThis();
console.log ( 'x.sqrThis()' );
console.log ( 'x is now', x );
In short, structuring a class this way provides two versions of the same method:
One method which embodies the function logic and directly mutates the instantiated this object.
And the other method which simply clones the instantiated this object, and then calls the associated method containing the function logic.

Related

How to use big.js?

From the examples of big.js they show this example
0.3 - 0.1 // 0.19999999999999998
x = new Big(0.3)
x.minus(0.1) // "0.2"
x // "0.3"
x.div(y).plus(z).times(9).minus('1.234567801234567e+8').plus(976.54321).div('2598.11772')
Which is a very simple example. In my case I would like to calculate
res = a + (b / c) + (d + 1) / (e * f * g);
I cannot see how that can be calculated without introducing 7 temporary variables, which doesn't seam correct.
Question
Does anyone know how to calculate the above with big.js?
You can do this "inside-out", i.e. first convert the parts in the inner parentheses.
For example:
const temp1 = b.div(c),
temp2 = d.plus(1),
temp3 = e.times(f).times(g),
temp4 = temp2.div(temp3),
result = a.plus(temp1).plus(temp4);
But you don't actually need those temporary variables. Just take that last expression and inject the definition of the temporary variables, so your expression expands to this:
const res = a.plus(b.div(c)).plus(d.plus(1).div(e.times(f).times(g)));
// a + (b / c ) + (d + 1) / (e * f * g )
Demo:
const params = [1, 100, 5, 99, 2, 5, 2];
{ // First with native types:
const [a,b,c,d,e,f,g] = params;
const res = a + (b / c) + (d + 1) / (e * f * g);
console.log(res);
}
{ // Then with big.js
const [a,b,c,d,e,f,g] = params.map(Big);
const res = a.plus(b.div(c)).plus(d.plus(1).div(e.times(f).times(g)));
console.log(res.toNumber());
}
<script src='https://cdn.jsdelivr.net/npm/big.js#6.2.1/big.min.js'></script>

Math operations from string using Javascript

I am trying to find a simple way to perform a set of javascript math operations without using eval() function. Example: 1+2x3x400+32/2+3 and it must follow the PEMDAS math principle. This is what I have, but it doesn't work exactly it should.
function mdas(equation) {
let operations = ["*", "/", "+", "-"];
for (let outerCount = 0; outerCount < operations.length; outerCount++) {
for (let innerCount = 0; innerCount < equation.length; ) {
if (equation[innerCount] == operations[outerCount]) {
let operationResult = runOperation(equation[innerCount - 1], operations[outerCount], equation[innerCount + 1]);
var leftSideOfEquation = equation.substr(0, equation.indexOf(innerCount - 1));
var rightSideOfEquation = equation.substr(equation.indexOf(innerCount), equation.length);
var rightSideOfEquation = rightSideOfEquation.replace(rightSideOfEquation[0],String(operationResult));
equation = leftSideOfEquation + rightSideOfEquation;
innerCount = 0;
}
else {
innerCount++;
}
}
}
return "Here is it: " + equation; //result of the equation
}
If you don't want to use a complete library like mathjs - and you don't want to tackle creating your own script which would involve: lexical analysis, tokenization, syntax analysis, recursive tree parsing, compiling and output...
the simplest banal suggestion: Function
const calc = s => Function(`return(${s})`)();
console.log( calc("1+2*3*400+32/2+3") ); // 2420
console.log( calc("-3*-2") ); // 6
console.log( calc("-3 * + 1") ); // -3
console.log( calc("-3 + -1") ); // -4
console.log( calc("2 * (3 + 1)") ); // 8
My take at a custom MDAS
Here I created a Regex to retrieve operands and operators, accounting for negative values: /(-?[\d.]+)([*\/+-])?/g.
Firstly we need to remove any whitespace from our string using str.replace(/ /g , "")
Using JavaScript's String.prototype.matchAll() we can get a 2D array with all the matches as [[fullMatch, operand, operator], [.. ] we can than further flatten it using Array.prototype.flat()
Having that flattened array, we can now filter it using Array.prototype.filter() to remove the fullMatch -es returned by the regular expression and remove the last undefined value.
Define a calc Object with the needed operation functions
Iterate over the MDAS groups */ and than +- as regular expressions /\/*/ and /+-/
Consume finally the array of matches until only one array key is left
let str = "-1+2 * 3*+400+-32 /2+3.1"; // 2386.1
str = str.replace(/ +/g, ""); // Remove all spaces!
// Get operands and operators as array.
// Remove full matches and undefined values.
const m = [...str.matchAll(/(-?[\d.]+)([*\/+-])?/g)].flat().filter((x, i) => x && i % 3);
const calc = {
"*": (a, b) => a * b,
"/": (a, b) => a / b,
"+": (a, b) => a + b,
"-": (a, b) => a - b,
};
// Iterate by MDAS groups order (first */ and than +-)
[/[*\/]/, /[+-]/].forEach(expr => {
for (let i = 0; i < m.length; i += 2) {
let [a, x, b] = [m[i], m[i + 1], m[i + 2]];
x = expr.exec(x);
if (!x) continue;
m[i] = calc[x.input](parseFloat(a), parseFloat(b)); // calculate and insert
m.splice(i + 1, 2); // remove operator and operand
i -= 2; // rewind loop
}
});
// Get the last standing result
console.log(m[0]); // 2386.1
It's a little hacky, but you can try something like this:
var eqs = [
'1+2*3*4+1+1+3',
'1+2*3*400+32/2+3',
'-5+2',
'3*-2',
];
for(var eq in eqs) { console.log(mdas(eqs[eq])); }
function mdas(equation) {
console.log(equation);
var failsafe = 100;
var num = '(((?<=[*+-])-|^-)?[0-9.]+)';
var reg = new RegExp(num + '([*/])' + num);
while(m = reg.exec(equation)) {
var n = (m[3] == "*") ? m[1]*m[4] : m[1]/m[4];
equation = equation.replace(m[0], n);
if(failsafe--<0) { return 'failsafe'; }
}
var reg = new RegExp(num + '([+-])' + num);
while(m = reg.exec(equation)) {
var n = (m[3] == "+") ? 1*m[1] + 1*m[4] : m[1]-m[4];
equation = equation.replace(m[0], n);
if(failsafe--<0) { return 'failsafe'; }
}
return equation;
}

High order function with javascript trouble

I want to be able to run the func n times with this createIterator function.
var createIterator = function (func, n) {
getDouble = function (x) {
return x + x;
};
return getDouble * n;
};
I want to be able to do this with the code:
var getQuad = createIterator(getDouble, 2);
getQuad(2) //8
Here are the tests is needs to pass:
Test.describe("Iterator for 'getDouble' function", function() {
var getDouble = function (n) {
return n + n;
};
Test.it("Running the iterator for once", function() {
var doubleIterator = createIterator(getDouble, 1);
Test.assertEquals(doubleIterator(3), 6, "Returns double of 3 as 6");
Test.assertEquals(doubleIterator(5), 10, "Returns double of 5 as 10");
});
Test.it("Running the iterator twice", function() {
var getQuadruple = createIterator(getDouble, 2);
Test.assertEquals(getQuadruple(2), 8, "Returns quadruple of 2 as 8");
Test.assertEquals(getQuadruple(5), 20, "Returns quadruple of 5 as 20");
});
});
I have been at this for awhile and have not been able to figure this out. Any help would be awesome. Thanks!
You can write a simple repeat procedure that when applied to n, f, and x, will repeat the application of function f to argument x, n times.
// ES6
const repeat = n => f => x =>
n === 1 ? f(x) : repeat(n-1)(f)(f(x));
const getDouble = x => x * 2;
const double = repeat(1)(getDouble);
const quad = repeat(2)(getDouble);
See it work
console.log(double(3)); // 6
console.log(double(5)); // 10
console.log(quad(2)); // 8
console.log(quad(5)); // 20
Let step through the evaluation of one of the examples:
const double = repeat(1)(getDouble);
Because repeat has been applied to n and f here, it returns
x => 1 === 1 ? getDouble(x) : repeat(0)(getDouble)(getDouble(x))
Now, when we call
double(3);
Substitute 3 for x
1 === 1 ? getDouble(3) : repeat(0)(getDouble)(getDouble(3));
Because 1 === 1, the first part of the ternary expression is returned
getDouble(3); // 6
Recap:
double(3) === getDouble(3) === 6
Now let's see the same process for quad
const quad = repeat(2)(getDouble);
Because repeat has been applied to n and f here, it returns
x => 2 === 1 ? getDouble(x) : repeat(1)(getDouble)(getDouble(x))
Now, when we call
quad(2);
Substitue 2 for x
2 === 1 ? getDouble(2) : repeat(1)(getDouble)(getDouble(2));
Because 2 === 1 is false, the second part of the ternary expression is returned
repeat(1)(getDouble)(getDouble(2))
repeat(1)(getDouble)(4)
So we have to call repeat again, with n=1, f=getDouble, x=4, so
1 === 1 ? getDouble(4) : repeat(0)(getDouble)(getDouble(4))
Because 1 === 1, the first part of the ternary expression is returned
getDouble(4); // 8
Recap:
quad(2) === getDouble(4) === 8
If you need the ES5, here you go
// ES5
var repeat = function repeat(n) {
return function (f) {
return function (x) {
return n === 1 ? f(x) : repeat(n - 1)(f)(f(x));
};
};
};
var getDouble = function getDouble(x) {
return x * 2;
};
var double = repeat(1)(getDouble);
var quad = repeat(2)(getDouble);
console.log(double(3)); // 6
console.log(double(5)); // 10
console.log(quad(2)); // 8
console.log(quad(5)); // 20
Lastly,
If you want your original API, which I believe to be inferior, we can still implement that
// ES6
const createIterator = (f, n) => x =>
n === 1 ? f(x) : createIterator(f, n-1)(f(x));
const getDouble = x => x * 2;
const double = createIterator(getDouble, 1);
const quad = createIterator(getDouble, 2);
And here's the ES5
// ES5
var createIterator = function createIterator(f, n) {
return function (x) {
return n === 1 ? f(x) : createIterator(f, n - 1)(f(x));
};
};
var getDouble = function getDouble(x) {
return x * 2;
};
var double = createIterator(getDouble, 1);
var quad = createIterator(getDouble, 2);
Both implementations work identically
So why is repeat(n)(f)(x) better ?
Well, because the function is fully curried, you can partially apply it in meaningful ways.
const getDouble = x => x * 2;
const once = repeat(1);
const twice = repeat(2);
const thrice = repeat(3);
const quad = twice(getDouble);
quad(5); // 20
const annoyingAlert = thrice(x => {alert(x); return x;});
annoyingAlert('wake up !'); // displays 'wake up !' three times
Your function isn't as flexible because it takes the function, f, and the number of times, n, as a tuple. Getting around this would require manually currying your function or using a Function.prototype.bind hack.
Try rearranging variables. Note, getDouble would be undefined at var getQuad = createIterator(getDouble, 2); as getDouble is defined within createIterator
var createIterator = function (func, n) {
getDouble = function (x) {
return (x + x) * n;
};
return func || getDouble;
};
var getQuad = createIterator(null, 2);
console.log(getQuad(2)) //8
alternatively
var createIterator = function(func, n) {
getDouble = function(x) {
return x + x;
};
return func.bind(null, n * n) || (getDouble(n)) * n;
};
var getQuad = createIterator(function(x) {
return x + x;
}, 2);
console.log(getQuad(2))
I just want to run getDouble n times.
You could use a loop inside of createIterator , return accumulated value as variable within function returned from createIterator that can be multiplied by parameter passed to getQuad
var createIterator = function(func, n) {
getDouble = function(x) {
return x + x;
};
var curr = n, res = 0;
while (--curr) {
res += func && func(n) || getDouble(n);
}
return function(y) {
return res * y
}
};
var getQuad = createIterator(null, 2);
console.log(getQuad(5)) // 20
You can do it like this,
Create an empty array of n
Fill the array by the function(arguments)
Join the array by operator
Create a function constructor using the joined array and arguments
Use the new function inside another function to pass the arguments from outside, and then return this new function.
Code snippet of what I am saying is here (if your browser supports Array.prototype.fill)
var createIterator = function (func, n, operator) {
operator = operator || "+";
var inner = Function(["f", "a"], "return " + Array(n ).fill("f(a)").join(operator) + ";");
return function (arg) {
return inner(func, arg);
};
};
var c = createIterator(function (n) {return n + n;}, 2);
document.write(c(3) + "<br/>");
document.write(c(6) + "<br/>");
var d = createIterator(function (n) {return n + n;}, 3, "+");
document.write(d(3) + "<br/>");
document.write(d(6) + "<br/>");
otherwise use this snippet
var createIterator = function (func, n, operator) {
operator = operator || "+";
var array = [];
for (var i = 0; i < n; i += 1) {array[i] = "f(a)";}
var inner = Function(["f", "a"], "return " + array.join(operator) + ";");
return function (arg) {
return inner(func, arg);
};
};
var c = createIterator(function (n) {return n + n;}, 2);
document.write(c(3) + "<br/>");
document.write(c(6) + "<br/>");
var d = createIterator(function (n) {return n + n;}, 3, "+");
document.write(d(3) + "<br/>");
document.write(d(6) + "<br/>");

Check if given three line segments represented by coordinates of 4 element array can form a triangle

I need to check if given three line segments form a triangle. A line segment can be expressed as an array of 4 integers giving the end-points coordinates in the form [ x1, y1, x2, y2 ].
So I need to write a function that is given as input three line segments K, L and M and will return 1 if they form a triangle, 0 otherwise.
If the input parameters are outside the range of the algorithm supports I need to return -1.
Examples :
function trigTest(K, L, M)
var K=[2,3,6,9], L=[8,1,6,9], M=[8,1,2,3], X=[1,7,6,9]
trigTest(K, L, M) // -> 1
trigTest(L, K, M) // -> 1
trigTest(M, K, L) // -> 1
trigTest(L, L, M) // -> 0
trigTest(X, L, M) // -> 0
I actually have a solution but it's pretty cumbersome and I don't think it is the right way. First I calculate the distance of every line segment and then I use triangle inequalities to check if they can actually form a triangles base on their lengths.
function distance(line){
var x1 = line[0],
y1 = line[1],
x2 = line[2],
y2 = line[3];
return Math.sqrt(Math.pow((x2-x1),2) + Math.pow(y2-y1),2)
}
function trigTest(K,L,M){
var distanceK = distance(K), distanceL = distance(L), distanceM = distance(M);
if((distanceK + distanceL) > distanceM && (distanceK + distanceM) > distanceL && distanceL + distanceM > distanceK){
// algorithm here
}else{
return 0;
}
}
Update
Thanks to #antoniskamamis and #trincot I have made a similar solution if someone wants to stick with arrays instead of working with strings. Big shout out to them.
function trigTest(K, L, M) {
var points = [];
var k = dots(K), l = dots(L), m = dots(M);
if(ifDotsOnSameLineAreEqual(k) || ifDotsOnSameLineAreEqual(l) || ifDotsOnSameLineAreEqual(m)){
return false;
}else{
return points.concat(k,l,m).every(function(point, index, array){
return array.filter(function(i){ return ifTwoDotsAreEqual(i,point)}).length == 2;
})
}
}
function dots(line) {
var x1 = line[0],
y1 = line[1],
x2 = line[2],
y2 = line[3];
return [[x1,y1],[x2, y2]];
}
function ifTwoDotsAreEqual(x,y){
return x[0] == y[0] && x[1] == y[1];
}
function ifDotsOnSameLineAreEqual(line){
return ifTwoDotsAreEqual(line[0],line[1]);
}
you could use this approach
function trigTest(a,b,c){
var parts = [];
Array.prototype.slice.call(arguments).forEach(function(item){
parts.push(item.slice(0,2).join("|"));
parts.push(item.slice(2).join("|"));
})
return parts.every(function(item, index, array){
return array.filter( function(x){ return x == item}).length == 2;
})
}
What it does is:
runs through the list of arguments
Array.prototype.slice.call(arguments).forEach
seperates the arrays into points first two, last two as strings parts.push(item.slice(0,2).join(""));parts.push(item.slice(2).join(""));
given the array of points it checks that each point is present two times parts.every(function(item, index, array){ return array.filter( function(x){ return x == item}).length == 2; })
Using a 'one liner'
function trigTest(a,b,c){
var slice = Array.prototype.slice;
return slice.call(arguments).reduce(function(previous, current){
previous.push(current.slice(0,2).join("|"));
previous.push(current.slice(2).join("|"));
return previous;
}, [])
.every(function(item, index, array){
return array.filter( function(x){ return x == item; }).length == 2;
})
}
Checking for zero length lines
if we know that the inputs are not validated to be lines before we have to add a check if any of the given lines has start and end points the same (is a 0 length line or a point)
in this case our code will have to be like this
function trigTest(a,b,c){
var slice = Array.prototype.slice;
if(slice.call(arguments).some(isPoint)){
return false;
};
return slice.call(arguments).reduce(function(previous, current){
previous.push(current.slice(0,2).join("|"));
previous.push(current.slice(2).join("|"));
return previous;
}, [])
.every(function(item, index, array){
return array.filter( function(x){ return x == item; }).length == 2;
})
}
function isPoint(value){
return value[0] == value[2] && value[1] == value[3];
}
Based on your examples, the key criteria is that you have exactly two copies of three x,y coordinates, so rather than deal with this from a geometric or trigonometric standpoint, you may have an easier time dealing with this based on basic set-theory: to have a triangle formed from three points A, B, C, your line segments must follow the pattern [Ax, Ay, Bx, By], [Bx, By, Cx, Cy], [Cx, Cy, Ax, Ay].
These segments are not required to be in that order, such as [Bx, By, Ax, Ay] is also valid for the first term.
To check for a valid triangle, count repeated coordinates first to verify two repeats of three unique coordinates (this will also eliminate repeated line segments), then verify that each line segment is non-zero in length (not [Ax, Ay, Ax, Ay]). Those two checks will handle the first two requirements.
I don't know the boundary limits, so I cannot advise on how to test whether it is outside the bounds of the algorithm, but I suspect that will require checking the actual coordinate range, which is integer arithmetic.
This approach should be usable in any javascript engine, although your specific choice of javascript engine will determine the best way to implement it.
var getRandom = () => 1+ Math.floor( Math.random() * 3 ) ;
// get random line
var getLine = () =>
{
do
var l = {
'a' : {
'x' : getRandom(),
'y' : getRandom()
},
'b' : {
'x' : getRandom(),
'y' : getRandom()
}
};
// repeat until startPoint differ from endPoint
while ( l.a.x == l.b.x & l.a.y == l.b.y )
return l;
};
var match = (K, L, M) => {
// Tirangle consist of three points
// three lines -> six points
var p1 = K.a.x + "," + K.a.y,
p2 = K.b.x + "," + K.b.y,
p3 = L.a.x + "," + L.a.y,
p4 = L.b.x + "," + L.b.y,
p5 = M.a.x + "," + M.a.y,
p6 = M.b.x + "," + M.b.y;
// count frequency
var freq = {};
freq[p1] = freq[p1] + 1 || 1;
freq[p2] = freq[p2] + 1 || 1;
freq[p3] = freq[p3] + 1 || 1;
freq[p4] = freq[p4] + 1 || 1;
freq[p5] = freq[p5] + 1 || 1;
freq[p6] = freq[p6] + 1 || 1;
// result Array
var result = Array();
for ( point in freq ){
// if the point is common for two lines add to result array
freq[point] == 2 ? result.push( point ) : false;
}
return result;
}
var test = () => {
// Three random lines
var K = getLine(), L = getLine(), M = getLine();
// Test if three lines has three common points
if ( match(K, L, M).length == 3 ) {
printSvg(K,L,M);
return 1
} else {
return 0
}
}
// run when document ready
var app = () => {
// div#box needed to print svg with triangles
const box = document.getElementById('box');
// test random lines, repeat
for (x =0; x <= 1000; x++) {
t = test ();
}
}
// fire app() when document ready
document.onreadystatechange = ()=> document.readyState == "complete" ? app() : false;
// format legend html
var printWsp = (L) => "("+ L.a.x + ","+ L.a.y+") ("+L.b.x+","+L.b.y+")";
// append svg to div#box
var printSvg = (K, L, M) => {
var legend = '<div class="legend">K ' + printWsp(K) +"<br>L " + printWsp(L) +"<br>M "+ printWsp(M) + "</div>";
var svgStr = "<svg height='250' width='250'>";
svgStr += "<line x1="+K.a.x*60 +" y1="+K.a.y*60 +" x2="+K.b.x*60 +" y2="+K.b.y*60 +" style='stroke:rgb(255,0,0);stroke-width:2' />";
svgStr += "<line x1="+L.a.x*60 +" y1="+L.a.y*60 +" x2="+L.b.x*60 +" y2="+L.b.y*60 +" style='stroke:rgb(0,255,0);stroke-width:2' />";
svgStr += "<line x1="+M.a.x*60 +" y1="+M.a.y*60 +" x2="+M.b.x*60 +" y2="+M.b.y*60 +" style='stroke:rgb(255,0,255);stroke-width:2' />";
svgStr += "</svg> ";
box.insertAdjacentHTML('beforeend', legend);
box.insertAdjacentHTML('beforeend', svgStr);
}

How to use Javascript class for xirr formula

Hello I have found a javascript class for some excel functions but i dont know how to use it. I need to use XIRR function but i dont know the type and format of parameters and the syntax.
Here is the code:
/* Based on
* - EGM Mathematical Finance class by Enrique Garcia M. <egarcia#egm.co>
* - A Guide to the PMT, FV, IPMT and PPMT Functions by Kevin (aka MWVisa1)
*/
var ExcelFormulas = {
PVIF: function(rate, nper) {
return Math.pow(1 + rate, nper);
},
FVIFA: function(rate, nper) {
return rate == 0? nper: (this.PVIF(rate, nper) - 1) / rate;
},
PMT: function(rate, nper, pv, fv, type) {
if (!fv) fv = 0;
if (!type) type = 0;
if (rate == 0) return -(pv + fv)/nper;
var pvif = Math.pow(1 + rate, nper);
var pmt = rate / (pvif - 1) * -(pv * pvif + fv);
if (type == 1) {
pmt /= (1 + rate);
};
return pmt;
},
IPMT: function(pv, pmt, rate, per) {
var tmp = Math.pow(1 + rate, per);
return 0 - (pv * tmp * rate + pmt * (tmp - 1));
},
PPMT: function(rate, per, nper, pv, fv, type) {
if (per < 1 || (per >= nper + 1)) return null;
var pmt = this.PMT(rate, nper, pv, fv, type);
var ipmt = this.IPMT(pv, pmt, rate, per - 1);
return pmt - ipmt;
},
DaysBetween: function(date1, date2) {
var oneDay = 24*60*60*1000;
return Math.round(Math.abs((date1.getTime() - date2.getTime())/oneDay));
},
// Change Date and Flow to date and value fields you use
XNPV: function(rate, values) {
var xnpv = 0.0;
var firstDate = new Date(values[0].Date);
for (var key in values) {
var tmp = values[key];
var value = tmp.Flow;
var date = new Date(tmp.Date);
xnpv += value / Math.pow(1 + rate, this.DaysBetween(firstDate, date)/365);
};
return xnpv;
},
XIRR: function(values, guess) {
if (!guess) guess = 0.1;
var x1 = 0.0;
var x2 = guess;
var f1 = this.XNPV(x1, values);
var f2 = this.XNPV(x2, values);
for (var i = 0; i < 100; i++) {
if ((f1 * f2) < 0.0) break;
if (Math.abs(f1) < Math.abs(f2)) {
f1 = this.XNPV(x1 += 1.6 * (x1 - x2), values);
}
else {
f2 = this.XNPV(x2 += 1.6 * (x2 - x1), values);
}
};
if ((f1 * f2) > 0.0) return null;
var f = this.XNPV(x1, values);
if (f < 0.0) {
var rtb = x1;
var dx = x2 - x1;
}
else {
var rtb = x2;
var dx = x1 - x2;
};
for (var i = 0; i < 100; i++) {
dx *= 0.5;
var x_mid = rtb + dx;
var f_mid = this.XNPV(x_mid, values);
if (f_mid <= 0.0) rtb = x_mid;
if ((Math.abs(f_mid) < 1.0e-6) || (Math.abs(dx) < 1.0e-6)) return x_mid;
};
return null;
}
};
You want to use XIRR, so let's look at its signature:
XIRR: function(values, guess)
What does it do with values?
var f1 = this.XNPV(x1, values);
So values must be whatever XNPV is expecting. It has this chunk at its core:
for (var key in values) {
var tmp = values[key];
var value = tmp.Flow;
var date = new Date(tmp.Date);
xnpv += value / Math.pow(1 + rate, this.DaysBetween(firstDate, date)/365);
};
So it is expecting values to be a dictionary (associative array), where the value part of the key-value pair has members .Flow and .Date. I assume .Flow is the cashflow, and from the DaysBetween method I can see that .Date is a javascript Date. The key is ignored, so it can be a numeric if we want. So let's make one of those:
var myInstrument = { 0: {Flow: 5, Date: new Date(2015, 7, 6)},
1: {Flow: 105, Date: new Date(2016, 7, 6)} };
(That is a dictionary (or array) declaration).
The other input to XIRR is guess, which it will use to solve something, but it will default to using 0.1 (10% !) if given a falsy input value. So we can call it with our myInstrument thus:
var myInternalReturn = XIRR(myInstrument, false);
NB: The XIRR function is implementing the Actual/365 Fixed day count convention for Annual payment frequency, which may not be appropriate for the instrument you are valuing. Maybe it won't make much difference, but it will be incorrect for semi-annual or 30/360, with particular problems around month-end dates, simple interest instruments and so on

Categories