From: john
Subject: Help, Java floating-point numbers...
Date: 
Message-ID: <e6001c6e.0210140330.626af27e@posting.google.com>
Hello,

I would like to use the LIJOS package in LispWorks.
LIJOS is a Lisp implementation of the Java ObjectStream, written by
Nichael Cramer and available at http://www.pointnclick.com/lijos/.
It allows reading and writing in Allegro CL of native Java types
(boolean, float, double, int, long, char etc.) and complex types
from/to a stream.

And now the questions : 

1. Is there in LispWorks any abstraction for "NaN" (Not a number - a
float constant (actually a range) representing the result of invalid
operation like "x = 0.0/0.0")
and "positive and negative infinity" (which are the result of
operations like "x = 1.0/0.0" and "x = 1.0/-0.0")?

2. Using the algorithm (from LIJOS) listed below, I get allmost
precise conversions between Java floats and Lisp floats

(defun javaEncode-float (B1 B2 B3 B4)
  (let ((retval 0))
    (cond ((= 0 B1 B2 B3 B4)
	   (setq retval 0.0))
	  ((and (= 128 B1)
		(= 0 B2 B3 B4))
	   (setq retval -0.0))
	  ((and (= 127 B1)
		(= 192 B2)
		(= 0 B3 B4))
	   (setq retval +FLOAT-NAN+))
	  ((and (= 127 B1)
		(= 128 B2)
		(= 0 B3 B4))
	   (setq retval +FLOAT-INFINITY+))
	  ((and (= 255 B1)
		(= 128 B2)
		(= 0 B3 B4))
	   (setq retval +FLOAT-NEGATIVE-INFINITY+))		
	  (t
	   (let ((sgn (ldb (byte 1 7) B1))
		 (exp (- (+ (ash (ldb (byte 7 0) B1) 1)
			    (ldb (byte 1 7) B2))
			 127))
		 (man 0))

	     (pushByteRight MAN (ldb '#.(byte 7 0) B2))
	     (pushByteRight MAN B3)
	     (pushByteRight MAN B4)

	     (setq retval (float (* (+ 1 (/ man #.(expt 2 23)))
				    (expt 2 exp)
				    )))

	     (if (< 0 sgn)
		 (setq retval (- retval))))))
    retval))
    
The parameters B1, B2, B3, B4 are the bytes from the binary
representation of the Java float values (obtained from
Float.floatToIntBits(value) which actually gives their IEEE 754
representation).
    
    
The encoding doesn't work for example in the following cases :

Java float			Lisp float
-1.0e38				-9.999999680285688E37
-0.1				-0.10000000149011612
-1.0000000000000006E-38		-1.0000000051105637E-38
1.0000000000000006E-38		1.0000000051105637E-38
0.1				0.10000000149011612
1.0E38				9.999999680285688E37

Actually I get the same results even if I don't use the described
listed,
but put the binary representation of the Java floats in FLI and read
the Lisp floats from there.

Of course the number 0.1 is precise representable in LispWorks, I just
don't know how to represent a "Java 0.1" as "LispWorks 0.1" :)

I'm not a IEEE 754 specialist and still a Lisp newbie, so suggestions
would be very helpfull.

The documentation about how Java represents floats (in IEEE 754) when
they exit
the virtual machine (for example by Serialization or Java Native
Interface) is described in
http://java.sun.com/j2se/1.4/docs/api/java/lang/Float.html#floatToRawIntBits(float)
http://java.sun.com/j2se/1.4/docs/api/java/lang/Float.html#intBitsToFloat(int)
and 
http://java.sun.com/docs/books/vmspec/2nd-edition/html/Concepts.doc.html#33377
http://java.sun.com/docs/books/vmspec/2nd-edition/html/Overview.doc.html#28147


With best regards

From: William D Clinger
Subject: Re: Help, Java floating-point numbers...
Date: 
Message-ID: <b84e9a9f.0210151333.7859edff@posting.google.com>
·········@yahoo.com (john) wrote:    
> The encoding doesn't work for example in the following cases :
> 
> Java float			Lisp float
> -1.0e38				-9.999999680285688E37
> -0.1				-0.10000000149011612
> -1.0000000000000006E-38		-1.0000000051105637E-38
> 1.0000000000000006E-38		1.0000000051105637E-38
> 0.1				0.10000000149011612
> 1.0E38				9.999999680285688E37

It looks like you are taking a Java float (IEEE single precision,
32 bits) and converting it to IEEE double precision (64 bits).
There is probably no practical way to avoid this if your Lisp system
doesn't support IEEE single precision, which is quite possible.  If
you'll tell us which Lisp system you are using, we might be able to
provide more help.

> Of course the number 0.1 is precise representable in LispWorks...

That seems unlikely to me.  I don't know anything about LispWorks,
but I do know that 0.1 is not representable in any format described
by the IEEE-754 standard for binary floating point arithmetic.

Will
From: john
Subject: Re: Help, Java floating-point numbers...
Date: 
Message-ID: <e6001c6e.0210160147.4774aadf@posting.google.com>
······@qnci.net (William D Clinger) wrote in message news:<····························@posting.google.com>...

> 
> > Of course the number 0.1 is precise representable in LispWorks...
> 
> That seems unlikely to me.  I don't know anything about LispWorks,
> but I do know that 0.1 is not representable in any format described
> by the IEEE-754 standard for binary floating point arithmetic.
> 
Thank you for the point. Now I readed a little about FP arithmetics
(the last time I had a course about it was about 10 years ago and
since then I lost the touch with that kind of questions) and
understand why 0.1 is not representable and why a single 0.1 is not
the same as a double 0.1. "95% of the folks out there are completely
clueless about floating point" - James Gosling, 1998, "May be more
than 95%?" - W. Kahan in "How Java's Floating Point Hurts Everyone
Everywhere" at www.cs.berkeley.edu/~wkahan/JAVAhurt.pdf :))). I'm
really one of them. My sentence about LispWorks and 0.1 was stupid. I
was misguided by the following in Lisp (also in Java):

CL-USER 1 > (setf x 0.1)
0.1

CL-USER 2 > x
0.1

which by the way I still don't understand. Does it mean that when I
print a number and the number is something like
0.10000000000000000000000000000000001 the printing uses only the first
15-17 numbers as significant, so that I see 0.1?


> It looks like you are taking a Java float (IEEE single precision,
> 32 bits) and converting it to IEEE double precision (64 bits).
> There is probably no practical way to avoid this if your Lisp system
> doesn't support IEEE single precision, which is quite possible.  If
> you'll tell us which Lisp system you are using, we might be able to
> provide more help.
Now I understand this :) I'm using LispWorks for Windows and would be
very glad about any further advices.

I lot of thanks to your mail!
Regards
From: Joe Marshall
Subject: Re: Help, Java floating-point numbers...
Date: 
Message-ID: <it02e9x5.fsf@ccs.neu.edu>
·········@yahoo.com (john) writes:

> CL-USER 1 > (setf x 0.1)
> 0.1
> 
> CL-USER 2 > x
> 0.1
> 
> which by the way I still don't understand. Does it mean that when I
> print a number and the number is something like
> 0.10000000000000000000000000000000001 the printing uses only the first
> 15-17 numbers as significant, so that I see 0.1?

The nearest number to .1 in double precision floating point is
exactly 7205759403792794/72057594037927936 

There are a lot of numbers near 7205759403792794/72057594037927936,
for which the number 7205759403792794/72057594037927936 will be used.
(for instance, 
   0.10000000000000000555111512312578d0
   0.09999999999999999903141590101011d0
   etc.)

There is no *mathematical* reason to choose between between these
various decimal numbers when printing ---  they will all be
interpreted by the reader as  7205759403792794/72057594037927936.
However, out of all the equivalent decimal expansions, the string
"0.1" is the shortest.  The printer chooses the shortest string it can
provided that the exact same floating point number will be
reconstructed upon reading.
From: john
Subject: Re: Help, Java floating-point numbers...
Date: 
Message-ID: <e6001c6e.0210170834.2b2fc636@posting.google.com>
A lot of thanks to all of you!

With best regards
From: Will Deakin
Subject: Re: Help, Java floating-point numbers...
Date: 
Message-ID: <aojeqo$mg5$1@newsreaderg1.core.theplanet.net>
john wrote:
> which by the way I still don't understand. Does it mean that when I
> print a number and the number is something like
> 0.10000000000000000000000000000000001 the printing uses only the first
> 15-17 numbers as significant, so that I see 0.1?
Yes. Or at least that is my understanding of what is happening. There 
are (aging) OS's -- an IBM IIRC -- that were in base 10. But this cost 
a lot of silicon in comparison to binary.

;)w
From: Daniel Martin
Subject: decimal floating point (was: Help, Java floating-point numbers...)
Date: 
Message-ID: <f05a0fe7.0210160752.7fbff3e4@posting.google.com>
Will Deakin <···········@hotmail.com> wrote in message news:<············@newsreaderg1.core.theplanet.net>...
> Yes. Or at least that is my understanding of what is happening. There 
> are (aging) OS's -- an IBM IIRC -- that were in base 10. But this cost 
> a lot of silicon in comparison to binary.

FWIW, Oracle (and possibly other SQL vendors) do this still; the space
is cheap next to the cost of a customer asking you why a value that
should be 3.45 instead is given as 3.444444444444487.

Keep in mind, though, that an SQL vendor generally has different goals
than someone wanting to use floating point representations for heavy
calculation, and it makes sense to be more concerned about the human
input in decimal -> computer storage -> human-readable decimal output
round trip than about storage space or cpu efficiency.
From: Adam Warner
Subject: Re: Help, Java floating-point numbers...
Date: 
Message-ID: <pan.2002.10.16.13.24.49.294940@consulting.net.nz>
Hi john,

> CL-USER 1 > (setf x 0.1)
> 0.1
> 
> CL-USER 2 > x
> 0.1
> 
> which by the way I still don't understand. Does it mean that when I
> print a number and the number is something like
> 0.10000000000000000000000000000000001 the printing uses only the first
> 15-17 numbers as significant, so that I see 0.1?

Yes, but the default precision may be truly horrifying. Just truncate a
float (e.g. 1.1) to see how much error is involved:

(truncate 1.1)

1
0.100000024

The default floats only appear to have about eight significant figures of
accuracy. We can confirm they are single precision floats (in CLISP and
CMUCL):

[9]> (type-of (second (multiple-value-list (truncate 1.1))))
single-float

As a consequence, if you enter a float with greater than 8 significant
figures the rest of the information is thrown away...

(truncate 1.00000001)
1 ;
0.0

...unless you use the correct notation (in this example a long float):

[1]> (truncate 1.00000001L0)
1 ;
1.0000000000049032167L-8

Which results in an impressively small error:

(format t "~,25F" 1.0000000000049032167L-8)
0.0000000100000000000490322

But to blow your mind (CLISP has arbitrary precision floats):

[6]> (setf (ext:long-float-digits) 3322)
3322
[7]> (truncate 1.00000001L0)
1 ;
9.9999999999999999999999999999999999999999999999999999999999999999999999999
999999999999999999999999999999999999999999999999999999999999999999999999999
999999999999999999999999999999999999999999999999999999999999999999999999999
999999999999999999999999999999999999999999999999999999999999999999999999999
999999999999999999999999999999999999999999999999999999999999999999999999999
999999999999999999999999999999999999999999999999999999999999999999999999999
999999999999999999999999999999999999999999999999999999999999999999999999999
999999999999999999999999999999999999999999999999999999999999999999999999999
999999999999999999999999999999999999999999999999999999999999999999999999999
999999999999999999999999999999999999999999999999999999999999999999999999999
999999999999999999999999999999999999999999999999999999999999999999999999999
999999999999999999999999999999999999999999999999999999999999999999999999999
999999999999999999999999999999999999999999999999999999999999999999999999999
9999999999999999999927095305L-9

Now that's precision.

http://clisp.sourceforge.net/impnotes/num-concepts.html

   It can be set by (SETF (EXT:LONG-FLOAT-DIGITS) n), where n is a
   positive integer.  E.g., (SETF (EXT:LONG-FLOAT-DIGITS) 3322) sets the
   default precision of long floats to about 1000 decimal digits.

Regards,
Adam
From: Nils Goesche
Subject: Re: Help, Java floating-point numbers...
Date: 
Message-ID: <lk3cr64g4i.fsf@pc022.bln.elmeg.de>
"Adam Warner" <······@consulting.net.nz> writes:

> [9]> (type-of (second (multiple-value-list (truncate 1.1))))
> single-float

You might want to have a look at NTH-VALUE.

Regards,
-- 
Nils Goesche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x0655CFA0
From: Adam Warner
Subject: Re: Help, Java floating-point numbers...
Date: 
Message-ID: <pan.2002.10.16.13.34.52.22257@consulting.net.nz>
BTW,

> But to blow your mind (CLISP has arbitrary precision floats):
> 
> [6]> (setf (ext:long-float-digits) 3322)
> 3322
> [7]> (truncate 1.00000001L0)

Adam's guide to calculating PI to around 100,000 decimal places:

1. Enter (setf (ext:long-float-digits) 332200)
2. Type pi.

:-)

Regards,
Adam