What is the type of nan's?

Monami's icon

Hi community,

I have been playing for about a year now with MaxMSP and I decided I wanted to try to star writing externals. I have been doing installations with patches that communicated over network. Some of the patches sometimes generate nan. So want to write an external that can replace nan from any kind of input: int, float, list, matrices... with the last input value or replace it with a value specified by an argument at the object creation.

To see what is a nan in MaxMSP I wrote this external taking a list as input and posting the value and type of the members of the atom to the max window. I was surprise to see that the atom corresponding in the list where I introduced the nan by dividing a float by 0. was a float type whit the value nan.

Now if this is the form of a atom:

union word
{
long w_long;
float w_float;
t_symbol *w_sym;
t_object *w_obj;
};
typedef struct atom
{
short a_type;
union word a_w;
} t_atom;

how can you put in w_float the value nan???

I am running a MBP whit osX 10.4.9 MaxMSP 4.6 and the SDK UB 4.6.

Joshua Kit Clayton's icon

On May 29, 2007, at 5:00 PM, Emmanuel wrote:

> how can you put in w_float the value nan???

NaN is a special floating point number: http://en.wikipedia.org/wiki/NaN

Sounds like you're trying to make a max version of bitsafe~ which
also filters out +/- infinity. You could use the following macros
from z_dsp.h from the MSP headers. This is essentially what bitsafe~
does.

#define NAN_MASK 0x7F800000
#define IS_NAN_FLOAT(v)        (((*(unsigned long *)&(v))&0x7f800000)
==0x7f800000)
#define IS_NAN_DOUBLE(v)        (((((unsigned long *)&(v))[1])&0x7fe00000)
==0x7fe00000)

Hope this helps. If after reading up a bit on the subject, it's not
too clear, I might suggest with some slightly more straightforward
tasks before tackling this.

-Joshua

Monami's icon

Thank you very Joshua for your prompt answer the link to wikipedia helped me to understand a little more about nan's.

Tell me if I am wrong nan can only be floating point value?

Also from the wikipedia page they say there is to type of nan, qnan and snan. The Define you gave me are for which one?

In the patch below, the sqrt would produce a nan and the output right? A nan can't be a int or long? from the wiki page they say there is no way to represent a nan as an integer. Does that mean that if a max object take a int but from a flaw in calculation produce a nan the type would be float? So in my code I just have to implement methods for float and double in list, matrices and for float coming in a inlet. right?

Thanks again

Mani

the patch:

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

Emmanuel Jourdan's icon
Peter Castine's icon

Quote: jkc wrote on Wed, 30 May 2007 03:25
----------------------------------------------------

> #define NAN_MASK 0x7F800000
> #define IS_NAN_FLOAT(v)        (((*(unsigned long *)&(v))&0x7f800000)
> ==0x7f800000)
> #define IS_NAN_DOUBLE(v)        (((((unsigned long *)&(v))[1])&0x7fe00000)
> ==0x7fe00000)

----------------------------------------------------

Just an idea: an arguably more portable way to test for NaN is

#define IS_NAN(v) ((v) != (v))

And actually nowadays I would inline rather than macro:

Boolean IsNan(double v)
{ return v != v; }

One of the interesting properties of NaN in the IEEE standard is that (NaN == NaN) always evaluates to FALSE, even if the NaNs are identical bit patterns.

Enjoy,
Peter

Eric Lyon's icon

===
A crude but usually effective test for NaN can be written based on the fact that IEEE NaN's never compare equal to anything, even themselves; therefore a number that doesn't compare equal to itself must be a NaN:

    #define isnan(x) ((x) != (x))

Beware, though, that non-IEEE-aware compilers may optimize the test away.
===

That last caveat scares me a tiny bit. Is there a safer way to stamp out NaNs, for paranoid programmers?

Eric

Peter Castine's icon

Quote: Eric Lyon wrote on Sat, 16 June 2007 13:12
----------------------------------------------------
>     #define isnan(x) ((x) != (x))
>
> Beware, though, that non-IEEE-aware compilers may optimize the test away.
> ===
>
> That last caveat scares me a tiny bit. Is there a safer way to stamp out NaNs, for paranoid programmers?

----------------------------------------------------

Paranoia is occasionally good, but I wonder what compilers are out there for Windows and MacOS that are not IEEE-savvy? (That's a real question, not rhetoric.) I would expect IEEE-ignorance to be a dying, if not already extinct, breed.

The alternative is to test against the bit pattern in the exponent bits that flags NaN. That simply requires the sort of typecasting Joshua suggested a few posts back.

If you're just worried about "is my compiler optimizing my NaN test away?" it's possible to check the assembley output, even if you're not fluent in the underlying assembly language.

Eric Lyon's icon

Following up, I tried three methods for denormalizing a sample inside the perform routine of one of my delay/feedback externals:

1. Do nothing. (Works fine on PPC hardware).

2. JKC's macro, used like this:

    if ( IS_NAN_DOUBLE( feedsamp ) ) {
        feedsamp = 0.0;
    }

3. My own ad hoc method:

    if( feedsamp < 0.000001 && feedsamp > -0.000001 ){
        feedsamp = 0.0;
    }

Tested on a 2GHz dual core Intel iMac with 10.4.9, 4.6.3:

Result: both methods 1 and 2 presented the same behavior: 0% CPU usage while signal is flowing into the delay line, followed by a surge to 3-5% CPU sustained indefinitely once input is zeroed and the denormals tail kicks in. Zeroing the delay memory returns CPU to 0%.

My method holds at 0% CPU indefinitely with no intervention.

Eric

AlexHarker's icon

Quote: Eric Lyon wrote on Sat, 16 June 2007 13:45
----------------------------------------------------

> My method holds at 0% CPU indefinitely with no intervention.

Ummm. Yes, but that's what I'd expect - aren't you confusing NaNs and denorms? A denormalised floating point number is still a number, just out of normal range. The first two versions don't test for this (the second ones testing for NaNs, but as long as your feedback is < 1 then you wouldn't expect these anyway). A test for NaNs won't catch denorms.

However there are denorm test macros in the maxMSP SDK (IS_DENORM_NAN_FLOAT / IS_DENORM_NAN_DOUBLE) plus test/fix macros (FIX_DENORM_NAN_FLOAT / FIX_DENORM_NAN_DOUBLE), and also a test to see whether you should bother looking for denorms (so your ppc code can run faster as they won't occur) (DENORM_WANT_FIX), but last time I looked the header file z_dsp.h was defined so that denormals are NOT fixed under MacIntel, but only under windows. This may have been fised by now (OK - jut checked the code from the website - and no it hasn't been, so if you want to use this test, you'll need the following fix). You can however fix the relevant code by substituting:

#if defined(WIN_VERSION) || (defined(MAC_VERSION)
&&TARGET_RT_LITTLE_ENDIAN)
#define DENORM_WANT_FIX 1
#endif

(credit due to jkc for this fix)

Sorry if I've confused what you mean, but this is my interpretation of your results from what you've written.

Cheers,

Alex

Eric Lyon's icon

> aren't you confusing NaNs and denorms?
> A denormalised floating point number is still a number,
> just out of normal range.

As a matter of fact I was. I can confirm that the following macro solves the problem:

IS_DENORM_FLOAT()

IS_DENORM_NAN_FLOAT() is unnecessary since there is no need to check for NaNs in this case.

Thanks,

Eric

AlexHarker's icon

Quote: Eric Lyon wrote on Wed, 20 June 2007 21:41

> IS_DENORM_NAN_FLOAT() is unnecessary since there is no need to check for NaNs in this case.

Of course. Missed this, as I didn't see all the flavours of macro when I was working at speed.

Another couple of possible points of interest. Looking at the SDK again I see that the fixing macros are undefined on the mac platform (again the sdk doesn't seem to be totally updated for intel), and also that the definition of nan/denorm doubles is different between the mac/windows platform, in a way that suggests that the mac macros will only work on PPC, because they are defined for big-endian cases, and not little-endian ones (as under intel). I'm not 100% this is the case, but that's what it looks like to me... This isn't an issue in your case eric if using floats, but may be for anyone using doubles. Maybe Joshua could comment on this if he happens to read this thread, and maybe it could be fixed in the next SDK?

Cheers,

Alex