nan
Hai group,
In a project I occasionaly get a "nan" in stead of a number. That makes my oscillators stop and the sound fuck up. It is a situation where a line~ is fed with bend-data (0-16383). The line~ has a tuneable time as a kind of legato. Does that "nan" mean that a buffer is full (after some time the numbers appear again by themselves).
Thx for any advice.
Peter
nan = not a number. Usually occurs when you divide by 0 and is typically
showing up in javascript/java. You may be using a js script that
converts/scales your input data, so when you send a particular value of
slider (e.g. 0) you get bad equation (e.g. some_number divided by 0 from
your controller).
Best wishes,
Ivica Ico Bukvic, D.M.A.
Composition, Music Technology, CCTAD
CHCI, CS, and Art (by courtesy)
Director, DISIS Interactive Sound & Intermedia Studio
Virginia Tech
Dept. of Music - 0240
Blacksburg, VA 24061
(540) 231-6139
(540) 231-5034 (fax)
ico@vt.edu
http://www.music.vt.edu/faculty/bukvic/
> -----Original Message-----
> From: maxmsp-bounces@cycling74.com [mailto:maxmsp-bounces@cycling74.com]
> On Behalf Of Peter
> Sent: Wednesday, August 06, 2008 4:07 PM
> Subject: [maxmsp] nan
>
>
> Hai group,
>
> In a project I occasionaly get a "nan" in stead of a number. That makes my
> oscillators stop and the sound fuck up. It is a situation where a line~ is
> fed with bend-data (0-16383). The line~ has a tuneable time as a kind of
> legato. Does that "nan" mean that a buffer is full (after some time the
> numbers appear again by themselves).
> Thx for any advice.
>
>
>
> Peter
[**] PEDANT WARNING [**]
With division only dividing 0.0 by 0.0 should be a NaN (in fact dividing ints 0 by 0 using the / object gives 0).
+ve floats divided by 0.0 will be +inf and -ve floats divided by 0.0 will be -inf.
Other ways of generating NaNs are, for example, square rooting -ve numbers.
Of course +/- infinity will probably screw things up just as efficiently as NaNs and although this is perhaps pedantic it might help track down the problem!
.. and of course jkc's bitsafe~ fixes NaNs and +/-infs anyway.
Quote: martinrobinson wrote on Thu, 07 August 2008 17:30
----------------------------------------------------
> With division only dividing 0.0 by 0.0 should be a NaN (in fact dividing ints 0 by 0 using the / object gives 0).
>
> +ve floats divided by 0.0 will be +inf and -ve floats divided by 0.0 will be -inf.
>
> Other ways of generating NaNs are, for example, square rooting -ve numbers.
>
> Of course +/- infinity will probably screw things up just as efficiently as NaNs and although this is perhaps pedantic it might help track down the problem!
Pedantry appreciated! :)
Quote: martinrobinson wrote on Thu, 07 August 2008 17:30
----------------------------------------------------
> [**] PEDANT WARNING [**]
>
> With division only dividing 0.0 by 0.0 should be a NaN (in fact dividing ints 0 by 0 using the / object gives 0).
>
> +ve floats divided by 0.0 will be +inf and -ve floats divided by 0.0 will be -inf.
>
> Other ways of generating NaNs are, for example, square rooting -ve numbers.
>
> Of course +/- infinity will probably screw things up just as efficiently as NaNs and although this is perhaps pedantic it might help track down the problem!
----------------------------------------------------
A bit more pedantry:
NaN and +/-Inf are special values in the IEEE 754 specification of how computers (are supposed to) represent float values. NaN and +/-Inf occur in exactly those situations where your math[s] teacher taught you to expect them: 0/0 is undefined, hence NaN; sqrt(-1) is undefined (in the Real domain), etc. +/-1 divided by 0 is infinite, tan(pi/2) is infinite, and so on; so in IEEE754 they result in Inf with the appropriate sign.
Integers are not covered by the IEEE754 spec (because the spec is for *floating point* values). So what happens with integer 0/0 is determined primarily by the processor manufacturer. Motorola built the 68k and PPC chip series so that 0/0 resulted in 0 (which is wrong mathematically, but what's a poor chip supposed to do?) Intel decided that 0/0 should crash the application (which is not wrong mathematically, but sheez, what an anal-retentive PITA solution). The [/] object, not wanting to crash on 0/0 on an Intel, must special-case for a zero divisor, suppress the call to machine division, and spit out some result. It happens to spit out the same result that the Motorola chips performed in hardware, a solution that has cross-platform compatibility going for it.
All of the previous paragraph applies to any integer dividend, btw.
You'll find out a lot more pedantic stuff if you Google IEEE-754, or just look up the Wikipedia article.
BTW, the other thing you may have to watch out for is -0.0.
-- P.
You can of course get to infinity with apparently reasonable arithmetic (if you ever considered dividing by zero unreasonable that is):
You get to inf if you click the button enough times.
Quote: martinrobinson wrote on Fri, 08 August 2008 14:01
----------------------------------------------------
> You can of course get to infinity with apparently reasonable arithmetic (if you ever considered dividing by zero unreasonable that is):
----------------------------------------------------
Yeah, exponential growth will do that to you. As the Emperor of India learned to his dismay.(*)
With 32-bit floating point, the largest representable number is in the region of 10^37. You want bigger numbers, you need more bits. Simple as that.
-- P.
PS (*): There is a legend that the Emperor of India was sufficiently impressed when chess was invented that, following custom, he offered the Inventor a token of his appreciation. But the Emperor was cheap, the reward was small, and the Inventor was clever. The latter declined the original offer and asked instead for one small, humble gift for 64 days, one day for each square of The Invention. Day one was to be a single grain of rice, two grains on the second day, *four* on the third, and doubling the amount of rice on each subsequent day. The Emperor thought he was getting off easy, but at the 15th day he's already up to a pound of rice, and we're at tons after four weeks. Around the 50th day the Inventor was literally owed "all the rice in China" (currently 184 million metric tons annually), and the current world production of rice would run out a week later.
This is just a story, a real Asian tyrant would probably have had the Inventor killed in the third week. But hopefully you've learned the lesson of exponential growth.
Sources: Wikipedia, WikiAnswers.
I knew you wouldn't need much provoking, Peter, to come out with some interesting nuggets :)
Seriously, the reason I mentioned the possibility of exponential growth resulting in an Inf is that this can be the cause of problems like this since it's not much of a step from a Inf to a NaN. Having said this the only ones I can think of are Inf/Inf and of course sqrt(-Inf).
I figured you could make a non-signal bitsafe abstraction too. Using select to detect NaNs and Infs doesn't appear to distinguish between them which is useful (since there are different flavours of NaN depending what caused it). The == object tested equality for Infs but not NaNs (even of the same flavour).
I think I'm going to put my mind to something else now :)
Quote: martinrobinson wrote on Sat, 09 August 2008 09:19
----------------------------------------------------
> The == object tested equality for Infs but not NaNs (even of the same flavour).
----------------------------------------------------
This is as it should be.
IEEE754 states that NaN is not equal to anything, even itself. In fact, one way of testing if a value is NaN is as follows:
----
double x = SomeFunction();
if (x != x) {
printf("SomeFunction() returned NaN");
}
----
This is *not* the preferred way to test for NaN in C/C++, there's a library function isnan() that you should use instead. The code has an undeniable charm, but a compiler might optimize it out!
BTW, your sample patch from a few posts ago (the one generating infinity by multiplying by tens) also produces interesting results if modified to work with ints. Ints do not have special bit patterns for representing infinity etc. On Intel and Motorola processors an overflow simply results in an implicit modulo calculation (ie modulo whatever the register capacity is). Cute, but not how your 3rd grade teacher taught you long multiplication.
The bitsafe patch is also cute.
Quote: Peter Castine wrote on Sat, 09 August 2008 21:42
----------------------------------------------------
> there's a library function isnan() that you should use instead.
----------------------------------------------------
Doing it in C would be easy! :)
Initially I thought it would be difficult to do that test in Max using standard objects. And thanks, the detail non NaN != NaN is useful. Curious, though, that [select] carefully caters for NaNs and Infs.
One thing I couldn't figure out without building an external was getting at the float bit pattern (although I'd guess there's some hideous arithmetic trick to do this without typecasting in C).
Anyway, I built a very simple "floatbits" external which converts (casts) in both directions since I'll be using it for teaching this stuff over the next year. I'll upload it somewhere soon.
An external to convert (cast) floats to their equivalent bit pattern as an int and vice versa.
Tested in Max 5 (but should work in Max 4 although the help patches are in Max 5 format). Mac and Windows externals included with source code.
Okay, so I'm getting the same error message, although mine occur when dividing two floats of extremely small value. I'm still working to pinpoint exactly when it happens, but they happen when dividing something like 0.000000000xyz by 0.000000000abc. I will get a nan when this occurs.
I'm guessing that this is also a limitation of Max/MSP's 32-bit computing. I've been seeking help from my friends, and they've suggested that Max/MSP's computation engine actually rounds values down to 0 when they get really really small (hence, 0.000xyz / 0.000abc becomes 0.000xyz / 0.000 = nan). If this is true, then at what point does Max/MSP round the value down to 0?
I'm willing to round numbers up or down to avoid this problem, but I'd like to keep as much decimal resolution as possible, so knowing the exact threshold of rounding would be helpful.
afaik Max uses the standard format : http://en.wikipedia.org/wiki/Single-precision_floating-point_format
It's not "Max rounding down." All Max is doing is standard processing on the floating-point unit on the processor. You feed it 32-bit numbers, it feeds the numbers and an operator to the FPU, the FPU returns a result. If the result is +/-Inf or NaN, well, you're screwed. Particularly if the numbers are in the MSP signal chain.
If you feed two really small numbers and divide, the result is going to be a really gargantuan number. If that humongous number is too large to represent in IEEE 754 (see Vichug's link), then you will typically get +/-Inf. It is possible to get numbers so small (see "denormal numbers" in the Wikipedia article) that they are, from the point of view of division, indistinguishable from zero. Then you'll NaN.
But it's the numbers you're feeding to Max that are generating the Infs and NaNs. If you don't want those ugly results, it's up to you to make sure they don't happen.
so knowing the exact threshold of rounding would be helpful.
See Vichug's link. 32-bit binary floats have a 24-bit mantissa, an 8-bit exponent, and a sign bit (how 33 bits of information get packed into a 32-bit storage unit is covered in the link).
BTW, 64-bit doesn't put an end to the difficulties you're seeing. It merely postpones them.
Just in case anyone was thinking 64 bits would give you the Big Rock Candy Mountain.