Skip to content

Commit b78d955

Browse files
authored
Merge pull request #90 from hrobotron/master
More robust polyfit
2 parents 7fa544e + a8c9302 commit b78d955

File tree

2 files changed

+22
-13
lines changed

2 files changed

+22
-13
lines changed

src/Polynomials.jl

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -499,31 +499,24 @@ roots(poly([1,2,3,4])) # [1.0,2.0,3.0,4.0]
499499
function roots{T}(p::Poly{T})
500500
R = promote_type(T, Float64)
501501
length(p) == 0 && return zeros(R, 0)
502-
503502
num_leading_zeros = 0
504503
while abs(p[num_leading_zeros]) <= 2*eps(T)
505504
if num_leading_zeros == length(p)-1
506505
return zeros(R, 0)
507506
end
508507
num_leading_zeros += 1
509508
end
510-
511509
num_trailing_zeros = 0
512510
while abs(p[end - num_trailing_zeros]) <= 2*eps(T)
513511
num_trailing_zeros += 1
514512
end
515-
516513
n = endof(p)-(num_leading_zeros + num_trailing_zeros)
517-
518514
n < 1 && return zeros(R, length(p) - num_trailing_zeros - 1)
519515

520-
companion = zeros(R, n, n)
516+
companion = diagm(ones(R, n-1), -1)
521517
an = p[end-num_trailing_zeros]
522-
for i = 1:n-1
523-
companion[i,n] = -p[num_leading_zeros + i - 1] / an
524-
companion[i+1,i] = 1;
525-
end
526-
companion[end,end] = -p[end-num_trailing_zeros-1] / an
518+
companion[1,:] = -p[(end-num_trailing_zeros-1):-1:num_leading_zeros] / an
519+
527520
D = eigvals(companion)
528521
r = zeros(eltype(D),length(p)-num_trailing_zeros-1)
529522
r[1:n] = D
@@ -571,13 +564,29 @@ polyfit(xs, ys, 2)
571564
```
572565
573566
Original by [ggggggggg](https://github.com/Keno/Polynomials.jl/issues/19)
567+
More robust version by Marek Peca <[email protected]>
568+
(1. no exponentiation in system matrix construction, 2. QR least squares)
574569
"""
575570
function polyfit(x, y, n::Int=length(x)-1, sym::Symbol=:x)
576571
length(x) == length(y) || throw(DomainError)
577572
1 <= n <= length(x) - 1 || throw(DomainError)
578573

579-
A = [ float(x[i])^p for i = 1:length(x), p = 0:n ]
580-
Poly(A \ y, sym)
574+
#
575+
# here unsure, whether similar(float(x[1]),...), or similar(x,...)
576+
# however similar may yield unwanted surprise in case of e.g. x::Int
577+
#
578+
A=similar(float(x[1:1]), length(x), n+1)
579+
#
580+
# TODO: add support for poly coef bitmap
581+
# (i.e. polynomial with some terms fixed to zero)
582+
#
583+
A[:,1]=1
584+
for i=1:n
585+
A[:,i+1]=A[:,i] .* x # cumulative product more precise than x.^n
586+
end
587+
Aqr=qrfact(A) # returns QR object, not a matrix
588+
p=Aqr\y # least squares solution via QR
589+
Poly(p, sym)
581590
end
582591
polyfit(x,y,sym::Symbol) = polyfit(x,y,length(x)-1, sym)
583592

test/runtests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ a_roots = copy(pN.a)
6363
@test all(abs(sort(roots(poly(a_roots))) - sort(a_roots)) .< 1e6)
6464
@test length(roots(p5)) == 4
6565
@test roots(pNULL) == []
66-
@test roots(pR) == [1//2, 3//2]
66+
@test sort(roots(pR)) == [1//2, 3//2]
6767

6868
@test pNULL + 2 == p0 + 2 == 2 + p0 == Poly([2])
6969
@test p2 - 2 == -2 + p2 == Poly([-1,1])

0 commit comments

Comments
 (0)