if to expr…wtf?

metamax's icon

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 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].

Max Patch
Copy patch and select New From Clipboard in Max.

Rick's icon

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

metamax's icon

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].

Max Patch
Copy patch and select New From Clipboard in Max.

Rick's icon

hold

metamax's icon

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.

Rick's icon

Look at it this way

"Specifically, why is the “else” element of [if $f1=0.5) ?"

"Specifically, why is the “else” element of[ if 15.=0.5) = 1?"

geotrupede's icon
Max Patch
Copy patch and select New From Clipboard in Max.

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

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.

metamax's icon

"Specifically, why is the “else” element of[ if 15.=0.5) = 1?"

(15 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)*y] is equivalent to [0*x + 1*y] = y

Again, no logical inconsistency.

Rick's icon

The if outputs 15. The expr outputs 1.

metamax's icon

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.

Max Patch
Copy patch and select New From Clipboard in Max.

geotrupede's icon

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

Max Patch
Copy patch and select New From Clipboard in Max.

PS to be sure it is clear:

metamax's icon

The if outputs 15. The expr outputs 1.

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

Follow me here... [if $f1 ( with out1 feeding to x and out2 to feeding to y) you can use [expr ($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.

metamax's icon

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?

Roman Thilenius's icon

because inside the expr object there is no type check?

metamax's icon

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.

metamax's icon

because inside the expr object there is no type check?

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

Roman Thilenius's icon

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

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

Rick's icon

"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?"

Max Patch
Copy patch and select New From Clipboard in Max.

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

metamax's icon

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.

Peter Castine's icon

0*NaN => NaN. Always.

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

metamax's icon

0*NaN => NaN. Always.

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

Peter Castine's icon

Don't forget to watch out for infinity.

What do you expect to get from 0*Inf?

metamax's icon

What do you expect to get from 0*Inf?

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

Max Patch
Copy patch and select New From Clipboard in Max.

Peter Castine's icon

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).

metamax's icon

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 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. :)

Peter Castine's icon

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.

metamax's icon

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.