NAN revisited, a crossover from old to new.

Started by CaveGuy, October 13, 2002, 08:11:34 AM

Previous topic - Next topic

CaveGuy

I posted the following on the old forun last night. Now I have figuring out case sensitivity problem I was haveing with loging in here. I will repeat myself here in the New forum.



Here we go on an adventure in NAN :)



Fresh Start:

newLISP v6.5.23-win32 Copyright (c) 1993-2002 Lutz Mueller. All rights reserved





> (set '+NAN (sqrt -1))



sqrt: DOMAIN error

+NAN

> (NaN? +NAN)

true

> (set 'X +NAN)

+NAN

> (NaN? X)

true

> (save "loadtest.lsp")

true



LoadTest contains:

(set '+NAN +NAN)



(set 'X +NAN)



Fresh Start:

newLISP v6.5.23-win32 Copyright (c) 1993-2002 Lutz Mueller. All rights reserved.





> (load "test")

true

> (symbols)



(! != % & * + +NAN - / < << <= = > >= >> ? MAIN NaN? X ^ abs ...... | ~)

> +NAN

nil

> (NaN? +NAN)



Value expected in function NaN?



> X

nil

> (NaN? X)



Value expected in function NaN?



>







Edit LoadTest file:

;(set '+NAN +NAN)  Don't mess with +NAN !



(set 'X +NAN)



Fresh Start:

newLISP v6.5.23-win32 Copyright (c) 1993-2002 Lutz Mueller. All rights reserved





> (set '+NAN (sqrt -1))



sqrt: DOMAIN error

+NAN

> (NaN? +NAN)

true

> (load "loadtest.lsp")

true

> (NaN? X)

true

>



If +NAN was a constant, then its inference

could be carried between states using (save)(load)

without having to force an seemingly untrapable error to generating one.



> (catch (set '+NAN (sqrt -1)) 'result)



sqrt: DOMAIN error

true

>



How can I generate a +NaN that I can test for with NAN?

without fireing off the error handler ?



Why you ask?



I am using the +NAN as a place holding excluder.



The Current Doc states:



    syntax: (NaN? number )



    Tests if the result of floating point math operation is a NaN.

    Certain floating point operations return a special IEE 754 number

    format called a NaN for 'Not a Number'.



    example:



       (set 'x (sqrt -1)  => NaN

       (add x 123)          => NaN

       (> x 0)            => nil

       (<= x 0)           => nil

       (= x x)            => nil

       (NaN? x)           => true



    Note that all floating point arithmetik operations with a NaN will

    yield a NaN. All comparisons with NaN will return nil,

    even if comparing NaN to itself.



While we are on the subject of the fact that "Certain floating point operations

return a special IEE 754 number format"



How about Pi ? Having access to the constant for Pi would be great !!!

A test (Pi? number ) would be very nice also. Problem is people trying

(Pi? 3.1416)



Final Note: a (div 1 0) should return a +NAN and not return to the OS !





Thanks, now I feel better :)

Keep up the good work.



Thanks

(bob)

bob@bradlee.org
Bob the Caveguy aka Lord High Fixer.

Lutz

#1
there is no symbol for NaN in newLISP (and in any other programming language  I know), '+NaN' is just the way the C-library, with which newLISP was compiled, formats NaN results. You can test a coputing result for NaN'nes, but a comparison of two expressions resulting in NaN will always give 'nil'. This last fact is illustrates the reason, that programming languages don't contain a symbol for NaN.



NaN is not a specific value of something, but rather a concept flagging a result as no computable.





+NaN is just a new symbol you created and has the value nil. The parser takes the '+' and ' -' minus characters only as number prefixes when followed by a number, else a space must be present. NaN is "Not a Number".





Lutz

CaveGuy

#2
In my example +NAN is in fact just a symbol like any other symbol, only it has been (set) to a NaN, the return value generated by the sqrt: DOMAIN error.



I use '+NAN as a reference symbol to the actual NaN in memory.

I can just as easily refer to it as 'X.



In fact +NAN does in have a value. It is not a string, handle, structure, integer ... it is a non-numeric value whose binary pattern represent the results of an invalid operation some where in the floating point specification.

By ignoring NaNs a stack based numeric processor like the 8087 could ignore intermediate calculations that resulted from previous errors.



I understand that it can only be tested for by using

(NaN?) that is to be expected. The fact that I can

bind a symbol to an NaN once it existence proves the

argument for assignability.



> (set '+NAN (sqrt -1))



 sqrt: DOMAIN error      ;<---- this is my nemeses

 +NAN                    ; give be a way to catch this error

 > (NaN? +NAN)           ; and I will go away for a while :)

 true

 > (set 'X +NAN)

 +NAN

 > (NaN? X)

 true

 >



We all use nil as a third state -1 0 1  True False Nil(unknown).

We use (list?) and Nil to represent knowledge or lack of it.

NaNs can be thought of as a mathematical nil.

The reason we have NaNs is to avoid floating point errors when dealing

with unknown values that resulted from previous operations.



We can use +NaN to replace all occurrence of 0.0 in a list to avoid a dreaded divide by zero error.



-0.999 +NAN +0.999 works very nicely in situations where a floating point error or (div x 0.0) will take the system down.



The use of NaN as a data type dates back to the first MASM and PL/M code that accessed the 8087 when Intel introduced it. At the time some said that existence of the NaN would eliminate all divide by zero exceptions in the future, it was the 80's and we had it all figured out, back then :)



Somewhere along the line the NaN became a secret weapon. Most software that exploited NaNs were/are locked deep in NDAs hiding both National and Industrial secrets and the NaN fell from grace. NaN logic is a 900 series topic that is seldom taught because for the most part it's use has been limited to stack based numerical recursion.



Base constants: true false nil NaN and mabe Pi.



Pi is righ next to NaN in the math co-processor and

is at the root of all polar mapping.



Back to my Rat Killen...
Bob the Caveguy aka Lord High Fixer.

Lutz

#3
Thanks Bob for your bits about NaN,  that was very interesting, I wonder if there is any literature you could point us too, to learn more about how to use NaN etc..



(div 1 0) => Inf  ;; hangs the Win32 version



is broken on the Win32 version. When compiled with GCC under Cygwin or Linux is gives you: 'Inf'



This 'Inf' behaves a little bit different than NaN, more like a number :) so:



(set 'x (div 1 0)) => Inf

(set 'y (div 1 0)) => Inf



(= x y) => true



but ?!?:



(+ x 1 ) => 1



But Inf is a total different animal, and at this moment I am just returning to the user, whatever the GCC libraries give me back. And as mentioned, it is broken on the Win32 version and I am not sure at this moment what we can or should do about it. Also just like with NaN 'Inf' is not a newLISP symbol, but unlike NaN, which you have to test using the NaN? newLISP function, you can test for 'Inf' using the equality operator.



But back to NaN. As you describe in your posting all arithmetik operations on NaN result in NaN and all comparisonas in 'nil' (which is also newLISP's false). I modeled this after Java's behavior, which is supposed to be pretty IEEE conformant when comes to floating point crazyness.



The message "sqrt: DOMAIN error", your are observing comes from the BORLAND C++ libraries, and is not present when compiled with GCC under Cygwin or Linux. This is why 'catch' will not work for you, because newLISP didn't observe any error.



There is surfacing all kinds of stuff over time since we have a native Win32 version of newLISP again. I.e. the 'date' function crashes with small values and sockets don't work with functions taking file handles. If you can, compile newLISP under Cygwin when on Windows and you will have more consistent behaviour to newLISP compiled inder UNIXes (UNICES).



About Pi. I just use:



(set 'Pi (mul (acos 0) 2)) => 3.41592564



at the beginning of a program, where I use Pi a lot. Interesting detail, you are mentioning, that Pi is burried in the math coprocessor, I didn't know that and guess it makes a lot of sence to build it into it.



Anyway, very welcome to our group of newLISP fans ...



Lutz

CaveGuy

#4
Pi is stored as an 80 bit float in the co-processor as a

constant. Your solution returns a 64 bit float If we stay in this solar system then polar error is not too bad :) Just Kidding.



I only need a symbol that has been set to +NAN to still

be a NAN after a save and load.

(save) saves it out as (set 'x +NaN)

(load) (sets 'x nil)



Makeing +NaN a static symbol pointing to a static NaN

would allow it to be restored.



Till later ...

Bob
Bob the Caveguy aka Lord High Fixer.

Lutz

#5
I have it working now on the cygwin/unix versions:



(set '+NaN (sqrt -1))

+NaN => +NaN



(= +NaN (sqrt -1)) => true



but still have problems on the BORLAND C++ compiled Win32, crashing

under certain cirumstances.



Lutz

Lutz

#6
NaN stuff now also working on Win32 see version 6.5.26 in:



http://newlisp.org/download/development/">//http://newlisp.org/download/development/



and the CHANGES file in the distribution



Lutz

CaveGuy

#7
newLISP v6.5.26-win32 Copyright (c) 1993-2002 Lutz Mueller. All rights reserved.



> (symbols) => no observed +NAN on the heap

> +NAN => nil

> (NaN? +NAN) => Value expected in function NaN?



; Now I force one into exsistance



> (set '+NAN (sqrt -1)) => sqrt: DOMAIN error  returns: +NAN



(symbols) => wa-la we got +NAN on the heap

; now there will be joy in mudville



> +NAN => +NAN

> (set 'q +NAN) => +NAN

> (NaN? q) => true

>



Like nil there should be only one value for +NAN

and all symbols point to it. If you save a +NAN a maie it constant, then the error does not have to occure to generate the first +NAN value to link to.



Close, real close, once "created" the new +NAN responds nicely.



Other than that, It looks great, thanks for the div by zero fix for winblows. Having forceing a +NaN as 0

in integer operations works for me nicely. I may start using it for Integer Values to be Ignored in a sequence :)



Till later ...
Bob the Caveguy aka Lord High Fixer.

Lutz

#8
At this moment there is no general mechanism in place to protect symbols from beeing changed. The mechanism used for 'nil and 'true wouldn't be suited. So at this moment constants have to be set initially and could be put into 'init.lsp' (in the start up directory of Win32 newLISP or in /usr/share/newlisp on Unix OS's).



Perhaps we will have some protection mechanism in the future or we could simply have a 'constant' primitive:



(constant '+NaN (sqrt -1))

(constant 'Pi (mul 2 (acos 0)))



etc.



Lutz

CaveGuy

#9
How about a new subber (+NaN) that performs a (sqrt -1) function internally and returns +NAN without the error.

The error is the only real problem, now.



I have not tried it as a CGI yet but I am sure it will go boom when I do ... I will give it a test late tonight.



I dont care about Pi it is easily worked around. But the

error is un-trapable.



Got to run...
Bob the Caveguy aka Lord High Fixer.

Lutz

#10
You could put:



 (define (+NaN) (sqrt -1))  ;; make new function retruning a NaN



In your initialization file (init.lsp) , or just put:



 (set '+NaN (sqrt -1))



in your initialization file.



Then after startup of newLISP +NaN will return +NaN.



Lutz



ps: just finished a new function 'constant' for protecting symbols to define constants, this will go into a new development version by the end of this week.

CaveGuy

#11
Been there done that.....



I have set up a CGI test so you can see my problem. "LSP" files are evaluated by your latest greatest, and "LISP" files are processed by the last known stable version before we started messing with it.



<center>

<A ref="http://autocode.com/run/nan-1.lsp">http://autocode.com/run/nan-1.lsp">"

http://autocode.com/run/nan-1.lsp%22%3C/a">http://autocode.com/run/nan-1.lsp"</a>



and



<A ref="http://autocode.com/run/nan-1.lisp">http://autocode.com/run/nan-1.lisp">"

http://autocode.com/run/nan-1.lisp%22%3C/a">http://autocode.com/run/nan-1.lisp"</a>



If you want/need FTP access for testing for your own, please contact me off-list.



Here are links to my first test using both.



<A ref="http://autocode.com/run/nan-test.lsp">http://autocode.com/run/nan-test.lsp">"

http://autocode.com/run/nan-test.lsp%22%3C/a">http://autocode.com/run/nan-test.lsp"</a>



and



<A ref="http://autocode.com/run/nan-test.lisp">http://autocode.com/run/nan-test.lisp">"

http://autocode.com/run/nan-test.lisp%22%3C/a">http://autocode.com/run/nan-test.lisp"</a>



Please believe me, when this works, I will provide you

examples.



Back to my Rat Killen....
Bob the Caveguy aka Lord High Fixer.

Lutz

#12
just to sum up where we are so far with NaN, and what's pending:



(1) we can now create a symbol containing the NaN value:

(set '+NaN (sqrt -1))



when doing this, the error message "sqrt: DOMAIN error" will occur only on the native Win32 version, and I have no way to suppress it (some body knows?). I guess this is a problem for you when doing CGI, where all STDOUT goes back to the client browser. Other than suggesting to use the Cygwin version on Windows, I don't have a solution at the moment. There must be a way to surpress this message. Anybody out there with Borland C++ documentation???



on Cygwin and UNIXs there is no such message.



(2)  all integer operations: + 0 / * take NaN as a zero

this seems to work on all versions.



(3) Divisions by zero cause a newLISP "Math exception" on all versions using integer operators and floating operators. This seems to work on all versions.



(4) all floating point ops: div mul add sub produce NaN when one of the arguments is NaN. This works on Cygwin and UNIX's but produces a Math exception error with 'div' on the native Win32 version.



(5) when doing

NaN? => NaN?  <407E08>



NaN? is a builtin primitive in newLISP, evaluating a primitive by itself will ebaluate to itself and print its's name and hexadecimal run address. This is intended behaviour for all builtin primitives.



To sum it up: my understanding is, that the only two things to be fixed is the (div 3.14 +NaN) bug in point (4) and surpression of the "DOMAIN error" message in Win32 in point (1), everything else is fine.



I think (4) I can do pretty quickly, for (1) I wouldn't know, how to do it, at the moment.



Lutz



PS: no rats or any other animals will be killed sqashing this bug.

CaveGuy

#13
Simple Answer: Yes and Yes :)



Please Understand the last "C" project I personaly coded was many years ago. What version of Borland

are you using I WILL locate a copy.  One workaround

that comes to mind is to force the error early.



In NewLISP internal init code. redirtect stdio to null,

do a (sqrt -1), store the return value, and put stdio

back. Now by the time it gets to me at the application level, the NAN value has already been forced and the

output suppressed :)



I have a "C" programmer in Chicago I work with, If you do not mind I will have him take a hack at the problem.



Till later

Bob
Bob the Caveguy aka Lord High Fixer.

Lutz

#14
I am using the BCC32 version 5.5.1 from Borland. It is a free compiler available on their website. I used to work with Borland C++ a long time ago, and I remember there was a way to redirect math exceptions to your own exception handler (sort of like signals in UNIX). That would be the 'right' way to do it. But any other 'hack' is welcome as long as it works :)



Lutz