Re: pi seems not to be a constant
"Pascal J. Bourguignon" <[email protected]>
| Newsgroups | gmane.lisp.clisp.general |
|---|---|
| Organization | Informatimago |
| Message-ID | <[email protected]> |
On 20/10/15 21:29, Don Cohen wrote:
> > If long-float-digits is changed and the "constants" are not adjusted
> > then STANDARD PORTABLE CL code will break.
>
> This is incomplete:
>
> Not only the constants should be adjusted, but all the standard
> portable CL code that has been compiled so far needs to be compiled
> again, because defconstant constants can be inlined.
>
> This is to avoid having to recompile and reload everything each time
> you set ext:long-float-digits, that cl:pi is not a constant.
>
> If I understand correctly, you are saying that
> *If* pi, etc. were declared defconstant and changing precision changed
> it, then everything using pi would have to be recompiled.
> And depending on what you think it means to change precision, you
> might also want to reread and recompile all the code containing long
> constants.
>
> I think you agree with me that it's a bad idea to change the values of
> things that are declared defconstant.
Yes. Or to declare with defconstant variables that can change.
Also, remember that defconstant defines constant VARIABLES.
> I can't tell whether you think pi should not be defconstant because of
> this, or whether you agree with me that it should be declared
> defconstant and then not changed.
Read again the discussion.
The current state is not conforming but it's better than a conforming
solution that would have to be much more complex.
> This doesn't solve the larger problem of constants in code.
> You probably don't want to replace 1l0 in your code with
> (read-from-string "1l0"), at leat if that code is to run many times.
> It's possible to write a macro (adjust-precision "1l0") that generates
> code that checks whether precision has been changed since it was last
> run (I hope that's cheap) and if so rereads the constant. It could
> even keep a cache of values of different precisions.
1L0 is always 1L0, whatever the long-float-digits.
1234567890123456789012345678901234567890123456789012345678901234567890L0
may be read as different values when read with a different
long-float-digits, but this remains conforming, since this is a behavior
that already exists for the other floating point types and on all the
implementations, and since the application knows when it changes the
long-float-digits, so it may decide what to do about it.
In any case, the point is that in both cases, the precision of the
concerned number is finite.
On the other hand, for π or e, the precision is infinite. Therefore
when you change long-float-digit, the long float value that should
represent π or e (or any of the other transcendental numbers), is not
the same anymore.
Again, in the case of e or other values, the implementation can deal
with it, since it knows that it changed long-float-digits, it can
re-compute a new approximation of its trancendantals with the new precision.
But the standard has a defect, in that it specifies PI to be a constant
variable instead of being a function.
For a strict pedantic conformity, this means you would have to keep the
precision of long-float fixed, and we'd have to provide a fifth subtype
of long-float for variable precision. This would lead to complexities
(and problems of conformity with programs that don't expect a fifth
subtype of float!).
Therefore it's better to make CL:PI a non constant variable, and to
rebind it when we change the precision.
We could also provide functions in EXT to provide values of
transcendantals such as PI and E at the current or other precisions.
> While we're at it, I suggest that it would be a lot more convenient
> to programmatically control precision if there were a function to
> read long floats of precision n, e.g., (read-long "1l0" n), which
> returns the rough equivalent (I hope much more efficiently) of
> (let ((p (ext:long-float-digits)))
> (setf (ext:long-float-digits) n)
> (prog1 (read-from-string "1l0") (setf (ext:long-float-digits) p)))
There it is:
(defun read-long (string n)
(let ((p (ext:long-float-digits)))
(setf (ext:long-float-digits) n)
(prog1 (read-from-string "1l0") (setf (ext:long-float-digits) p))))
> It would also be nice if different threads could work in different
> default precisions. For this purpose it seems better to make
> long-float-digits a regular special variable that can be rebound
> by any code and only affect the reads that are done with that binding.
> Of course, I don't propose that pi be changed or even rebound when
> long-float-digits is rebound. But the rebinding will affect the value
> of (pi).
The binding of cl:pi could be thread-local.
> So now I'm proposing somewhat larger changes, but I think they
> make the resulting system quite a bit more useful.
> The underlying clisp seems perfectly well adapted to using different
> precisions under program control, but this facility is made
> unnecessarily inconvenient to use, in my opinion, by the current
> mechanism of (setf long-float-digits) and its adjustments, along with
> the lack of the read-long function and the functions like
> (pi &optional precision).
Notice that if you set long-float-digits, and save a bunch of long-float
values computed with that precision, then you change long-float-digits,
and use the saved values to further compute, then the resulting
long-float will have the original precision. Therefore you can already
have threads performing computations with different long-float
precisions! (only take care of not reading new long floats or not using
cl:pi or otherwise poluting your computing with long-float of a
different precision).
--
__Pascal J. Bourguignon__
http://www.informatimago.com/
------------------------------------------------------------------------------
_______________________________________________
clisp-list mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/clisp-list