I've computed the first 9.6 million coefficients and get the following maximum values. There is only one additional large value added to your list.
n a_n
1 1
2 3
4 5
10 8
12 14
32 15
36 534
572 7451
1991 12737
20857 22466
27432 68346
28763 148017
155122 217441
190271 320408
288108 533679
484709 4156269
1395499 4886972
9370521 10253793
Here is my Ruby code.
The big improvement over your code is that I do a binary search, first finding the smallest $n$ such that $p(2^n)<0
Once we have the values $2^n$ and $2^{n+1}$, this algorithm performs a binary search between those values to find $m$ so that $p(m)<0
Even this could be optimized, since the binary search is pure, so we are always doing $p(N+2^k)$ for some $N$ where $p(N)$ is already known. We get $$p(N+2^k)=p(N)+p'(N)2^k + p''(N)2^{2k}/2 + p'''(N)2^{3k},$$ so we might be able to get away with speeding up those calculations. The second code example implements that. It is a bit more opaque.
# Evaluate the polynomial at a value
def evaluate(v,poly)
total = 0
poly.each do |c|
total = total*v + c
end
total
end
# Performance hack - evaluate the polynomial at 2**n
# Uses bit-shifting to improve performance in this cases
def evaluate_bits(n,coefficients)
total = 0
coefficients.each do |c|
total = (total << n) + c
end
total
end
# Given the current polynomial, and a value, compute
# y^3p(v+1/y)
#
# p(x)=ax^3+bx^2+cx+d
# y^3p(v+1/y)=a(yv+1)^3 + by(yv+1)^2+cy^2(yv+1)+dy^3
# = p(v)y^3+(3av^2+2bv+c)y^2+(3av+b)y +a
def nextPoly(v,poly)
a,b,c,d = poly
v2= v*v
v3 = v2*v
a1 = a*v3+b*v2+c*v+d
b1 = 3*a*v2 + 2*b*v + c
c1 = 3*a*v + b
d1 = a
# Take the negative, so the new polynomial is negative at 1
[-a1,-b1,-c1,-d1]
end
# Find 2^n so that p(2^n)<01 do
#STDERR.puts "#{range1} #{range2}"
middle = (range1+range2)/2
midval = evaluate(middle,poly)
if midval < 0 then
range1 = middle
else
range2 = middle
end
end
range1
end
p = [1,0,0,-2]
denom1 = 1
denom2 = 0
numer1 = 0
numer2 = 1
(1..500000).each do |i|
c = next_value(p)
p = nextPoly(c,p)
puts "#{i} #{c}"
end
puts '#{p}'
The more opaque script using polynomial shifting to try to avoid most multiplications.
require 'csv'
# Performance hack - evaluate a polynomial at 2**n
# Uses bit-shifting to improve performance
def evaluate_bits(n,coefficients)
total = 0
coefficients.each do |c|
total = (total << n) + c
end
total
end
# p(x)=x^3-2
p = [1,0,0,-2]
max_index = 0
pn_1=0
qn_1=1
pn=1
qn=0
if ARGV.size>0
# Read the CSV file for the first coefficients
CSV.foreach(ARGV[0],col_sep: ' ') do |row|
index = row[0].to_i
coefficient = row[1].to_i
max_index = index
pn_1,pn = pn, pn*coefficient +pn_1
qn_1,qn = qn, qn*coefficient +qn_1
if index % 10000 == 0
STDERR.puts "Finished coefficient #{index}"
end
puts "#{index} #{coefficient}"
end
# p(x)=(x*p_n + p_(n-1))^3 - 2*(x*q_n+q_(n-1))^3
a = pn*pn*pn - 2*qn*qn*qn
b = 3*(pn*pn*pn_1 - 2*qn*qn*qn_1)
c = 3*(pn*pn_1*pn_1 - 2*qn*qn_1*qn_1)
d = pn_1*pn_1*pn_1 - 2*qn_1*qn_1*qn_1
if (a>0)
p = [a,b,c,d]
else
p = [-a,-b,-c,-d]
end
end
# Find n so that 2^n so that p(2^n)<00 do
bits = bits-1
midval = evaluate_bits(bits,shifted_poly)
if midval < 0 then
shifted_poly = shift_poly_bits(bits,midval,shifted_poly)
minimum = minimum + (1<
Closing in on n=10,000,000, the program is dealing with cubic polynomials with coefficients of about 16,500,000 bits each. In base 10, these numbers would have more than 5,000,000 digits. My laptop takes about 6.7 minutes to compute each additional 10,000 coefficients, or about 25 additional coefficients per second.