Skip to content

Commit 86c2a97

Browse files
bdeketsoegaard
authored andcommitted
fllog+, fllog-quotient & fllog-hypot
document (and improve) fllog+ and fllog-quotient, and add fllog-hypot fllog+ * change boundaries for double-double calculation `(fflog+ -1.4293498385921057e-012 +2.5111776760269606)` fllog-quotient * correct handling if x is +nan.0 * double-double calculation if x/y is near 1 * avoid unnecessary multiplication with s `(fflog-quotient 500000000001. +500000000000.)` `(fflog-quotient +nan.0 +2.)` fllog-hypot * avoid over/underflow * accuracy where (hypot x y) is near 1 `(fllog-hypot 1e-321 +1e-320)` `(fllog-hypot 1.1084129893159664 +1.619387121491612e-005)`
1 parent eac8cd9 commit 86c2a97

File tree

3 files changed

+50
-5
lines changed

3 files changed

+50
-5
lines changed

math-doc/math/scribblings/math-flonum.scrbl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,13 @@ For factorial-like functions that return sensible values for non-integers, see
121121
@racket[gamma] and @racket[beta].
122122
}
123123

124+
@deftogether[(@defproc[(fllog+ [a Flonum] [b Flonum]) Flonum]
125+
@defproc[(fllog-quotient [a Flonum] [b Flonum]) Flonum]
126+
@defproc[(fllog-hypot [a Flonum] [b Flonum]) Flonum])]{
127+
Like @racket[(fllog (+ a b))] , @racket[(fllog (/ a b))] and @racket[(fllog (flhypot a b))]
128+
but avoiding over/underflow and accurate when the argument to @racket[fllog] is near 1
129+
(within 1 @tech{ulp}).}
130+
124131
@deftogether[(@defproc[(fllog-factorial [n Flonum]) Flonum]
125132
@defproc[(fllog-binomial [n Flonum] [k Flonum]) Flonum]
126133
@defproc[(fllog-permutations [n Flonum] [k Flonum]) Flonum]

math-lib/math/private/flonum/flonum-log.rkt

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
lg1+ lg+ lg1- lg- lgsum
1515
fllog-quotient
1616
fllog2
17-
fllogb)
17+
fllogb
18+
fllog-hypot)
1819

1920
(begin-encourage-inline
2021

@@ -99,9 +100,10 @@
99100

100101
(: fllog+ (Flonum Flonum -> Flonum))
101102
;; Computes log(a+b) in a way that is accurate for a+b near 1.0
103+
;; random testing shows 99.9% <0.5ulp and 100%< 1ulp
102104
(define (fllog+ a b)
103105
(define a+b (+ a b))
104-
(cond [((flabs (- a+b 1.0)) . < . (fllog 2.0))
106+
(cond [(< 0.3 a+b 2.7)
105107
;; a+b is too close to 1.0, so compute in higher precision
106108
(define-values (a+b a+b-lo) (fast-fl+/error a b))
107109
(- (fllog a+b) (fllog1p (- (/ a+b-lo a+b))))]
@@ -167,16 +169,21 @@
167169
(+ max-log-x (fllog1p s)))))))))))
168170

169171
(: fllog-quotient (Flonum Flonum -> Flonum))
170-
;; Computes (fllog (/ x y)) in a way that reduces error and avoids under-/overflow
172+
;; Computes (fllog (/ x y)) in a way that reduces error, avoids under-/overflow
173+
;; and is more accurate for x ≈ y. random testing shows 96% <0.5 ulp 99.5%<1ulp
174+
;; and 100% < 1.3 (when x very big and y very small or reversed)
171175
(define (fllog-quotient x y)
172176
(let ([x (flabs x)]
173177
[y (flabs y)]
174178
[s (fl/ (flsgn x) (flsgn y))])
175179
(cond [(s . fl> . 0.0)
176180
(define z (fl/ x y))
177-
(cond [(and (z . fl> . +max-subnormal.0) (z . fl< . +inf.0)) (fllog (fl* s z))]
181+
(cond [(< 0.5 z 2.5)
182+
(define-values (z z_) (fl//error x y))
183+
(fl- (fllog z) (fllog1p (- (/ z_ z))))]
184+
[(and (z . fl> . +max-subnormal.0) (z . fl< . +inf.0)) (fllog z)]
178185
[else (fl+ (fllog x) (- (fllog y)))])]
179-
[(s . fl= . 0.0) -inf.0]
186+
[(and (s . fl= . 0.0) (not (flnan? x))) -inf.0]
180187
[else +nan.0])))
181188

182189
(define log-max.0 (fllog +max.0))
@@ -264,3 +271,24 @@
264271
;; Oh noes! We had overflows or underflows!
265272
;; Not a lot we can do without introducing more error, so just return y
266273
y])]))
274+
275+
(: fllog-hypot (-> Flonum Flonum Flonum))
276+
;; computes (log (hypot x y)) avoiding over/underflow and more accurate when (hypot x y) ≈ 1.0
277+
;; random testing shows 99.9% < 0.5ulp and 100% < 1ulp
278+
(define (fllog-hypot X Y)
279+
(define x (flabs X))
280+
(define y (flabs Y))
281+
(define m (flhypot x y))
282+
(cond
283+
[(or (<= m .23e-307)
284+
(and (flinfinite? m) (flrational? x) (flrational? y)))
285+
(fl* 0.5 (lg+ (fl* 2. (fllog x)) (fl* 2. (fllog y))))]
286+
[(<= 0.15 m 2.7)
287+
(define-values (x² x²_) (fl*/error x x))
288+
(define-values (y² y²_) (fl*/error y y))
289+
(define-values (x+y x+y_) (fl2+ x² x²_ y² y²_))
290+
(fl* 0.5 (fl- (fllog x+y) (fllog1p (- (/ x+y_ x+y)))))]
291+
[(<= 0.025 m 25.)
292+
(fl* 0.5 (fllog (+ (flexpt x 2.) (flexpt y 2.))))]
293+
[else
294+
(fllog m)]))

math-test/math/tests/function-tests.rkt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,13 @@
101101
(check-= (Fresnel-C 20) 0.4999873349723443881870062136976602164476 (ε))
102102
(check-= (Fresnel-C 50) 0.4999991894307279679558101639817919070024 (ε))
103103

104+
;; ---------------------------------------------------------------------------------------------------
105+
;; fllog+ fllog-quotient fllog-hypot
106+
(check-= (fllog+ 1. 1e-20) 1e-20 (* 10 (flulp 1e-20)))
107+
(check-= (fllog-quotient +min.0 2.0) -745.1332191019411 1.e-10)
108+
(check-= (fllog-quotient 1.8244133740471687e+267 +8.64804592730887e-063) 758.2970057934524 1.)
109+
(check-= (fllog-quotient 1.8244133740471687e+267 +8.64804592730887e-063) 758.2970057934524 1.)
110+
(check-= (fllog-quotient 500000000001. +500000000000.) 2e-12 1e-20)
111+
(check-= (fllog-hypot #i3/5 #i4/5) 2.22e-17 1e-18)
112+
(check-= (fllog-hypot +min.0 +min.0) -744.0934983311013 1e-10)
113+
(check-= (fllog-hypot +max.0 +max.0) 710.1292864836639 1e-10)

0 commit comments

Comments
 (0)