Project Euler Problem 57
这个要深入研究一下。。。。我是暴力写的。。太对不起人了。。。以后再改。。。
最近也在看连分数。。但是还是太囧。。
下面是在论坛讨论上大家的讨论。。以后再整理。。感觉还是遇到大牛了。。。。
巨牛的一个人用汇编写的代码,这个让我意识到,你真的很强悍!!
.data?
sumof dd ?
cword dw ?
.code
start:
mov ecx,1000 ;loop counter
finit
fstcw cword ;get control word
or cword,0c00h ;adjust it for truncating
fldcw cword ;modify FPU accordingly
fld1
fld1 ;initialize 2 registers
start1:
fadd st,st(1)
<script src="http://hi.images.csdn.net/js/blog/tiny_mce/themes/advanced/langs/zh.js" type="text/javascript"></script> <script src="http://hi.images.csdn.net/js/blog/tiny_mce/plugins/syntaxhl/langs/zh.js" type="text/javascript"></script> fadd st(1),st ;expand the 2 numbers
fxch ;larger one in top register
fldlg2
fld st(2)
fyl2x ;get log of smaller number
frndint ;keep only the mantissa
fldlg2
fld st(2)
fyl2x ;get log of larger number
frndint
fcomip st,st(1) ;compare the 2 mantissas
fstp st
jz @F
inc sumof ;increment if not the same
@@:
dec ecx
jnz start1
;final result is in "sumof"
05 Sep 2005 05:53 pm
KermitDFrog (Pencil/Paper)
if you examine the function:
Len(Numerator)/Len(Denominator)
you'll notice a pattern.
1 <= x < 2
x,1,1,1,1,1,1,1,x,1,1,1,1,x,1,1,1,1,1,1,1,x...
that is, an x (the value with different Len values. except in the first case of 1.) followed by 7 ones, x, then 4
ones, then x.
so, if we measure the distances between x's, we get 8, and 5, (thats measured x to x. as follows:
x, 1, 1, 1, 1, 1, 1, 1, x, 1, 1, 1, 1, x...
0, 1, 2, 3, 4, 5, 6, 7, 8,
0, 1, 2, 3, 4, 5...
so the First answer you should generate out of this is:
;this is just psuedocode.
Loop While i <= Limit [
i += 8
i += 5
x += 2
]
So, this can be easily simplified to
Loop While i <= Limit [
i += 13
x += 2
]
further, you can break this down to
2*((Limit-1) / 13)
that is, x += 2 becomes 2*
Limit is the upper limit of the function (1000 in this case)
you subtract one to eliminate the first x (which equals 1, and is therefore an exception to the pattern.) and
divide by 13, which is the distance between pairs of x's.
So, the number of non-1 values the function
Len(N)/Len(D), where the Limit Value is 1000, is the following.
2*(1000-1/13)
2*(999/13)
1998/13
153.692
the function has a minor margin of error, so for relatively small Limit-values, you should be accurate enough to
just take the integer part, which i did, and, apparently, became the first person to post a non-bruteforce method
to solve this problem.
Rockin.
PS, this officially puts me as more than 1/4 done. 13/50's of the way done, to be exact.
; Edit
This is a better Formula, eliminates the Int(n) portion. Simple Mod Trick.
{[2((Limit-1)-((Limit-1) Mod 13))]/13} + 1
They should install MathTex or LaTeX on this forum, so I can spew my genius in the appropriate form.
I believe the magic number in there (the +1) accounts for the first x in the series-- Not entirely sure, can't
prove anything yet..
Ribbet.
11 Sep 2005 07:53 am
KermitDFrog (Pencil/Paper)
Just a Quick update, The Cleanest Method I came up with uses Mathematica's Floor Function, It looks something
like:
(2*Floor[(L-1)/13])+ 1
Although, I'm convinced there is a prettier way of doing this. That doesn't involve that ugly floor function.
~~joe
PS, how are you coming with your better way, Zron?
Letting N(n) and D(n) represent the nth numerator and denominator, we have the recurrence relations
N(0) = 1, N(1) = 1, N(n) = 2*N(n-1)+ N(n-2) for n>=2
D(0) = 0, D(1) = 1, D(n) = 2*D(n-1)+ D(n-2) for n>=2
These are linear, homogeneous recurrence relations, relatively easily solvable by standard methods. (Try a
solution of the form a(n) = r^n, you'll get a quadratic equation for r, with roots r1 and r2, and the final
solution will be a linear combination a(n) = A*r1^n + B*r2^n, where A and B are determined by the initial
conditions.)
In this case, r1=1+sqrt(2) and r2=1-sqrt(2), and
N(n) = (r1^n + r2^n)/(2)
D(n) = (r1^n - r2^n)/(2*sqrt(2))
In fact, I've actually set it so that when the above formula starts with n=2, it coincides with the first
numerator & denominator given in the problem.
Using the formula that the number of digits of x is 1+floor(log10(x)), we see that
numer_dig = 1+floor(log10(N(n))) = 1+floor(n*log10(r1) + log10(1+(r2/r1)^n) - log10(2))
denom_dig = 1+floor(log10(D(n))) = 1+floor(n*log10(r1) + log10(1-(r2/r1)^n) - 1.5*log10(2))
[hide code]
#include <stdio.h>
#include <math.h>
int main(void)
{
int n, count;
double c1, c2, power, numer_dig, denom_dig;
c1 = log10(1.0+sqrt(2.0));
c2 = 2.0*sqrt(2.0)-3.0;
count=0;
for (n=2; n<=1001; n++) {
power = pow(c2,n);
numer_dig = 1 + floor(n*c1 + log10(1+power) -1.0*log10(2.0));
denom_dig = 1 + floor(n*c1 + log10(1-power) -1.5*log10(2.0));
if (numer_dig >denom_dig) count++;
}
printf("count=%d/n", count);
return 0;
}
31 Jan 2008 04:35 pm
observ (C/C++)
Using the recurrences
nr = 2dr-1 + nr-1 [0]
dr = dr-1 + nr-1 [1]
=> nr = dr + dr-1 [2]
I end up with
[hide code]
#include <iostream>
#include <iomanip>
#include <gmpxx.h>
int main ()
{
mpz_class n (1393), d (985), powerten (1000);
int sn = 7, count = 0;
do
{
do
{
if (n >= powerten)
++count;
mpz_class old_d (d);
d = n + d;
n = d + old_d;
} while (++sn < 1000 && d < powerten);
powerten *= 10;
} while (sn < 1000);
std::cout << "Answer: " << count << std::endl;
return 0;
}
amitg@athena. time ./p57
Answer: 153
./p57 0.00s user 0.00s system 154% cpu 0.003 total
Incidentally, we can derive a pure recurrence for the denominator (not involving the numerator):
nr-1 + dr-1 = dr [3] (from 1)
nr-1 - dr-1 = dr-2 [4] (from 2)
Subtracting 4 from 3:
2dr-1 = dr - dr-2
=> dr = 2dr-1 + dr-2 [5]
Now, given that n1 = 3 and d1 = 2, we get (from 1 and 2):
2n0 + d0 = 3
n0 + d0 = 2
We get n0 = d0 = 1.
This makes 5 the Pell Number recurrence (see http://mathworld.wolfram.com/PellNumber.html), with values 1, 2, 5,
12, 29, ...
Similarly, we can derive a recurrence relation only in n for the numerator:
2dr-1 = nr - nr-1 (from 0)
2dr = 2dr-1 + 2nr-1 (from 1)
=> nr+1 - nr = nr - nr-1 + 2nr-1
=> nr+1 = 2nr + nr-1
=> nr = 2nr-1 + nr-2 [6]
This is the same recurrence relation as the denominator, but with different seed values, so it does not generate
Pell numbers.
I found it easier to use the mutually dependent recurrences, however.