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 <[email protected]> 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 <[email protected]> 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 <[email protected]> writes:
>>
>>> Greetings!
>>>
>>> Matt Kaufmann <[email protected]> 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 [email protected]
>> ==========================================================================
>> "The earth is but one country, and mankind its citizens." -- Baha'u'llah
>
>
>
--
Camm Maguire [email protected]
==========================================================================
"The earth is but one country, and mankind its citizens." -- Baha'u'llah