Greetings, and thanks again for pointing this out.  Implementation
pushed to master:

=============================================================================
(declaim (inline fryi))
(defun fryi (x a)
  (labels ((fryn (x a) (abs (- (* x (denominator a)) (numerator a))))
           (fryk (x a b &aux (c (fryn x a))(d (fryn x b))
                    (kf 0.8);heuristic guard against overshoot
                    (cf (* c kf))(df (* d kf)))
             (cond ((> cf d 0) (values (truncate (/ cf d))))
                   ((> df c 0) (values (truncate (/ df c))))
                   (1)))
           (med (a b k)
             (/ (+ (numerator a)   (* k (numerator b)))
                (+ (denominator a) (* k (denominator b)))))
           (fry (x a b)
             (cond ((= (float a x) x) a)
                   ((= (float b x) x) b)
                   ((< (med a b 1) x) (fry x (med a b (fryk x a b)) b))
                   ((fry x a (med b a (fryk x a b)))))))
    (fry x a (1+ a))))


(defun rationalize (x)
  (declare (optimize (safety 1)))
  (check-type x real)
  (typecase x
    (rational x)
    (float
     (if (isnan x)
         (rational x)
         (multiple-value-bind
               (f r) (truncate x)
           (cond ((minusp r) (fryi x (1- f)))
                 ((zerop r) f)
                 ((fryi x f))))))))
=============================================================================

Take care,

Matt Kaufmann <kaufm...@cs.utexas.edu> writes:

> Hi Camm,
>
> Thanks for your persistence in getting GCL 2.7 ready!
>
> One thing I noticed about floating-point computations in GCL -- both
> 2.6.15pre and 2.7.0, both CLtL1 and ANSI -- is that rationalize
> appears to be the same as rational, at least on input (float 1/3
> 0.0d0).
>
>>(rationalize (float 1/3 0.0d0))
>
> 6004799503160661/18014398509481984
>
>>
>
> I don't think that's an error, but it's maybe not what one would
> expect of rationalize, as (rationalize (float 1/3 0.0d0)) evaluates to
> 1/3 in all the other Lisps I checked (CCL, SBCL, LispWorks, CMUCL, and
> ALlegro CL).
>
> -- Matt
> Camm Maguire <c...@maguirefamily.org> writes:
>
>> Greetings!  I just thought I'd post on the resolution of this old
>> thread.
>>
>> In summary, GCL 2.7.0 chose option 1) as previously described, namely
>> NaNs are floats and do not trigger errors unless trapping is explicitly
>> set. For posterity, option 2) was unworkable as if NaNs were not floats
>> and not numbers, one could not get them to traverse the typecases
>> correctly when one wished to disable the error.
>>
>> (/= x x) and the like will be optimized away if and only if the compiler
>> can determine the value is not a NaN, see below.  This is identical
>> behavior for gcc.
>>
>> I had to rework the type system a bit to accommodate unordered floats.  In
>> sum, (or (long-float 0) (long-float * 0)) is a subtype of, but not equal
>> to, long-float.  As NaNs were not envisioned in the spec (apparently),
>> I've taken the liberty of defining (long-float si::unordered) to refer
>> to the and of the latter and the not of the former.  The interested soul
>> can experiment with NaNs in types passed to 'si::resolve-type to their
>> heart's content to see how this works out.
>>
>> This was the last obstacle for GCL 2.7.0 release.  AFAICS GCL master
>> supports current master of ACL2, maxima, axiom, fricas, and hol88 and is
>> ready for release.  If anyone has any extremely minor suggestions in the
>> next week or so please send them my way.  No unicode changes made it
>> into this release.
>>
>> If anyone has access to gcc-15, it would be helpful if they could
>> confirm that GCL master builds with -std=gnu17 passed to CFLAGS.  I do
>> not yet have access to this compiler for testing, but it is coming and it 
>> would be
>> great if GCL worked out of the box.
>>
>> Separately there are some improvements to the maxima build procedure
>> available via the new function si::do-recomp to avoid recompiling the
>> whole tree twice.  I will try to commit a patch soon.
>>
>> Take care,
>>
>> =============================================================================
>> (disassemble '(lambda (x y) (declare ((float 0 ) x y)) (/= x x)))
>>
>> ;; Compiling /tmp/gazonk_890403_0.lsp.
>> ;; When compiling (DEFUN CMP-ANON)
>> INTERNAL-SIMPLE-STYLE-WARNING: The variable Y is not used.
>> ;; End of Pass 1.
>> ;; End of Pass 2.
>> OPTIMIZE levels: Safety=0 (No runtime error checking), Space=0, Speed=3
>> ;; Finished compiling /tmp/gazonk_890403_0.o.
>>
>> #include "gazonk_890403_0.h"
>> void init_code(){do_init((void *)VV);}
>> /*   local entry for function COMPILER::CMP-ANON     */
>>
>> static object LI1__CMP_ANON___gazonk_890403_0(object V3,object V4)
>> {     VMB1 VMS1 VMV1
>>      {object V5 = Cnil;
>>      VMR1(V5);}
>> }
>> (1 (MAPC 'EVAL *COMPILER-COMPILE-DATA*))
>> static object LI1__CMP_ANON___gazonk_890403_0(object V3,object V4)
>> ;
>> #define VMB1
>> #define VMS1
>> #define VMV1
>> #define VMRV1(a_,b_) return((object )a_);
>> #define VMR1(a_) VMRV1(a_,0);
>> #define VM1 0
>> static void * VVi[1]={
>> #define Cdata VV[0]
>> (void *)(LI1__CMP_ANON___gazonk_890403_0)
>> };
>> #define VV (VVi)
>> NIL
>>
>> COMPILER>(disassemble '(lambda (x y) (declare ((float  ) x y)) (/= x x)))
>>
>> ;; Compiling /tmp/gazonk_890403_0.lsp.
>> ;; When compiling (DEFUN CMP-ANON)
>> INTERNAL-SIMPLE-STYLE-WARNING: The variable Y is not used.
>> ;; End of Pass 1.
>> ;; End of Pass 2.
>> OPTIMIZE levels: Safety=0 (No runtime error checking), Space=0, Speed=3
>> ;; Finished compiling /tmp/gazonk_890403_0.o.
>>
>> #include "gazonk_890403_0.h"
>> void init_code(){do_init((void *)VV);}
>> /*   local entry for function COMPILER::CMP-ANON     */
>>
>> static object LI1__CMP_ANON___gazonk_890403_0(object V3,object V4)
>> {     VMB1 VMS1 VMV1
>>      {object V5 = (immnum_ne((V3),(V3))?Ct:Cnil);
>>      VMR1(V5);}
>> }
>> (1 (MAPC 'EVAL *COMPILER-COMPILE-DATA*))
>> static object LI1__CMP_ANON___gazonk_890403_0(object V3,object V4)
>> ;
>> #define VMB1
>> #define VMS1
>> #define VMV1
>> #define VMRV1(a_,b_) return((object )a_);
>> #define VMR1(a_) VMRV1(a_,0);
>> #define VM1 0
>> static void * VVi[1]={
>> #define Cdata VV[0]
>> (void *)(LI1__CMP_ANON___gazonk_890403_0)
>> };
>> #define VV (VVi)
>> NIL
>>
>> COMPILER>(disassemble '(lambda (x y) (declare ((short-float  ) x y)) (/= x 
>> x)))
>>
>> ;; Compiling /tmp/gazonk_890403_0.lsp.
>> ;; When compiling (DEFUN CMP-ANON)
>> INTERNAL-SIMPLE-STYLE-WARNING: The variable Y is not used.
>> ;; End of Pass 1.
>> ;; End of Pass 2.
>> OPTIMIZE levels: Safety=0 (No runtime error checking), Space=0, Speed=3
>> ;; Finished compiling /tmp/gazonk_890403_0.o.
>>
>> #include "gazonk_890403_0.h"
>> void init_code(){do_init((void *)VV);}
>> /*   local entry for function COMPILER::CMP-ANON     */
>>
>> static object LI1__CMP_ANON___gazonk_890403_0(object V3,object V4)
>> {     VMB1 VMS1 VMV1
>>      {object V5 = ((sf(V3))!=(sf(V3))?Ct:Cnil);
>>      VMR1(V5);}
>> }
>> (1 (MAPC 'EVAL *COMPILER-COMPILE-DATA*))
>> static object LI1__CMP_ANON___gazonk_890403_0(object V3,object V4)
>> ;
>> #define VMB1
>> #define VMS1
>> #define VMV1
>> #define VMRV1(a_,b_) return((object )a_);
>> #define VMR1(a_) VMRV1(a_,0);
>> #define VM1 0
>> static void * VVi[1]={
>> #define Cdata VV[0]
>> (void *)(LI1__CMP_ANON___gazonk_890403_0)
>> };
>> #define VV (VVi)
>> NIL
>>
>> COMPILER>=============================================================================
>>
>>
>> Camm Maguire <c...@maguirefamily.org> writes:
>>
>>> Greetings!
>>>
>>> Matt Kaufmann <kaufm...@cs.utexas.edu> writes:
>>>
>>>> Hi Camm,
>>>>
>>>> Excellent.  ACL2 will evaluate the following at start-up.
>>>>
>>>> (fpe:break-on-floating-point-exceptions
>>>>  :floating-point-overflow t
>>>>  :division-by-zero t ; not sure this is actually needed
>>>>  :floating-point-invalid-operation t)
>>>>
>>>
>>> Sounds good, but you might want to consider adding the other two with a
>>> setting of nil so your behavior is immune to GCL changes in its default
>>> configuration.  I don't plan on enabling traps by default at the moment
>>> as it appears controversial, but that could change.
>>>
>>>
>>>> That said, consider the following from the Common Lisp Hyperspec,
>>>> Section 12.1.4.4 (Rule of Float Precision Contagion).
>>>>
>>>>    The result of a numerical function is a float of the largest format
>>>>    among all the floating-point arguments to the function.
>>>>
>>>> This seems to argue for proposal 1), since when a NaN results from the
>>>> application of a numerical function to double-float arguments, that
>>>> NaN would apparently need to be of type double-float.
>>>
>>> Yeah, I think 1) is the way to go for now, but the reading of this
>>> section depends to my mind on whether NaN is a valid return, in which
>>> case it is a number/float/long-float, or an error indicator, which can
>>> be trapped or not.  Conceptually you might as well replace the NaN with
>>> a common-lisp condition akin to
>>>
>>>
>>>>(arithmetic-error-operands (make-condition 
>>>>'floating-point-invalid-operation :operands (list compiler::nan 1.0)))
>>>
>>> (#<nan> 1.0)
>>>
>>> and return this when not trapping, but defining some additional cell
>>> containing the NaN result for use in subsequent processing.  The chief
>>> argument against this appears to be performance.
>>>
>>> Take care,
>>
>> --
>> Camm Maguire                                     c...@maguirefamily.org
>> ==========================================================================
>> "The earth is but one country, and mankind its citizens."  --  Baha'u'llah
>
>
>

-- 
Camm Maguire                                        c...@maguirefamily.org
==========================================================================
"The earth is but one country, and mankind its citizens."  --  Baha'u'llah

Reply via email to