Forums > MaxMSP

if to expr…wtf?

January 20, 2014 | 11:52 am

Can someone kindly tell me why the combined expression in the included patch is not a valid substitute for the split expression that utilizes [if]? Logically, how do they differ?

Specifically, why is the "else" element of [if $f1<0.5 then $f1 else out2 $f1] not equivalent to ($f1>=0.5) ?

I suspect the nan error is related to the sqrt but it doesn’t make sense why the same error doesn’t occur with the variation using [if].

– Pasted Max Patch, click to expand. –

January 20, 2014 | 12:24 pm

The result of ($f1>=0.5) is 0 or 1. $f1 can be any value.


January 20, 2014 | 12:50 pm

The result of ($f1>=0.5) is 0 or 1. $f1 can be any value.

That’s the whole point of using a relational function in the expression.

If ($f1=0.5) is true, then ($f1>=0.5) is false and vice versa.. so the expression reduces to one of two possibilities: [0*x + 1*y] or [1*x + 0*y]. Hence, it should output either x or y for any input [0..1].

– Pasted Max Patch, click to expand. –

January 20, 2014 | 1:23 pm

hold


January 20, 2014 | 1:31 pm

The "else" statement of [if $f1==0.5 then $f1 else out2 $f1] is ($f1!=0.5).

If $f1 = 15 then ($f1==0.5) = 0 and ($f1!=0.5) = 1.


January 20, 2014 | 1:34 pm

Look at it this way

"Specifically, why is the "else" element of [if $f1<0.5 then $f1 else out2 $f1] not equivalent to ($f1>=0.5) ?"

"Specifically, why is the "else" element of[ if 15.<0.5 then 15. else out2 15.] not equivalent to (15.>=0.5) = 1?"


January 20, 2014 | 1:44 pm

I think you are right, the issue is the ‘nan’ mixed with floats.

<code>

– Pasted Max Patch, click to expand. –

</code>

G

PS the difference, I guess, is that in one case the if is within the expression and thus the ‘nan’ is messing up the computation as it is always calculated (the sum of the two and in one there is ‘nan’).

in the other case the if is outside the computation and the program checks for what is true and based on that compute a value.


January 20, 2014 | 1:45 pm

"Specifically, why is the "else" element of[ if 15.<0.5 then 15. else out2 15.] not equivalent to (15.>=0.5) = 1?"

(15<0.5) is false. (15>=0.5) is true. So the value of 15 gets passed out the second outlet instead of the first. Perfectly logical.

By the same token, [(15<0.5)*x + (15>=0.5)*y] is equivalent to [0*x + 1*y] = y

Again, no logical inconsistency.


January 20, 2014 | 1:50 pm

The if outputs 15. The expr outputs 1.


January 20, 2014 | 2:02 pm

OK… answering my own question – at least in terms of getting the expression to work. I’m still not sure why the same expression doesn’t fail when split by the if object. Somehow, a negative value is generated within expr as it is evaluating the two conditions.

– Pasted Max Patch, click to expand. –

January 20, 2014 | 2:06 pm

as I said above I think the issue is an expression with a non number as one of the element to be calculated.
By adding the ‘abs’ you are getting rid of the ‘nan’ from the negative value inside of ‘sqrt’
that’s all…
see my example above and the expression adding nan to real, the result is surprise surprise nan.
G

PS to be sure it is clear:
<code>

– Pasted Max Patch, click to expand. –

</code>


January 20, 2014 | 2:35 pm

The if outputs 15. The expr outputs 1.

No… using your example, the expr outputs 1 * 15.

Follow me here… [if $f1<0.5 then $f1 else out2 $f1] ( with out1 feeding to x and out2 to feeding to y) you can use [expr ($f1<0.5)*$f1*x + ($f1>=0.5)*$f1*y]. iow, the if object outputs the input to one of two outputs, which is then processed by an expression. The expr object multiplies 1 or 0 by the input * an expression. It’s the same logic in a single object.


January 20, 2014 | 2:44 pm

By adding the ‘abs’ you are getting rid of the ‘nan’ from the negative value inside of ‘sqrt’ that’s all…

Well, yeah.. that’s why I used it. I admit it came in a "duh" moment.

But my original confusion still hasn’t been addressed… Why does the same sqrt expression fail when the logic is evaluated internally by the expression object yet work when the logical is handled by the if object?


January 20, 2014 | 6:12 pm

because inside the expr object there is no type check?


January 20, 2014 | 6:29 pm

just had a quick look, can it be that you need to put another bracket around everything behind the boolean?
[expr ($f1>0.5)*((0.5)*...) + ... ]

Nope.. that was the first thing I checked. But I agree the 0.5 does look kinda naked.

There is something internal happening in [expr].. somehow signed values are being created in the process of evaluating the logic.. even if for only a flash moment.. and then whammo… NAN.


January 20, 2014 | 6:36 pm

because inside the expr object there is no type check?

I thought that was defined by the operators… > is boolean… sqrt is not, etc.


January 20, 2014 | 9:22 pm

as you can see i deleted my first response before you copied it.

now lets see if my second version is better. :)


January 21, 2014 | 4:25 am

"Why does the same sqrt expression fail when the logic is evaluated internally by the expression object yet work when the logical is handled by the if object?"

Because in the combined expr equation one side is always nan. The if removes the nan.

<code>

– Pasted Max Patch, click to expand. –

</code>


January 21, 2014 | 9:04 am

Rick, you’re right! I don’t know how I missed that. For some reason I was thinking that a false evaluation would equal 0… while somehow overlooking 0 * x. In most cases, multiplying by zero generates a zero.. which is enough to get the job done. But this time, I was one who was goosed. Thanks for the exchange.


January 22, 2014 | 3:41 am

0*NaN => NaN. Always.

The other thing that trips people up is evaluating (x == x) when x=NaN.


January 22, 2014 | 8:12 am

0*NaN => NaN. Always.

It’s as though 0 and 1 are the Trumps in the deck of numbers… but NaN is the Joker.


January 23, 2014 | 6:36 am

Don’t forget to watch out for infinity.

What do you expect to get from 0*Inf?


January 23, 2014 | 11:11 am

What do you expect to get from 0*Inf?

Well it looks like NaN reigns supreme.. but maybe there is a way to cheat? :)

– Pasted Max Patch, click to expand. –

January 24, 2014 | 11:02 am

Yes, in fact you really need to do something like this if your calculations can produce an Inf or NaN and you don’t want your patch to trip up because of it.

There is a convenience object for this in the MSP domain: [bitsafe~] ("Replace NaN and infinite signal values with 0").

My favorite way to filter out NaN in Max (not MSP) is [if $f1==$f1 then $f1 else 0.]. The IEEE spec for floating point explicitly states that the expression (NaN == NaN) must evaluate to false (which makes sense, if you think about it).


January 24, 2014 | 12:38 pm

Ahh, that’s very helpful. Thank you.

Of course, now I’m confused by all this inf business.. and [if $f1==$f1 then $f1 else 0.] doesn’t address the problem of inf.

Even if something like if ($f1==$f1&&$f1<=2147483647) then $f1 else 0] was adequate to filter inf output, I still don’t understand why the max window will handle up to 2^1023 and flonum will handle up to 2^127.. and I would’t want to filter those larger values unnecessarily. Yet Max is only 32-bit and I always seem limited to 6 decimal places of precision. Seems inconsistent.

Anyway, I don’t mean to take advantage of your time. It’s too bad I can’t buy a round of beers to motivate you to stick around. :)


January 26, 2014 | 9:20 am

No, my little code example only addresses NaN. In C one could write an ISINF macro as follows:

#define ISNAN(x) ((x) != (x))
#define ISINF(x) (!ISNAN(x) && ISNAN(x-x))

Except nowadays I’d write them as inline functions (to avoid the standard unwanted macro side effects). And except if I were writing in a compiled code environment it would arguably be better to use compiler-supplied test functions. But hopefully you get the idea.

Yet Max is only 32-bit and I always seem limited to 6 decimal places of precision.

Max 6.1 is only 32-bit if you tell it to be so. It is 64-bit if you allow it to be so.

The "six decimal places of precision" is, largely, a display issue only. When posting to the Max window, [print] seems to call the standard C function sprintf() with a default "%f" parameter, which rounds the output to six decimal digits. Some other objects display other degrees of precision (capture~, for instance, normally displays three digits after the decimal point, and so on). But floats are always passed between objects with full 32-bit precision (and most objects use 64-bit precision internally).

The 2,147,483,647 you cite is the highest value for a 32-bit signed integer. Floats and integers are different animals and have different min/max values (comparing a float to the maximum integer value is of somewhat limited value, btw). 2^127 is the largest exponent a 32-bit float can have (the largest possible value is greater than that, since the mantissa can be as large as just-less-than-two). 2^1023 is the highest exponent for 64-bit floats.

You might want to spend some quality time with http://en.wikipedia.org/wiki/IEEE_floating_point if you want this to all really make sense.

Finally, one reason the sprintf() function has a default precision of six significant decimal places for floats is because the most common size for floats when the C Standard Libraries were first being developed was 32 bits, and 32-bit floats have 24-bit mantissas, which gives approximately six decimal places of precision. Not much point in the default display precision being higher than that.


January 27, 2014 | 8:54 am

Enlightening. It’s still a bit ambiguous to me if the "full 32-bit precision" that is passed between objects entails 24-bit mantissas/6 decimal places – which would mean that 6 decimal places is more than just a display issue. I’ll check out the IEEE info and see if I can’t clear that up myself… :) Thanks for all the insight.


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