You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Evaluate `p(x)` using a compensation scheme of S. Graillat, Ph. Langlois, N. Louve [Compensated Horner Scheme](https://cadxfem.org/cao/Compensation-horner.pdf). Either a `Polynomial` `p` or it coefficients may be passed in.
308
+
309
+
The Horner scheme has relative error given by
310
+
311
+
`|(p(x) - p̂(x))/p(x)| ≤ α(n) ⋅ u ⋅ cond(p, x)`, where `u` is the precision (`2⁻⁵³ = eps()/2`)).
312
+
313
+
The compensated Horner scheme has relative error bounded by
As noted, this reflects the accuracy of a backward stable computation performed in doubled working precision `u²`. (E.g., polynomial evaluation of a `Polynomial{Float64}` object through `compensated_horner` is as accurate as evaluation of a `Polynomial{Double64}` object (using the `DoubleFloat` package), but significantly faster.
318
+
319
+
Pointed out in https://discourse.julialang.org/t/more-accurate-evalpoly/45932/5.
320
+
"""
321
+
functioncompensated_horner(p::P, x) where {T, P <:Polynomials.StandardBasisPolynomial{T}}
322
+
compensated_horner(coeffs(p), x)
323
+
end
324
+
325
+
# rexpressed from paper to compute horner_sum in same pass
326
+
# sᵢ -- horner sum
327
+
# c -- compensating term
328
+
@inlinefunctioncompensated_horner(ps, x)
329
+
n, T =length(ps), eltype(ps)
330
+
aᵢ = ps[end]
331
+
sᵢ = aᵢ *_one(x)
332
+
c =zero(T) *_one(x)
333
+
for i in n-1:-1:1
334
+
aᵢ = ps[i]
335
+
pᵢ, πᵢ =two_product_fma(sᵢ, x)
336
+
sᵢ, σᵢ =two_sum(pᵢ, aᵢ)
337
+
c =fma(c, x, πᵢ + σᵢ)
338
+
end
339
+
sᵢ + c
340
+
end
341
+
342
+
functioncompensated_horner(ps::Tuple, x::S) where {S}
343
+
ps == () &&returnzero(S)
344
+
if@generated
345
+
n =length(ps.parameters)
346
+
sσᵢ =:(ps[end] *_one(x), zero(S))
347
+
c = :(zero(S) *_one(x))
348
+
for i in n-1:-1:1
349
+
pπᵢ = :(two_product_fma($sσᵢ[1], x))
350
+
sσᵢ = :(two_sum($pπᵢ[1], ps[$i]))
351
+
Σ = :($pπᵢ[2] +$sσᵢ[2])
352
+
c = :(fma($c, x, $Σ))
353
+
end
354
+
s = :($sσᵢ[1] +$c)
355
+
s
356
+
else
357
+
compensated_horner(ps, x)
358
+
end
359
+
end
360
+
361
+
# error-free-transformations (EFT) of a∘b = x + y where x, y floating point, ∘ mathematical
362
+
# operator (not ⊕ or ⊗)
363
+
@inlinefunctiontwo_sum(a, b)
364
+
x = a + b
365
+
z = x - a
366
+
y = (a - (x-z)) + (b-z)
367
+
x, y
368
+
end
369
+
370
+
# return x, y, floats, with x + y = a * b
371
+
@inlinefunctiontwo_product_fma(a, b)
372
+
x = a * b
373
+
y =fma(a, b, -x)
374
+
x, y
375
+
end
376
+
377
+
378
+
# Condition number of a standard basis polynomial
379
+
# rule of thumb: p̂ a compute value
380
+
# |p(x) - p̃(x)|/|p(x)| ≤ α(n)⋅u ⋅ cond(p,x), where u = finite precision of compuation (2^-p)
381
+
function LinearAlgebra.cond(p::P, x) where {P <:Polynomials.StandardBasisPolynomial}
0 commit comments