Forums > Javascript

Make sure js outputs a floating point number? It seems to mix floats and int!

June 9, 2011 | 11:57 pm

I know this is really obscure, but I hope there’s a solution….

With this function:

function test(v){
     var msg = Effect[1];
    var num=v/127;
    outlet(0,msg,num);
}

I seem to get a mix of int and floats coming from outlet.
If I feed it "test 1" the ouput in max is:
Effect[1] 0.007874
If I feed it "test 0" the ouput in max is:
Effect[1] 0

which, on the surface, seems like no problem. However, the fact that the "0" is an integer type, rather than a float like "0.0" is causing me sadness. For some reason, this change between floats and ints keeps the pattrstorage from reporting the "Effect[1] 0" with all the other stream of messages that have floats. This bizarre wrinkle is causing me some grief, and I’m wondering if there’s a way to force that 0 into a 0.0 from within the js? I already tried parseFloat, which, as you might expect, didn’t work. I’m guessing this has to do with the bridge between js and max, and the fact that js only has the type "number" and doesn’t distinguish between float and int.
Anyway, I hope there’s a good solution. Thanks for listening!
Pete


June 10, 2011 | 8:50 am

You can output a float by specifying the message type, for example:

outlet(0,"float",num);

This will make integers appear with a decimal point. That comes unstuck a bit if you want to have a message preceeding your number though.


June 10, 2011 | 2:11 pm

A nice tip to be treasured for the future, but, that msg is pretty important! I suppose I could do 2 outlets, then pack them in Max, but that would have other irritating consequences. Dammit!


June 11, 2011 | 3:41 am

Yeah, I like that one too!

Pete: have you tried toFixed()? Or maybe, cast the 0 to a string?


June 12, 2011 | 9:55 am

This will probably throw up some sort of problems but it might just be a way you can sneak past the javascript/max boundary the way you want. Clearly it is less than ideal!

outlet(0,"something_here",num+0.00000000001);


June 12, 2011 | 3:03 pm

@aumonra: toFixed! I had a thought about something like that. However, I tried it, and it ends up casting the number as a symbol:
outlet(0,msg,num.toFixed(4));
yeilds
"my msg" "0.0000"
And, given that this is all for controller data, which could be a heavy stream, I really don’t think it’s a good idea to get into symbol to number conversion on the entire stream.
@luke: also considered, but , yeah, I think that would end up causing more problems than solving.

I guess I will just have to abandon all hope of outputmode 2 on pattrstorage, whose "change" filter seems to be the real problem here, and try out outputmode 1….

Thanks for all the suggestions! It’s details like this that provide a salve of learning amid a sting of irritation.

Pete.


June 21, 2011 | 3:07 pm

Just an off-the-wall idea… you could hang a [t f] object after the [js] object to "typecast" any ints to floats. In your case you’d have to [unpack] your message and then [pack] it up again, but it might be a workaround.

‘zat help?


June 21, 2011 | 5:03 pm

Sure, that would work, and I could also just use 2 outlets in the js and avoid an unpack. But its just clumsy. Ultimately, I changed my outputmode on the pattrstorage so it doesn’t have a change filter. This has been ok so far, but as I proceed with testing, it could end up outputting too much data. Keeping my fingers crossed!


September 13, 2011 | 10:26 pm

For the sake of archive, here’s what I did. I changed the output mode on an as-need basis:

outlet(0,"outputmode",1);
outlet(0,msgout,valout_);
outlet(0,"outputmode",2);

April 2, 2013 | 7:48 pm

Sorry to revive this old thread, but I just came upon this same thing when trying to generate a list of filter coefs for cascade~ using a javascript. All coefs that were set as 0. (for unity filters) came out as ints (just 0) in the list and cascade~ complained that the list had to be all floats. I got around it by using Luke Hall’s solution, which is less than ideal- doing something like this in my script

coefs[i+0] = 0.99999999999999999999999999; //stupid hack to get float output in a list
coefs[i+1] = 0.00000000000000000000000001;
coefs[i+2] = 0.00000000000000000000000001;
coefs[i+3] = 0.00000000000000000000000001;
coefs[i+4] = 0.00000000000000000000000001;

and it worked. But there really should be a better way to do this. I’d like a way to specify what type of data an array is interpreted as when sent out of a js object as a list.

Sure – i could in this case type the output as "float", output individual floats and then use a [zl group] to make them into a list… or maybe do something with a coll or dict… but that seems like significantly more extra work when you just want a list of floats. And you need to be very careful with [zl group] if your desired list length can change – been through that one more times than i want to count :)


June 22, 2014 | 5:45 pm

another bump for this thread. there has to be a more elegant solution for this issue. i too am using luke’s solution:

outlet(0,"something_here",num+0.00000000001);


June 23, 2014 | 10:21 am

The basic problem is that Max has two separate data types, int and float, and JavaScript only has one numeric data type, called Number.

JS does all sorts of magic stuff in the background to try to make sure that "the right thing" happens in arithmetic; with Max you have direct control (for instance, dividing two ints gives you integer division, which catches people out who aren’t prepared for it, but can be dead useful when you understand how to use it).

There’s really no way for the JS-to-Max bridge to know that you want a number that looks like it ought to be an int to behave like a float. At least not when it’s in the middle of a message.

So either you have to do it explicitly (with something like [t f]). But then do it without grumbling and whining .-)

Or you use Luke’s hack, which is actually pretty elegant. As these things go. The neat thing about the outlet(0, "msg", intVal + 0.000000000000001) trick is that, when you’re using 32-bit arithmetic in Max (which used to be the only option), you should actually get the float equivalent of your integer, with nothing but zeros after the decimal point. That tiny amount you add in JS to force the value to a float is way beyond the precision available in 32-bit floating point, so it will get lost in Maxland. (Testing this is left to the diligent reader.)


June 23, 2014 | 11:53 am

luke’s hack is certainly helpful & i noticed that it yields the float of equivalent of the desired integer. what i didn’t realize is that js has only one numeric data type, interesting. thanks for your response.


Viewing 13 posts - 1 through 13 (of 13 total)