Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Impact of implicit arrays...

103 views
Skip to first unread message

Chris M. Thomasson

unread,
Jun 11, 2016, 1:52:43 PM6/11/16
to
I created a little complex number library for some new
fractal encryption techniques I am going to put online.
I am a bit worried about all of the arrays I am using in
the following code:
______________________________
"use strict";

function ct_complex_add(c0, c1)
{
return [c0[0] + c1[0], c0[1] + c1[1]];
}

function ct_complex_sub(c0, c1) {
return [c0[0] - c1[0], c0[1] - c1[1]];
}

function ct_complex_abs(c)
{
return Math.sqrt(c[0] * c[0] + c[1] * c[1]);
}

function ct_complex_mul(c0, c1)
{
return [c0[0] * c1[0] - c0[1] * c1[1],
c0[0] * c1[1] + c0[1] * c1[0]];
}

function ct_complex_mul_real(c0, c)
{
return [c0[0] * c, c0[1] * c];
}

function ct_complex_pow(c, p)
{
var l = ct_complex_abs(c);
var s = Math.pow(l, p);
var a = Math.atan2(c[1], c[0]) * p;

return [Math.cos(a) * s, Math.sin(a) * s];
}

function ct_complex_roots(c, p)
{
var l = ct_complex_abs(c);
var s = Math.pow(l, 1.0 / p);
var a = Math.atan2(c[1], c[0]) / p;

var n = Math.ceil(Math.abs(p));
var as = (Math.PI * 2) / p;
var roots = [];

for (var i = 0; i < n; ++i)
{
roots.push([Math.cos(a + as * i) * s,
Math.sin(a + as * i) * s]);
}

return roots;
}
______________________________


If I call any of the functions above in a large
iteration, will memory start to explode and stress
out the garbage collector? I mean will there be
millions of arrays that are allocated during heavy
load? This is purely functional implementation. Can
an intrusive technique give better performance?

Thank you.

Thomas 'PointedEars' Lahn

unread,
Jun 12, 2016, 6:16:10 AM6/12/16
to
Chris M. Thomasson wrote:

> […]
> function ct_complex_add(c0, c1)
> {
> return [c0[0] + c1[0], c0[1] + c1[1]];
> }
> […]
> function ct_complex_sub(c0, c1) {
> return [c0[0] - c1[0], c0[1] - c1[1]];
> }
> […]
> ______________________________
>
>
> If I call any of the functions above in a large
> iteration, will memory start to explode and stress
> out the garbage collector? I mean will there be
> millions of arrays that are allocated during heavy
> load?

The only good answer to such questions is “try and see”. You can start with
a small example and see how the approach scales in various runtime
environments. You might see a pattern emerging if the same ECMAScript
implementation is used.

> This is purely functional implementation. Can
> an intrusive technique give better performance?

Mu.

I referred to my JSX:math/complex.js before, so you are reinventing the
wheel (but you might do it better), but the only real difference to your
approach is that mine is *more* object-oriented: there are Complex instances
(arrays *are* objects too, so your approach is _not_ “purely functional”)
because new Complex instances are created as the result of operations.

Creating new objects when operating on complex values (literally and
figuratively) can only be avoided if an operation function modifies the
object and returns a reference to the modified object. Or one can, with
loss of precision and performance, operate only on string representations,
hoping that the script engine does not create objects from them unless
necessary, i.e. unless String methods are called. Is one of those what you
mean by “an intrusive technique”?

--
PointedEars
FAQ: <http://PointedEars.de/faq> | SVN: <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | ES Matrix: <http://PointedEars.de/es-matrix>
Please do not cc me. / Bitte keine Kopien per E-Mail.

Chris M. Thomasson

unread,
Jun 13, 2016, 3:23:35 PM6/13/16
to
> Chris M. Thomasson wrote:
> […]
> function ct_complex_add(c0, c1)
> {
> return [c0[0] + c1[0], c0[1] + c1[1]];
> }
> […]
> function ct_complex_sub(c0, c1) {
> return [c0[0] - c1[0], c0[1] - c1[1]];
> }
> […]
> ______________________________
>
>
> If I call any of the functions above in a large
> iteration, will memory start to explode and stress
> out the garbage collector? I mean will there be
> millions of arrays that are allocated during heavy
> load?


> > "Thomas 'PointedEars' Lahn" wrote:

> > The only good answer to such questions is “try and see”. You can start
> > with
> > a small example and see how the approach scales in various runtime
> > environments. You might see a pattern emerging if the same ECMAScript
> > implementation is used.

Excellent advise. So far it seems to be okay, but I have
the feeling that it can still blow up.


> This is purely functional implementation. Can
> an intrusive technique give better performance?

> > Mu.

> > I referred to my JSX:math/complex.js before, so you are reinventing the
> > wheel (but you might do it better), but the only real difference to your
> > approach is that mine is *more* object-oriented: there are Complex
> > instances
> > (arrays *are* objects too, so your approach is _not_ “purely
> > functional”)
> > because new Complex instances are created as the result of operations.


:^D Yeah, I am a C programmer at heart, so this type of
(ct_complex_xxx) function naming scheme is natural to me.
Also, so is returning arrays that do not need to be allocated.
That's the main source of my worry.


> > Creating new objects when operating on complex values (literally and
> > figuratively) can only be avoided if an operation function modifies the
> > object and returns a reference to the modified object. Or one can, with
> > loss of precision and performance, operate only on string
> > representations,
> > hoping that the script engine does not create objects from them unless
> > necessary, i.e. unless String methods are called. Is one of those what
> > you
> > mean by “an intrusive technique”?

YES! Intrusive means to change the inputs from (input only)
to (input/output) parameters. So, take the snippet of my
code you saved wrt (ct_complex_add). The intrusive analog
of this could be:

// IMVHO, functional...
> function ct_complex_add(c0, c1)
> {
> return [c0[0] + c1[0], c0[1] + c1[1]];
> }


IMHO, this following code is not so functional!
Its intrusive... ;^o
______________________________
function ct_complex_add(c0, c1)
{
c0[0] += c1[0];
c0[1] += c1[1];
return c0;
}
______________________________


I can do this, but it requires the caller needs to respect the
fact that actual function parameters will be changed. However,
there will be no chance of a new array being created on each
call to this function wrt intrusive design.

;^)

Michael Haufe (TNO)

unread,
Jun 14, 2016, 1:00:11 AM6/14/16
to
Potentially, yes.

You want to avoid the intermediate data structures obviously, but the question is how? Sadly since JavaScript uses CBV evaluation semantics, you won't get any help there [1]. Which means it's up to you to do some creative thinking in your data structures.

Looking at what you have thus far, I don't think there is much you can do to improve things at this level of discourse, at best I think you might get a constant factor speedup at the significant expense of readability. (Bit fiddling and Math.foo() alternatives...)

I think what I would do is evaluate how the application is developing and at that stage try to discover some form of higher level rules that you can exploit. For example, for manipulating sums:

1 + 2 + 3 + ... + n = (n*(n+1)) / 2

Another thought is to switch to polar coordinates instead of Cartesian coordinates as it would simplify multiplication and division at least. With fractal based work this might be more intuitive anyway, yes?




[1] <https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_value>

Chris M. Thomasson

unread,
Jun 14, 2016, 8:17:37 PM6/14/16
to
> "Michael Haufe (TNO)" wrote in message
> news:4a1c28ea-447b-4e9b...@googlegroups.com...

>> On Saturday, June 11, 2016 at 12:52:43 PM UTC-5, Chris M. Thomasson
>> wrote:
>> I created a little complex number library for some new
>> fractal encryption techniques I am going to put online.
>> I am a bit worried about all of the arrays I am using in
>> the following code:
>> ______________________________
>> "use strict";
[...]
>> function ct_complex_mul(c0, c1)
>> {
>> return [c0[0] * c1[0] - c0[1] * c1[1],
>> c0[0] * c1[1] + c0[1] * c1[0]];
>> }
[...]
>> function ct_complex_pow(c, p)
>> {
>> var l = ct_complex_abs(c);
>> var s = Math.pow(l, p);
>> var a = Math.atan2(c[1], c[0]) * p;
>>
>> return [Math.cos(a) * s, Math.sin(a) * s];
>> }
>>
>> function ct_complex_roots(c, p)
>> {
>> var l = ct_complex_abs(c);
>> var s = Math.pow(l, 1.0 / p);
>> var a = Math.atan2(c[1], c[0]) / p;
>>
>> var n = Math.ceil(Math.abs(p));
>> var as = (Math.PI * 2) / p;
>> var roots = [];
>>
>> for (var i = 0; i < n; ++i)
>> {
>> roots.push([Math.cos(a + as * i) * s,
>> Math.sin(a + as * i) * s]);
>> }
>>
>> return roots;
>> }
>> ______________________________
>>
>>
>> If I call any of the functions above in a large
>> iteration, will memory start to explode and stress
>> out the garbage collector?
[...]


> Potentially, yes.

Yup. I agree. Its behaving okay for some stuff, but
I do not trust it under prolonged sustained load.


> You want to avoid the intermediate data structures
> obviously, but the question is how? Sadly since
> JavaScript uses CBV evaluation semantics, you won't
> get any help there [1]. Which means it's up to you
> to do some creative thinking in your data structures.

Agreed. For instance, intrusive function design should
work well here. Lets focus on converting the functional
complex multiplication function:
_______________________________________
>> function ct_complex_mul(c0, c1)
>> {
>> return [c0[0] * c1[0] - c0[1] * c1[1],
>> c0[0] * c1[1] + c0[1] * c1[0]];
>> }
_______________________________________


into an intrusive form:
_______________________________________
function ct_complex_mul(c0, c1)
{
var x = c0[0] * c1[0] - c0[1] * c1[1];
c0[1] = c0[0] * c1[1] + c0[1] * c1[0];
c0[0] = x;

return c0;
}
_______________________________________


Now, this will modify (c0), effectively turning it into
an input/output parameter. To call it in a loop could
look like:
_______________________________________
function foo_with_intrusive()
{
var z = [1, 1];
var c = [2, 2];

for (var i = 0; i < 10; ++i)
{
z = ct_complex_mul(z, c);
}
}
_______________________________________



Also, we can do this another way that involves an explicit
output parameter to the function. Something like:
_______________________________________
function ct_complex_mul(c0, c1, out)
{
out[0] = c0[0] * c1[0] - c0[1] * c1[1];
out[1] = c0[0] * c1[1] + c0[1] * c1[0];

return out;
}
_______________________________________


To call it in a loop could look like:
_______________________________________
function foo_with_out()
{
var out = [0, 0];
var z = [1, 1];
var c = [2, 2];

for (var i = 0; i < 10; ++i)
{
out = ct_complex_mul(z, c);
z[0] = out[0];
z[1] = out[1];
}
}
_______________________________________


Notice that both approaches have caveats, but both of them
will not have a chance to create a shi% load of objects!
Do you have some better ideas here?


> Looking at what you have thus far, I don't think
> there is much you can do to improve things at this
> level of discourse, at best I think you might get a
> constant factor speedup at the significant expense
> of readability. (Bit fiddling and Math.foo()
> alternatives...)

FWIW, check out this sqrt estimation algorithm:

http://forums.parallax.com/discussion/147522/dog-leg-hypotenuse-approximation

;^)

> I think what I would do is evaluate how the application
> is developing and at that stage try to discover some
> form of higher level rules that you can exploit. For
> example, for manipulating sums:

> 1 + 2 + 3 + ... + n = (n*(n+1)) / 2

Indeed.

> Another thought is to switch to polar coordinates
> instead of Cartesian coordinates as it would simplify
> multiplication and division at least. With fractal based
> work this might be more intuitive anyway, yes?

Right. However, I think that converting Polar into Cartesian
in order to add/subtract is the simplest route correct?

Thomas 'PointedEars' Lahn

unread,
Jun 15, 2016, 12:52:44 AM6/15/16
to
Chris M. Thomasson wrote:

> Also, we can do this another way that involves an explicit
> output parameter to the function. Something like:
> _______________________________________
> function ct_complex_mul(c0, c1, out)
^^^
> {
> out[0] = c0[0] * c1[0] - c0[1] * c1[1];
> out[1] = c0[0] * c1[1] + c0[1] * c1[0];
>
> return out;
> }
> _______________________________________
>
>
> To call it in a loop could look like:
> _______________________________________
> function foo_with_out()
> {
> var out = [0, 0];
> var z = [1, 1];
> var c = [2, 2];
>
> for (var i = 0; i < 10; ++i)
> {
> out = ct_complex_mul(z, c);
^^
> z[0] = out[0];
> z[1] = out[1];
> }
> }
> _______________________________________

No, that would be pointless. In fact, the function SHOULD NOT *return* the
changed value then.

But this non-idempotent, non-reentrant code is not thread-safe – it is not
suited for animations.

>> Another thought is to switch to polar coordinates
>> instead of Cartesian coordinates as it would simplify
>> multiplication and division at least. With fractal based
>> work this might be more intuitive anyway, yes?
>
> Right. However, I think that converting Polar into Cartesian
> in order to add/subtract is the simplest route correct?

Yes. UTSL.


Your “From” is borked, see

<http://www.interhack.net/pubs/munging-harmful/>
<http://tools.ietf.org/html/rfc5536#section-3.1.2>

You should also avoid the troll server, aioe.org.

Pseudo-address added to killfile.

F'up2 poster

Thomas 'PointedEars' Lahn

unread,
Jun 15, 2016, 12:55:30 AM6/15/16
to
Chris M. Thomasson wrote:

> Also, we can do this another way that involves an explicit
> output parameter to the function. Something like:
> _______________________________________
> function ct_complex_mul(c0, c1, out)
^^^
> {
> out[0] = c0[0] * c1[0] - c0[1] * c1[1];
> out[1] = c0[0] * c1[1] + c0[1] * c1[0];
>
> return out;
> }
> _______________________________________
>
>
> To call it in a loop could look like:
> _______________________________________
> function foo_with_out()
> {
> var out = [0, 0];
> var z = [1, 1];
> var c = [2, 2];
>
> for (var i = 0; i < 10; ++i)
> {
> out = ct_complex_mul(z, c);
^^
> z[0] = out[0];
> z[1] = out[1];
> }
> }
> _______________________________________

No, that would be pointless. In fact, the function SHOULD NOT *return* the
changed value then.

But this non-idempotent, non-reentrant code is not thread-safe – it is not
suited for animations.

>> Another thought is to switch to polar coordinates
>> instead of Cartesian coordinates as it would simplify
>> multiplication and division at least. With fractal based
>> work this might be more intuitive anyway, yes?
>
> Right. However, I think that converting Polar into Cartesian
> in order to add/subtract is the simplest route correct?

Yes. UTSL.


The “From” and “Reply-To” header fields of your postings are borked, see

<http://www.interhack.net/pubs/munging-harmful/>
<http://tools.ietf.org/html/rfc5536#section-3.1.2>
<http://tools.ietf.org/html/rfc5536#section-3.2>

Chris M. Thomasson

unread,
Jun 15, 2016, 1:19:51 AM6/15/16
to
On 6/14/2016 5:17 PM, Chris M. Thomasson wrote:
[...]
> Also, we can do this another way that involves an explicit
> output parameter to the function. Something like:
> _______________________________________
> function ct_complex_mul(c0, c1, out)
> {
> out[0] = c0[0] * c1[0] - c0[1] * c1[1];
> out[1] = c0[0] * c1[1] + c0[1] * c1[0];
>
> return out;
> }
> _______________________________________
>
>
> To call it in a loop could look like:
> _______________________________________
> function foo_with_out()
> {
> var out = [0, 0];
> var z = [1, 1];
> var c = [2, 2];
>
> for (var i = 0; i < 10; ++i)
> {
> out = ct_complex_mul(z, c);
> z[0] = out[0];
> z[1] = out[1];
> }
> }
> _______________________________________

I have a nasty typo in there. Let me correct that:
_______________________________________
function ct_complex_mul(c0, c1, out)
{
out[0] = c0[0] * c1[0] - c0[1] * c1[1];
out[1] = c0[0] * c1[1] + c0[1] * c1[0];
}

function foo_with_out()
{
var out = [0, 0];
var z = [1, 1];
var c = [2, 2];

for (var i = 0; i < 10; ++i)
{
ct_complex_mul(z, c, out);

Michael Haufe (TNO)

unread,
Jun 18, 2016, 3:47:39 PM6/18/16
to
On Tuesday, June 14, 2016 at 7:17:37 PM UTC-5, Chris M. Thomasson wrote:

> Notice that both approaches have caveats, but both of them
> will not have a chance to create a shi% load of objects!
> Do you have some better ideas here?

This still feels like premature optimization. I'd say start with implementing this in a naive way and optimize from there (after you benchmark). It won't help if on step 1 you have a potentially efficient but cryptic implementation and later on at step N you want/need to refactor but can't because you've built upon a non-obvious implementation.

Something Naive (ES6):

class Complex{}

class ComplexRect extends Complex{
conj(){
return new ComplexRext(this.re,-this.im)
}
constructor(re,im){
this.re = re
this.im = im
}
equals(cr){
return this.re == cr.re && this.im == cr.im
}
magnitude(){
return Math.hypot(this.re,this.im)
}
plus(cr){
return new ComplexRect(this.re + cr.re, this.im + cr.im)
}
times(cr){
return new ComplexRect(
this.re*cr.re - this.im*cr.im,
this.re*cr.im + cr.re*this.im
)
}
//TODO: etc
}

class ComplexPolar extends Complex {
constructor(r, theta){
this.r = r
this.theta = theta
}
// TODO
}

Chris M. Thomasson

unread,
Jun 21, 2016, 5:43:31 PM6/21/16
to
So nice! I have not used ES6 and the (class x extends y) technique. I am
wondering about browser support for this. How good is it?

Humm... FWIW, for some reason I also really like the simple array based
method I am using now.

Yours is easier to read, but for me using foo[0] for x, foo[1] for y,
ect looks more matrix like wrt indexing into an array; its not all that
bad to my eyes. Also, it makes iterating over the elements really intuitive.

Christoph M. Becker

unread,
Jun 21, 2016, 6:10:54 PM6/21/16
to
On 21.06.2016 at 23:43, Chris M. Thomasson wrote:

> Humm... FWIW, for some reason I also really like the simple array based
> method I am using now.
>
> Yours is easier to read, but for me using foo[0] for x, foo[1] for y,
> ect looks more matrix like wrt indexing into an array; its not all that
> bad to my eyes. Also, it makes iterating over the elements really
> intuitive.

Then you might be interested in typed arrays, see, for instance,
<https://developer.mozilla.org/en/docs/Web/JavaScript/Typed_arrays>.

--
Christoph M. Becker

Chris M. Thomasson

unread,
Jun 21, 2016, 6:28:23 PM6/21/16
to
Yes, thank you. FWIW, I use these when I am working with WebGL. However,
the fact that I need to use (new) for each member converting the
following struct:
____________________________
struct someStruct {
unsigned long id;
char username[16];
float amountDue;
};
____________________________


to the following typed array representation:
____________________________
var buffer = new ArrayBuffer(24);

// ... read the data into the buffer ...

var idView = new Uint32Array(buffer, 0, 1);
var usernameView = new Uint8Array(buffer, 4, 16);
var amountDueView = new Float32Array(buffer, 20, 1);
____________________________


Is still troublesome. I will do some benchmarks wrt looping through
functional ops, and their intrusive equivalents. AFAICT, the intrusive
technique basically has to win. :^o

Chris M. Thomasson

unread,
Jun 21, 2016, 6:31:19 PM6/21/16
to
Although, why should I use full blown dynamic arrays, when these types
arrays will work fine? Humm, they almost have to be more efficient in
this respect.

Michael Haufe (TNO)

unread,
Jun 21, 2016, 8:35:19 PM6/21/16
to
On Tuesday, June 21, 2016 at 4:43:31 PM UTC-5, Chris M. Thomasson wrote:

> So nice! I have not used ES6 and the (class x extends y) technique. I am
> wondering about browser support for this. How good is it?

<https://kangax.github.io/compat-table/es6/>

In other words, use TypeScript of Babel and integrate it into your IDE, such as VS Code <https://code.visualstudio.com/>.

> Humm... FWIW, for some reason I also really like the simple array based
> method I am using now.

Which keeps the components implicit, and also makes it a bit harder if you plan to mix/match polar/cartesian coordinates

> Yours is easier to read, but for me using foo[0] for x, foo[1] for y,
> ect looks more matrix like wrt indexing into an array; its not all that
> bad to my eyes.

and yet it isn't a matrix and you don't get the benefit of the operations. it also hides what I mentioned earlier.

> Also, it makes iterating over the elements really intuitive.

There are only two components, why would you iterate?

Chris M. Thomasson

unread,
Jun 22, 2016, 12:08:39 AM6/22/16
to
On 6/21/2016 5:35 PM, Michael Haufe (TNO) wrote:
> On Tuesday, June 21, 2016 at 4:43:31 PM UTC-5, Chris M. Thomasson wrote:
>
>> So nice! I have not used ES6 and the (class x extends y) technique. I am
>> wondering about browser support for this. How good is it?
>
> <https://kangax.github.io/compat-table/es6/>
>
> In other words, use TypeScript of Babel and integrate it into your IDE, such as VS Code <https://code.visualstudio.com/>.

I notice that Chrome gives me a "Reference Error: this is not defined"
such that (alert("hello 1");) never gets called in your constructor:
______________________________
constructor(re, im) {
alert("hello 0");
this.re = re;
alert("hello 1");
this.im = im;
}
______________________________

I must be creating (ComplexRect) objects in a totally screwed up way:
______________________________
{
var c = new ComplexRect(-.75, .09);
alert(c.re + ", " + c.im);
}
______________________________

How do I create instances of (ComplexRect)?

>> Humm... FWIW, for some reason I also really like the simple array based
>> method I am using now.
>
> Which keeps the components implicit, and also makes it a bit harder if you plan to mix/match polar/cartesian coordinates

I need to think here.


>
>> Yours is easier to read, but for me using foo[0] for x, foo[1] for y,
>> ect looks more matrix like wrt indexing into an array; its not all that
>> bad to my eyes.
>
> and yet it isn't a matrix and you don't get the benefit of the operations. it also hides what I mentioned earlier.
>
>> Also, it makes iterating over the elements really intuitive.
>
> There are only two components, why would you iterate?

Because I like to add on extra components for fun/experimental purposes. ;^)

Also, take a look at my (ct_complex_roots) function:
_________________________________________
function ct_complex_roots(c, p)
{
var l = ct_complex_abs(c);
var s = Math.pow(l, 1.0 / p);
var a = Math.atan2(c[1], c[0]) / p;

var n = Math.ceil(Math.abs(p));
var as = (Math.PI * 2) / p;
var roots = [];

for (var i = 0; i < n; ++i)
{
roots.push([Math.cos(a + as * i) * s,
Math.sin(a + as * i) * s]);
}

return roots;
}
_________________________________________


The return value from this can contain more than two objects, so, IMVHO,
the ease of iterating the return value (roots) is very nice wrt Arrays.

Michael Haufe (TNO)

unread,
Jun 22, 2016, 2:09:11 AM6/22/16
to
On Tuesday, June 21, 2016 at 11:08:39 PM UTC-5, Chris M. Thomasson wrote:

> I notice that Chrome gives me a "Reference Error: this is not defined"
> such that (alert("hello 1");) never gets called in your constructor:
> ______________________________
> constructor(re, im) {
> alert("hello 0");
> this.re = re;
> alert("hello 1");
> this.im = im;
> }
> ______________________________
>
> I must be creating (ComplexRect) objects in a totally screwed up way:
> ______________________________
> {
> var c = new ComplexRect(-.75, .09);
> alert(c.re + ", " + c.im);
> }
> ______________________________
>
> How do I create instances of (ComplexRect)?

small typo there. If a class extends another class, super() must be called before referencing "this".

> Because I like to add on extra components for fun/experimental purposes. ;^)
>
> Also, take a look at my (ct_complex_roots) function:
> _________________________________________
> function ct_complex_roots(c, p)
> {
> var l = ct_complex_abs(c);
> var s = Math.pow(l, 1.0 / p);
> var a = Math.atan2(c[1], c[0]) / p;
>
> var n = Math.ceil(Math.abs(p));
> var as = (Math.PI * 2) / p;
> var roots = [];
>
> for (var i = 0; i < n; ++i)
> {
> roots.push([Math.cos(a + as * i) * s,
> Math.sin(a + as * i) * s]);
> }
>
> return roots;
> }
> _________________________________________
>
>
> The return value from this can contain more than two objects, so, IMVHO,
> the ease of iterating the return value (roots) is very nice wrt Arrays.


I'm still missing the point here. Why not have:

class Complex{
...

root(p){...}
}

where c.roots(p) returns an Array<Complex>?

even in your example the roots array still only has two components per entry

Christoph M. Becker

unread,
Jun 22, 2016, 5:55:27 AM6/22/16
to
On 22.06.2016 at 00:31, Chris M. Thomasson wrote:

> On 6/21/2016 3:28 PM, Chris M. Thomasson wrote:

>> On 6/21/2016 3:10 PM, Christoph M. Becker wrote:
>>
>>> Then you might be interested in typed arrays, see, for instance,
>>> <https://developer.mozilla.org/en/docs/Web/JavaScript/Typed_arrays>.
>
> Although, why should I use full blown dynamic arrays, when these types
> arrays will work fine? Humm, they almost have to be more efficient in
> this respect.

I presume they're more efficient, but I've never used them so can't
tell. Most likely there are multiple benchmarks available on the web,
and of course, you could do your own.

--
Christoph M. Becker

Chris M. Thomasson

unread,
Jun 23, 2016, 3:23:47 PM6/23/16
to
Agreed! FWIW, I have already did some of my own, and intrusive style is
around 1.8x faster. Heck, functional style functions totally lock up the
browser and use a lot of memory on that shi%ty Edge browser; I have to
kill the process. Chrome works fine, and gives me timing information. I
have tested normal arrays both functional and intrusive, and intrusive
certainly wins for me. I will post the test today or tomorrow. I am
think of using WebWorkers for the tests because they do not lock up the
damn browser for the duration of process!

;^o

Chris M. Thomasson

unread,
Jun 23, 2016, 5:14:56 PM6/23/16
to
On 6/22/2016 2:55 AM, Christoph M. Becker wrote:
Here is my first try at WebWorkers wrt a "benchmark" of the following
functions:
______________________________
function ct_functional_add_0(a, b)
{
return [a[0] + b[0], a[1] + b[1]];
}

function ct_intrusive_add_0(a, b)
{
a[0] += b[0];
a[1] += b[1];
return a;
}
______________________________

The code for the WebWorker can be found here:

http://funwithfractals.atspace.cc/ct_root/ct_ui/ct_test_worker.js

Along with a webpage here:

http://funwithfractals.atspace.cc/ct_root/ct_ui

You should probably hit refresh on your browser. Anyway, you should see
two buttons:

(Run Intrusive Test), and (Run Functional Test).

Click on one of them, and it runs 1,000,000,000 iterations on the
relevant function.

FWIW, I always seem to get the following results on average:
_____________________________________
The Intrusive Test Completed in 3500ms

The Functional Test Completed in 10000ms
_____________________________________


So, on my end, intrusive wins. Can you please give it a go and post the
results here?

BTW, does this even work for you?

Thanks! :^)

Chris M. Thomasson

unread,
Jun 23, 2016, 5:16:35 PM6/23/16
to
On 6/23/2016 2:14 PM, Chris M. Thomasson wrote:
[...]
> http://funwithfractals.atspace.cc/ct_root/ct_ui
[...]
> BTW, does this even work for you?

I forgot to mention the times I get are for:

Chrome:(51.0.2704.103 m)

Chris M. Thomasson

unread,
Jun 23, 2016, 5:38:51 PM6/23/16
to
On 6/21/2016 11:09 PM, Michael Haufe (TNO) wrote:
> On Tuesday, June 21, 2016 at 11:08:39 PM UTC-5, Chris M. Thomasson wrote:
[...]
> even in your example the roots array still only has two components per entry

Yup. Humm, how about the following functional addition function:

(please excuse any typos, I typed this in the newsreader)
_______________________________________
function ct_complex_add(a, b) {
var n = Math.min(a.length, b.length);

var sum = new Array(n);

for (var i = 0; i < n; ++i) {
sum[i] = a[i] + b[i];
}

return sum;
}
_______________________________________


You can call it like:
_______________________________________
{
var r = ct_complex_add([1, 2], [3, 4]);
alert("r:(" + r + ")");
return true;
}
_______________________________________


We can add extra elements to the arrays, and the function
(ct_complex_add) still works:

_______________________________________
{

var r = ct_complex_add([1, 2, 3, 4], [5, 6, 7, 8]);
alert("r:(" + r + ")");
return true;
}
_______________________________________




We can add extra elements or even pass arrays that have different number
of elements:
_______________________________________
{

var r = ct_complex_add([1, 2, 3], [4, 5, 6, 7]);
alert("r:(" + r + ")");
return true;
}
_______________________________________



What do you think of this? Is it a bit too contrived?

:^o

Chris M. Thomasson

unread,
Jun 23, 2016, 9:14:20 PM6/23/16
to
Something weird happens on Firefox (46.0.1). I am getting numbers like:
_____________________________________
The Intrusive Test Completed in 7100ms

The Functional Test Completed in 400ms
_____________________________________


Strange!


Also, I forgot to update the running total in the
(ct_test_functional_add_0) function from:
________________________
function ct_test_functional_add_0(n) {
var start = new Date().getTime();

var a = [1, 2];
var b = [1, .75];

for (var i = 0; i < n; ++i) {
// *** This line ***
ct_functional_add_0(a, b);
}

var end = new Date().getTime();
return end - start;
}
_____________________________



The line should be:
_____________________________
a = ct_functional_add_0(a, b);
_____________________________


I have fixed it in the webpage:

http://funwithfractals.atspace.cc/ct_root/ct_ui

http://funwithfractals.atspace.cc/ct_root/ct_ui/ct_test_worker.js

You probably need to refresh the page.

Sorry about that.

Chris M. Thomasson

unread,
Jun 23, 2016, 9:47:02 PM6/23/16
to
On 6/23/2016 6:14 PM, Chris M. Thomasson wrote:
> On 6/23/2016 2:16 PM, Chris M. Thomasson wrote:
[...]
> Something weird happens on Firefox (46.0.1). I am getting numbers like:
> _____________________________________
> The Intrusive Test Completed in 7100ms
>
> The Functional Test Completed in 400ms
> _____________________________________
[...]

I fixed it. The times for Firefox (46.0.1) are:
_____________________________________
The Intrusive Test Completed in 7100ms

The Functional Test Completed in 7700ms
_____________________________________


So, the difference between the times of the two tests in Firefox, is not
as great as in Chrome.

Michael Haufe (TNO)

unread,
Jun 24, 2016, 8:22:40 PM6/24/16
to
What do the arrays represent in this case? Before it was [Re,Im]

Chris M. Thomasson

unread,
Jun 25, 2016, 9:03:15 PM6/25/16
to
x, y, z, w? I admit this is highly contrived wrt justifying arrays via
looping... ;^o

Michael Haufe (TNO)

unread,
Jun 25, 2016, 9:24:48 PM6/25/16
to
You can represent Complex Numbers as Matrices as well if you want. It's been 2 years or so since I did much Linear Algebra, so I'd have to brush up again on the subject to provide any insight if you go in that direction though.

Basically given two Matrices:

// 2x2 Identity matrix
var I = [
1, 0,
0, 1
]

// J**2 == -I
// eigenvalues(J) == [i, -i] where i = sqrt(-1)
var J = [
0, -1,
1, 0
]

You can represent the complex number a + bi instead as the matrix aI + bJ and get all the benefits of matrix operations. I would still suggest having an object to represent these of course.

[*] <https://en.wikipedia.org/wiki/Eigenvalues_and_eigenvectors>

Chris M. Thomasson

unread,
Jul 1, 2016, 4:52:52 PM7/1/16
to
Ah yes. agreed. I think I like the array approach a little better
because a user can pass a number like:

foo.bar([.1, .2])

instead of:

foo.bar(new complex(.1, .2))

This is contrived, but I have always liked arrays wrt storing x, y, z,
w, ... like parameters.
0 new messages