|
From: Barton W. <wi...@un...> - 2025-12-04 13:23:14
|
The file globals.lisp defines 1//2 as ((rat simp) 1 2). However, when I run the testsuite, I find that 1//2 is sometimes equal to a bigfloat 1/2. Specifically, out of 59,014 calls to the function absarg, 13,691 times 1//2 is a bigfloat half. I noticed this when I saw that rpart.lisp defines a macro half that returns 1/2. This macro was introduced eight years ago by Andreas Eder with the following commit message: backed out the change that necessitated to relax the rel-error bounds for the erf inverse_erf tests at +/- 2b0 and +/-2b0+/-2b0%i in rtest_gamma.mac. The problem arises in the function absarg in rpart.lisp. Reintroduced the half macro again for this use. It should make no difference, but the code at this point seems to be a bit subtle :-) Anyway, whith the old half macro instead of the variable 1//2 the test results are unchanged. I suspect the subtle problem is that something is converting 1//2 into a bigfloat 1/2 (with various values of fpprec). There are hundreds of uses of 1//2 in the Maxima code. Changing the value of 1//2 is surely a bug. Guess: Fixing this bug will cause at least a handful of testsuite cases to fail. --Barton |
|
From: Barton W. <wi...@un...> - 2025-12-04 13:43:14
|
OK, maybe I found the culprit:
(defun bfloat-erf (z)
;; Warning! This has round-off problems when abs(z) is very small.
(let ((1//2 ($bfloat '((rat simp) 1 2))))
;; The argument is real, the result is real too
($realpart
(mul
(simplify (list '(%signum) z))
(sub 1
(mul
(div 1 (power ($bfloat '$%pi) 1//2))
(bfloat-gamma-incomplete 1//2 ($bfloat (power z 2)))))))))
And similarly for complex-bfloat-erf . Changing 1//2 to bfhalf in this code didn't result in any testsuite failures, but I have a few pending changes to the function absarg.
Also, loading gamma.lisp gives the warning: (SBCL)
in: DEFUN GAMMA-INCOMPLETE
; (COND ((COMPLEXP MAXIMA::X) #C(0.0d0 0.0d0)) ((REALP MAXIMA::X) 0.0d0))
; --> IF
; ==>
; NIL
;
; caught STYLE-WARNING:
; This is not a NUMBER:
; NIL
; See also:
; The SBCL Manual, Node "Handling of Types"
I think this should be fixed.
________________________________
From: Barton Willis via Maxima-discuss <max...@li...>
Sent: Thursday, December 4, 2025 7:08 AM
To: <max...@li...> <max...@li...>
Subject: [Maxima-discuss] sometimes 1//2 =/= 1/2
Caution: Non-NU Email
The file globals.lisp defines 1//2 as ((rat simp) 1 2). However, when I run the testsuite, I find that 1//2 is sometimes equal to a bigfloat 1/2.
Specifically, out of 59,014 calls to the function absarg, 13,691 times 1//2 is a bigfloat half.
I noticed this when I saw that rpart.lisp defines a macro half that returns 1/2. This macro was introduced eight years ago by Andreas Eder with the following commit message:
backed out the change that necessitated to relax the rel-error bounds
for the erf inverse_erf tests at +/- 2b0 and +/-2b0+/-2b0%i in rtest_gamma.mac.
The problem arises in the function absarg in rpart.lisp. Reintroduced
the half macro again for this use. It should make no difference, but the
code at this point seems to be a bit subtle :-)
Anyway, whith the old half macro instead of the variable 1//2 the test
results are unchanged.
I suspect the subtle problem is that something is converting 1//2 into a bigfloat 1/2 (with various values of fpprec).
There are hundreds of uses of 1//2 in the Maxima code. Changing the value of 1//2 is surely a bug.
Guess: Fixing this bug will cause at least a handful of testsuite cases to fail.
--Barton
|
|
From: Raymond T. <toy...@gm...> - 2025-12-04 16:28:33
|
On 12/4/25 5:43 AM, Barton Willis via Maxima-discuss wrote: > OK, maybe I found the culprit: > > (defun bfloat-erf (z) > ;; Warning! This has round-off problems when abs(z) is very small. > (let ((1//2 ($bfloat '((rat simp) 1 2)))) > ;; The argument is real, the result is real too > ($realpart > (mul > (simplify (list '(%signum) z)) > (sub 1 > (mul > (div 1 (power ($bfloat '$%pi) 1//2)) > (bfloat-gamma-incomplete 1//2 ($bfloat (power z 2))))))))) > > > > And similarly for |complex-bfloat-erf| . Changing 1//2 to bfhalf in > this code didn't result in any testsuite failures, but I have a few > pending changes to the function |absarg.| Nice bit of detective work! Yeah, renaming 1//2 to something else should take care of the problem. > > |Also, loading gamma.lisp gives the warning: (SBCL)| > > in: DEFUN GAMMA-INCOMPLETE > ; (COND ((COMPLEXP MAXIMA::X) #C(0.0d0 0.0d0)) ((REALP MAXIMA::X) > 0.0d0)) I think there are lots of these. The issue here is that the compiler doesn't know what X is, so the |cond| cases of |complexp| and |realp| covers the case of numbers, but there are lots of other types which aren't covered. This can be fixed in two ways. Add |(declare (number x))|. Add a |T| clause to |cond|. This should probably signal an error. Or maybe even replace the |cond| with |etypecase|? ​ |
|
From: Barton W. <wi...@un...> - 2025-12-04 16:51:17
|
I have tested changing (let ((1//2 ... to (let ((bfhalf .... It fixes the trouble and eliminates the need for the macro half that is used in absarg. I hope to commit this fix along with a few others in a few weeks.
________________________________
From: Raymond Toy <toy...@gm...>
Sent: Thursday, December 4, 2025 10:28 AM
To: max...@li... <max...@li...>
Subject: Re: [Maxima-discuss] sometimes 1//2 =/= 1/2
Caution: Non-NU Email
On 12/4/25 5:43 AM, Barton Willis via Maxima-discuss wrote:
OK, maybe I found the culprit:
(defun bfloat-erf (z)
;; Warning! This has round-off problems when abs(z) is very small.
(let ((1//2 ($bfloat '((rat simp) 1 2))))
;; The argument is real, the result is real too
($realpart
(mul
(simplify (list '(%signum) z))
(sub 1
(mul
(div 1 (power ($bfloat '$%pi) 1//2))
(bfloat-gamma-incomplete 1//2 ($bfloat (power z 2)))))))))
And similarly for complex-bfloat-erf . Changing 1//2 to bfhalf in this code didn't result in any testsuite failures, but I have a few pending changes to the function absarg.
Nice bit of detective work! Yeah, renaming 1//2 to something else should take care of the problem.
Also, loading gamma.lisp gives the warning: (SBCL)
in: DEFUN GAMMA-INCOMPLETE
; (COND ((COMPLEXP MAXIMA::X) #C(0.0d0 0.0d0)) ((REALP MAXIMA::X) 0.0d0))
I think there are lots of these.
The issue here is that the compiler doesn't know what X is, so the cond cases of complexp and realp covers the case of numbers, but there are lots of other types which aren't covered.
This can be fixed in two ways. Add (declare (number x)). Add a T clause to cond. This should probably signal an error.
Or maybe even replace the cond with etypecase?
​
|
|
From: Raymond T. <toy...@gm...> - 2025-12-04 23:44:38
|
On 12/4/25 8:51 AM, Barton Willis wrote: > I have tested changing (let ((1//2 ... to (let ((bfhalf .... It fixes > the trouble and eliminates the need for the macro half that is used in > absarg. I hope to commit this fix along with a few others in a few > weeks. Hmm. float.lisp defines |bfhalf| spec var. And it's value is updated whenever fpprec1 is called. Maybe you don't need that at all. And we should probably rename |bfhalf| to |*bfhalf*| along with the other spec vars updated in fpprec1. And rename |1//2| to |*1/2*|. Or make |1//2| a |defconstant|. But sbcl is really picky about what can be a |defconstant|. > > > ------------------------------------------------------------------------ > *From:* Raymond Toy <toy...@gm...> > *Sent:* Thursday, December 4, 2025 10:28 AM > *To:* max...@li... > <max...@li...> > *Subject:* Re: [Maxima-discuss] sometimes 1//2 =/= 1/2 > > > Caution: Non-NU Email > > > On 12/4/25 5:43 AM, Barton Willis via Maxima-discuss wrote: > >> OK, maybe I found the culprit: >> >> (defun bfloat-erf (z) >> ;; Warning! This has round-off problems when abs(z) is very small. >> (let ((1//2 ($bfloat '((rat simp) 1 2)))) >> ;; The argument is real, the result is real too >> ($realpart >> (mul >> (simplify (list '(%signum) z)) >> (sub 1 >> (mul >> (div 1 (power ($bfloat '$%pi) 1//2)) >> (bfloat-gamma-incomplete 1//2 ($bfloat (power z 2))))))))) >> >> >> >> And similarly for |complex-bfloat-erf| . Changing 1//2 to bfhalf in >> this code didn't result in any testsuite failures, but I have a few >> pending changes to the function |absarg.| > Nice bit of detective work! Yeah, renaming 1//2 to something else > should take care of the problem. >> >> |Also, loading gamma.lisp gives the warning: (SBCL)| >> >> in: DEFUN GAMMA-INCOMPLETE >> ; (COND ((COMPLEXP MAXIMA::X) #C(0.0d0 0.0d0)) ((REALP MAXIMA::X) >> 0.0d0)) > > I think there are lots of these. > > The issue here is that the compiler doesn't know what X is, so the > |cond| cases of |complexp| and |realp| covers the case of numbers, but > there are lots of other types which aren't covered. > > This can be fixed in two ways. Add |(declare (number x))|. Add a |T| > clause to |cond|. This should probably signal an error. > > Or maybe even replace the |cond| with |etypecase|? > > ​ ​ |
|
From: Barton W. <wi...@un...> - 2025-12-05 12:55:25
|
Another thing: Although bfhalf automatically updates when fpprec changes, some special variables defined in globals.lisp do not. Examples:
(%i1) :lisp(print bigfloat%pi)
((BIGFLOAT SIMP 56) 56593902016227522 2)
((BIGFLOAT SIMP 56) 56593902016227522 2)
(%i1) fpprec : 57$
(%i2) :lisp(print bigfloat%pi)
((BIGFLOAT SIMP 56) 56593902016227522 2)
((BIGFLOAT SIMP 56) 56593902016227522 2)
________________________________
From: Raymond Toy <toy...@gm...>
Sent: Thursday, December 4, 2025 5:44 PM
To: Barton Willis <wi...@un...>; max...@li... <max...@li...>
Subject: Re: [Maxima-discuss] sometimes 1//2 =/= 1/2
Caution: Non-NU Email
On 12/4/25 8:51 AM, Barton Willis wrote:
I have tested changing (let ((1//2 ... to (let ((bfhalf .... It fixes the trouble and eliminates the need for the macro half that is used in absarg. I hope to commit this fix along with a few others in a few weeks.
Hmm. float.lisp defines bfhalf spec var. And it's value is updated whenever fpprec1 is called. Maybe you don't need that at all.
And we should probably rename bfhalf to *bfhalf* along with the other spec vars updated in fpprec1. And rename 1//2 to *1/2*. Or make 1//2 a defconstant. But sbcl is really picky about what can be a defconstant.
________________________________
From: Raymond Toy <toy...@gm...><mailto:toy...@gm...>
Sent: Thursday, December 4, 2025 10:28 AM
To: max...@li...<mailto:max...@li...> <max...@li...><mailto:max...@li...>
Subject: Re: [Maxima-discuss] sometimes 1//2 =/= 1/2
Caution: Non-NU Email
On 12/4/25 5:43 AM, Barton Willis via Maxima-discuss wrote:
OK, maybe I found the culprit:
(defun bfloat-erf (z)
;; Warning! This has round-off problems when abs(z) is very small.
(let ((1//2 ($bfloat '((rat simp) 1 2))))
;; The argument is real, the result is real too
($realpart
(mul
(simplify (list '(%signum) z))
(sub 1
(mul
(div 1 (power ($bfloat '$%pi) 1//2))
(bfloat-gamma-incomplete 1//2 ($bfloat (power z 2)))))))))
And similarly for complex-bfloat-erf . Changing 1//2 to bfhalf in this code didn't result in any testsuite failures, but I have a few pending changes to the function absarg.
Nice bit of detective work! Yeah, renaming 1//2 to something else should take care of the problem.
Also, loading gamma.lisp gives the warning: (SBCL)
in: DEFUN GAMMA-INCOMPLETE
; (COND ((COMPLEXP MAXIMA::X) #C(0.0d0 0.0d0)) ((REALP MAXIMA::X) 0.0d0))
I think there are lots of these.
The issue here is that the compiler doesn't know what X is, so the cond cases of complexp and realp covers the case of numbers, but there are lots of other types which aren't covered.
This can be fixed in two ways. Add (declare (number x)). Add a T clause to cond. This should probably signal an error.
Or maybe even replace the cond with etypecase?
​
​
|
|
From: Raymond T. <toy...@gm...> - 2025-12-05 14:47:06
|
On 12/5/25 4:55 AM, Barton Willis wrote: > Another thing: Although |bfhalf| automatically updates when |fpprec > |changes, some special variables defined in |globals.lisp| do not. > Examples: > > (%i1) :lisp(print bigfloat%pi) > > ((BIGFLOAT SIMP 56) 56593902016227522 2) > ((BIGFLOAT SIMP 56) 56593902016227522 2) > > (%i1) fpprec : 57$ > > (%i2) :lisp(print bigfloat%pi) > > ((BIGFLOAT SIMP 56) 56593902016227522 2) > ((BIGFLOAT SIMP 56) 56593902016227522 2) Yeah, this is confusing. I'm not sure what should happen here. But AFAICT, |bigfloat%pi| is only used in gamma.lisp, and it recomputes a value via |($bfloat '$%pi)|. Fortunately, that will use a memoized value if available. Updating these constants when changing fpprec is potentially very expensive since computing pi, e, gamma, and log2 can be rather expensive, even if they are memoized. On the other hand, the uses of pi, e, and gamma are always recomputed as needed so these special variables can probably be removed (for the best!). And |bigfloat_log2| doesn't seem to be used anywhere. I'll file a bug on this. > ------------------------------------------------------------------------ > *From:* Raymond Toy <toy...@gm...> > *Sent:* Thursday, December 4, 2025 5:44 PM > *To:* Barton Willis <wi...@un...>; > max...@li... > <max...@li...> > *Subject:* Re: [Maxima-discuss] sometimes 1//2 =/= 1/2 > > > Caution: Non-NU Email > > > On 12/4/25 8:51 AM, Barton Willis wrote: > >> I have tested changing (let ((1//2 ... to (let ((bfhalf .... It >> fixes the trouble and eliminates the need for the macro half that is >> used in absarg. I hope to commit this fix along with a few others >> in a few weeks. > > Hmm. float.lisp defines |bfhalf| spec var. And it's value is updated > whenever fpprec1 is called. Maybe you don't need that at all. > > And we should probably rename |bfhalf| to |*bfhalf*| along with the > other spec vars updated in fpprec1. And rename |1//2| to |*1/2*|. Or > make |1//2| a |defconstant|. But sbcl is really picky about what can > be a |defconstant|. > >> >> >> ------------------------------------------------------------------------ >> *From:* Raymond Toy <toy...@gm...> >> <mailto:toy...@gm...> >> *Sent:* Thursday, December 4, 2025 10:28 AM >> *To:* max...@li... >> <mailto:max...@li...> >> <max...@li...> >> <mailto:max...@li...> >> *Subject:* Re: [Maxima-discuss] sometimes 1//2 =/= 1/2 >> >> >> Caution: Non-NU Email >> >> >> On 12/4/25 5:43 AM, Barton Willis via Maxima-discuss wrote: >> >>> OK, maybe I found the culprit: >>> >>> (defun bfloat-erf (z) >>> ;; Warning! This has round-off problems when abs(z) is very small. >>> (let ((1//2 ($bfloat '((rat simp) 1 2)))) >>> ;; The argument is real, the result is real too >>> ($realpart >>> (mul >>> (simplify (list '(%signum) z)) >>> (sub 1 >>> (mul >>> (div 1 (power ($bfloat '$%pi) 1//2)) >>> (bfloat-gamma-incomplete 1//2 ($bfloat (power z 2))))))))) >>> >>> >>> >>> And similarly for |complex-bfloat-erf| . Changing 1//2 to bfhalf in >>> this code didn't result in any testsuite failures, but I have a few >>> pending changes to the function |absarg.| >> Nice bit of detective work! Yeah, renaming 1//2 to something else >> should take care of the problem. >>> >>> |Also, loading gamma.lisp gives the warning: (SBCL)| >>> >>> in: DEFUN GAMMA-INCOMPLETE >>> ; (COND ((COMPLEXP MAXIMA::X) #C(0.0d0 0.0d0)) ((REALP >>> MAXIMA::X) 0.0d0)) >> >> I think there are lots of these. >> >> The issue here is that the compiler doesn't know what X is, so the >> |cond| cases of |complexp| and |realp| covers the case of numbers, >> but there are lots of other types which aren't covered. >> >> This can be fixed in two ways. Add |(declare (number x))|. Add a |T| >> clause to |cond|. This should probably signal an error. >> >> Or maybe even replace the |cond| with |etypecase|? >> >> ​ > ​ ​ |
|
From: Robert D. <rob...@gm...> - 2025-12-05 18:41:34
|
On Fri, Dec 5, 2025 at 4:58 AM Barton Willis via Maxima-discuss <max...@li...> wrote: > > Another thing: Although bfhalf automatically updates when fpprec changes, some special variables defined in globals.lisp do not. I wonder if any specific bigfloat values should be functions instead of constants, so that changing fpprec causes a different value to be returned. Or maybe baking the prevailing fpprec into the symbol name, something like BIGFLOAT-%PI-FOR-DEFAULT-FPPREC or whatever. Speaking strictly for myself, I can't keep it straight in my head when some constant is no longer valid in some context ... if developers are supposed to "just know", then it's likely that I'll mess it up at some point. YMMV as always. Robert |
|
From: Richard F. <fa...@gm...> - 2025-12-05 19:17:03
|
Having written the bigfloat code about 50 years ago, I'm probably to blame for such things. Resetting the global bf values for one, zero, half are cheap. Values for e and pi and other constants may not be so cheap. I think some computations are done by bumping up the precision slightly and then rounding down, so re-doing e,pi, etc at each change may not be a great idea. But if they are memoized, maybe it doesn't matter, and it doesn't matter if functions producing the values are used in places, instead of the values themselves being stored. Note that the precision used for a bigfloat op like fpplus is the global fp precision, and is NOT governed by precision of the arguments. Also there is a Maxima variable $fpprec , initially 16, supposed to be number of decimal digits, and a lisp variable ?fpprec, initially 56, the corresponding number of binary bits in the "fraction" part of the bigfloat. Whether it is a feature or a defect, it is unclear: since there is no limit on the value of the exponent, "underflow" or "overflow" by exceeding that range is not possible, and so bigfloats do not have NaN (Not a Number) as do IEEE754 standard floats. Maxima has inf, und, ind, which might be "allowed" as bigfloats, if someone cared to do that, figured out the consequences, and it was acceptably fast. RJF On Fri, Dec 5, 2025 at 10:41 AM Robert Dodier <rob...@gm...> wrote: > On Fri, Dec 5, 2025 at 4:58 AM Barton Willis via Maxima-discuss > <max...@li...> wrote: > > > > Another thing: Although bfhalf automatically updates when fpprec > changes, some special variables defined in globals.lisp do not. > > I wonder if any specific bigfloat values should be functions instead > of constants, so that changing fpprec causes a different value to be > returned. Or maybe baking the prevailing fpprec into the symbol name, > something like BIGFLOAT-%PI-FOR-DEFAULT-FPPREC or whatever. > > Speaking strictly for myself, I can't keep it straight in my head when > some constant is no longer valid in some context ... if developers are > supposed to "just know", then it's likely that I'll mess it up at some > point. YMMV as always. > > Robert > > > _______________________________________________ > Maxima-discuss mailing list > Max...@li... > https://lists.sourceforge.net/lists/listinfo/maxima-discuss > |
|
From: Raymond T. <toy...@gm...> - 2025-12-05 21:49:42
|
On 12/5/25 10:41 AM, Robert Dodier wrote: > On Fri, Dec 5, 2025 at 4:58 AM Barton Willis via Maxima-discuss > <max...@li...> wrote: >> Another thing: Although bfhalf automatically updates when fpprec changes, some special variables defined in globals.lisp do not. > I wonder if any specific bigfloat values should be functions instead > of constants, so that changing fpprec causes a different value to be > returned. Or maybe baking the prevailing fpprec into the symbol name, > something like BIGFLOAT-%PI-FOR-DEFAULT-FPPREC or whatever. I agree on adding functions. We already have `fppi` that returns a bigfloat pi for the current fpprec. But `fppi` returns a bfloat object sans bfloat marker. And `fppi` is memoized. I think if you use the bigfloat package, you get `(bigfloat:%pi num)` where `num` is only used to figure out what kind of result to return (single, double, big float). Similarly for `bigfloat:%e`. > > Speaking strictly for myself, I can't keep it straight in my head when > some constant is no longer valid in some context ... if developers are > supposed to "just know", then it's likely that I'll mess it up at some > point. YMMV as always. I don't think it's just you. |
|
From: Richard F. <fa...@gm...> - 2025-12-05 23:42:03
|
(fppi) returns the insides of bigfloat %pi to the current bigfloat precision. If you want the whole number with the precision encoded, then use bcons. :lisp (setf $mypi (bcons (fppi))) sets the maxima variable mypi to a bigfloat pi which in the default precision prints as 3.141592653589793b0 The lisp programs (of which there are lots of examples) generally do calculations on the "insides" with the precision understood, and presumed (required) to be the same for all bigfloat insides in the calculation. One could relax that understanding and instead insist that each number has the header, so instead of just (say) adding two bigfloats insides by (fpplus a b), we could convert a to current precision, b to current precision, add them producing a result (with header) specifying the current precision. This is what bfloat(a+b) does. (fppi) returns the lisp list (56593902016227522 2) $mypi in lisp is ((bigfloat simp 56) 56593902016227522 2) I hope this helps if someone decides to read/extend/improve/replace this code. RJF On Fri, Dec 5, 2025 at 1:49 PM Raymond Toy <toy...@gm...> wrote: > > On 12/5/25 10:41 AM, Robert Dodier wrote: > > On Fri, Dec 5, 2025 at 4:58 AM Barton Willis via Maxima-discuss<max...@li...> <max...@li...> wrote: > > Another thing: Although bfhalf automatically updates when fpprec changes, some special variables defined in globals.lisp do not. > > I wonder if any specific bigfloat values should be functions instead > of constants, so that changing fpprec causes a different value to be > returned. Or maybe baking the prevailing fpprec into the symbol name, > something like BIGFLOAT-%PI-FOR-DEFAULT-FPPREC or whatever. > > I agree on adding functions. We already have `fppi` that returns a > bigfloat pi for the current fpprec. But `fppi` returns a bfloat object sans > bfloat marker. And `fppi` is memoized. I think if you use the bigfloat > package, you get `(bigfloat:%pi num)` where `num` is only used to figure > out what kind of result to return (single, double, big float). Similarly > for `bigfloat:%e`. > > Speaking strictly for myself, I can't keep it straight in my head when > some constant is no longer valid in some context ... if developers are > supposed to "just know", then it's likely that I'll mess it up at some > point. YMMV as always. > > I don't think it's just you. > > > _______________________________________________ > Maxima-discuss mailing list > Max...@li... > https://lists.sourceforge.net/lists/listinfo/maxima-discuss > |
|
From: Raymond T. <toy...@gm...> - 2025-12-05 23:50:19
|
On 12/5/25 3:41 PM, Richard Fateman wrote: > (fppi) returns the insides of bigfloat %pi to the current bigfloat > precision. If you want the > whole number with the precision encoded, then use bcons. > > :lisp (setf $mypi (bcons (fppi))) > > sets the maxima variable mypi to a bigfloat pi which in the default > precision prints as > 3.141592653589793b0 > > The lisp programs (of which there are lots of examples) generally do > calculations on the "insides" with > the precision understood, and presumed (required) to be the same for > all bigfloat insides in the calculation. > > One could relax that understanding and instead insist that each number > has the header, so > instead of just (say) adding two bigfloats insides by (fpplus a b), > we could convert a to current precision, b to current precision, add > them producing a result (with header) > specifying the current precision. This is what bfloat(a+b) does. > > (fppi) returns the lisp list (56593902016227522 2) > $mypi in lisp is ((bigfloat simp 56) 56593902016227522 2) > > I hope this helps if someone decides to read/extend/improve/replace > this code. The bigfloat package is intended to hide these implementation details while still using the original algorithms from float.lisp so that there are no weird and very hard to debug regressions in bfloat arithmetic. It won't be as fast as using the bare code from float.lisp, but hopefully it's a lot less error-prone and easier to write and debug. If someone really, really needs that speed boost, they can still get down and dirty with the original code. |