Skip to content

Commit 1db97d8

Browse files
committed
Implement the rest of the functionality. All tests pass
1 parent aa2c7e2 commit 1db97d8

File tree

2 files changed

+80
-46
lines changed

2 files changed

+80
-46
lines changed

src/Polynomials.jl

Lines changed: 75 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ promote_rule{T, S}(::Type{Poly{T}}, ::Type{Poly{S}}) = Poly{promote_type(T, S)}
2727
eltype{T}(::Poly{T}) = T
2828

2929
length(p::Poly) = length(p.a)
30-
endof(p::Poly) = length(p)
30+
endof(p::Poly) = length(p) - 1
3131

3232
getindex{T}(p::Poly{T}, i) = (i+1 > length(p.a) ? zero(T) : p.a[i+1])
3333
function setindex!(p::Poly, v, i)
@@ -67,12 +67,13 @@ function printterm{T}(io::IO,p::Poly{T},j,first)
6767
if pj == zero(T)
6868
return false
6969
end
70-
neg = abs(pj) < 0
70+
neg = pj < 0
7171
if first
7272
neg && print(io, "-") #Prepend - if first and negative
7373
else
7474
neg ? print(io, " - ") : print(io," + ")
7575
end
76+
pj = abs(pj)
7677
if pj != one(T) || j == 0
7778
show(io,pj)
7879
end
@@ -154,10 +155,23 @@ function -{T}(c::Number, p::Poly{T})
154155
end
155156
end
156157

157-
+{T,S}(p1::Poly{T}, p2::Poly{S}) = Poly([p1[i] + p2[i] for i = 0:max(length(p1),length(p2))])
158-
-{T,S}(p1::Poly{T}, p2::Poly{S}) = Poly([p1[i] - p2[i] for i = 0:max(length(p1),length(p2))])
158+
function +{T,S}(p1::Poly{T}, p2::Poly{S})
159+
if p1.var != p2.var
160+
error("Polynomials must have same variable")
161+
end
162+
Poly([p1[i] + p2[i] for i = 0:max(length(p1),length(p2))])
163+
end
164+
function -{T,S}(p1::Poly{T}, p2::Poly{S})
165+
if p1.var != p2.var
166+
error("Polynomials must have same variable")
167+
end
168+
Poly([p1[i] - p2[i] for i = 0:max(length(p1),length(p2))])
169+
end
159170

160171
function *{T,S}(p1::Poly{T}, p2::Poly{S})
172+
if p1.var != p2.var
173+
error("Polynomials must have same variable")
174+
end
161175
R = promote_type(T,S)
162176
n = length(p1)
163177
m = length(p2)
@@ -170,39 +184,43 @@ function *{T,S}(p1::Poly{T}, p2::Poly{S})
170184
a
171185
end
172186

187+
function degree{T}(p::Poly{T})
188+
for i = length(p):-1:0
189+
if p[i] > 2*eps(T)
190+
return i
191+
end
192+
end
193+
return -1
194+
end
195+
173196
function divrem{T, S}(num::Poly{T}, den::Poly{S})
174197
if num.var != den.var
175198
error("Polynomials must have same variable")
176199
end
177-
m = length(den)
178-
if m == 0
200+
m = degree(den)
201+
if m < 0
179202
throw(DivideError())
180203
end
181204
R = typeof(one(T)/one(S))
182-
n = length(num)
205+
n = degree(num)
183206
deg = n-m+1
184207
if deg <= 0
185-
return zero(Poly{R}), convert(Poly{R}, num)
208+
return convert(Poly{R}, zero(num)), convert(Poly{R}, num)
186209
end
187-
d = zeros(R, n)
188-
q = zeros(R, deg)
189-
r = zeros(R, n)
190-
r[:] = num.a
191-
for i = 1:deg
192-
quot = r[i] / den[1]
193-
q[i] = quot
194-
if i > 1
195-
d[i-1] = 0
196-
r[i-1] = 0
197-
end
198-
for j = 1:m
199-
k = i+j-1
210+
# We will still modify q,r, but already wrap it in a
211+
# polynomial, so the indexing below is more natural
212+
pQ = Poly(zeros(R, deg), num.var)
213+
pR = Poly(zeros(R, n+1), num.var)
214+
pR.a[:] = num.a[1:(n+1)]
215+
for i = n:-1:m
216+
quot = pR[i] / den[m]
217+
pQ[i-m] = quot
218+
for j = 0:m
200219
elem = den[j]*quot
201-
d[k] = elem
202-
r[k] -= elem
220+
pR[i-(m-j)] -= elem
203221
end
204222
end
205-
return Poly(q, num.var), Poly(r, num.var)
223+
return pQ, pR
206224
end
207225
/(num::Poly, den::Poly) = divrem(num, den)[1]
208226
rem(num::Poly, den::Poly) = divrem(num, den)[2]
@@ -227,7 +245,7 @@ function polyval{T}(p::Poly{T}, x::Number)
227245
return zero(R)
228246
else
229247
y = convert(R, p[end])
230-
for i = (lenp-1):-1:0
248+
for i = (endof(p)-1):-1:0
231249
y = p[i] + x.*y
232250
end
233251
return y
@@ -277,34 +295,50 @@ poly(A::Matrix, var::Char) = poly(eig(A)[1], symbol(var))
277295

278296
roots{T}(p::Poly{Rational{T}}) = roots(convert(Poly{promote_type(T, Float64)}, p))
279297

298+
280299
# compute the roots of a polynomial
281300
function roots{T}(p::Poly{T})
282301
R = promote_type(T, Float64)
283-
num_zeros = 0
284-
if length(p) == 0
285-
return zeros(R, 0)
286-
end
287-
while abs(p[num_zeros]) <= 2*eps(T)
288-
if num_zeros == length(p)-1
302+
length(p) == 0 && return zeros(R, 0)
303+
304+
num_leading_zeros = 0
305+
while abs(p[num_leading_zeros]) <= 2*eps(T)
306+
if num_leading_zeros == length(p)-1
289307
return zeros(R, 0)
290308
end
291-
num_zeros += 1
309+
num_leading_zeros += 1
292310
end
293-
n = length(p)-num_zeros-1
294-
if n < 1
295-
return zeros(R, length(p)-1)
311+
312+
num_trailing_zeros = 0
313+
while abs(p[end - num_trailing_zeros]) <= 2*eps(T)
314+
num_trailing_zeros += 1
296315
end
316+
317+
n = endof(p)-(num_leading_zeros + num_trailing_zeros)
318+
319+
n < 1 && return zeros(R, length(p) - num_trailing_zeros - 1)
320+
297321
companion = zeros(R, n, n)
298-
a0 = p[num_zeros]
322+
an = p[end-num_trailing_zeros]
299323
for i = 1:n-1
300-
companion[1,i] = -p[num_zeros+i] / a0
324+
companion[i,n] = -p[num_leading_zeros + i - 1] / an
301325
companion[i+1,i] = 1;
302326
end
303-
companion[1,end] = -p[end] / a0
304-
D,V = eig(companion)
305-
r = zeros(eltype(D),length(p)-1)
306-
r[1:n] = 1./D
327+
companion[end,end] = -p[end-num_trailing_zeros-1] / an
328+
D = eigvals(companion)
329+
r = zeros(eltype(D),length(p)-num_trailing_zeros-1)
330+
r[1:n] = D
307331
return r
308332
end
309333

334+
function gcd{T<:FloatingPoint, S<:FloatingPoint}(a::Poly{T}, b::Poly{S})
335+
#Finds the Greatest Common Denominator of two polynomials recursively using
336+
#Euclid's algorithm: http://en.wikipedia.org/wiki/Polynomial_greatest_common_divisor#Euclid.27s_algorithm
337+
if all(abs(b.a).<=2*eps(S))
338+
return a
339+
else
340+
s, r = divrem(a, b)
341+
return gcd(b, r)
342+
end
343+
end
310344
end # module Poly

test/tests.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,17 @@ a_roots = copy(pN.a)
5353
@test roots(pR) == [1//2, 3//2]
5454

5555
@test pNULL + 2 == p0 + 2 == 2 + p0 == Poly([2])
56-
@test p2 - 2 == -2 + p2 == Poly([1,-1])
57-
@test 2 - p2 == Poly([-1,1])
56+
@test p2 - 2 == -2 + p2 == Poly([-1,1])
57+
@test 2 - p2 == Poly([1,-1])
5858

5959
p0 = Poly([0])
6060
p1 = Poly([1])
61-
p2 = Poly([4, 2, -3, 6, 5])
62-
p3 = Poly([6, 2, -3, 7])
61+
p2 = Poly([5, 6, -3, 2 ,4])
62+
p3 = Poly([7, -3, 2, 6])
6363
p4 = p2 * p3
6464
@test divrem(p4, p2) == (p3, zero(p3))
6565
@test p3%p2 == p3
66-
@test all((abs((p2/p3 - Poly([2/3,1/9])).a)) .< eps())
66+
@test all((abs((p2/p3 - Poly([1/9,2/3])).a)) .< eps())
6767
@test divrem(p0,p1) == (p0,p0)
6868
@test divrem(p1,p1) == (p1,p0)
6969
@test divrem(p2,p2) == (p1,p0)

0 commit comments

Comments
 (0)