summaryrefslogtreecommitdiff
path: root/066.c
blob: 3c1014e24cc594c420f60ca85cd20b740efbe900 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include <gmp.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// numerator/denominator pairs of continued fractions are solutions to pell's equations

/*
 * taken from problem 65
 *
 * numerator, denominator: resulting num / denom are stored there
 * limit: depth of continued fraction
 * start: decimal part (pre-period)
 * factors, factor_len: period of continued fraction with factor_len elements
 *
 */
void compute(mpz_t numerator, mpz_t denominator, unsigned int limit,
		unsigned long start, const unsigned int* factors, unsigned int factor_len)
{
	int i;
	mpz_set_ui(numerator, 1);
	mpz_set_ui(denominator, factors[limit % factor_len]);
	for(i=limit-1; i>=0; i--)
	{
		mpz_addmul_ui(numerator, denominator, factors[i % factor_len]);
		mpz_swap(numerator, denominator);
	}
	mpz_addmul_ui(numerator, denominator, start);
}

// taken from problem 64
int continued_fraction(unsigned int* fraction, unsigned int n)
{
	double sqrtn, x, y;
	unsigned int an, a0, pos=0;

	sqrtn = sqrt((double)n);
	a0 = (int)floor(sqrtn);

	fraction[pos++] = sqrtn;

	if((int)sqrtn*sqrtn == n) // works only for rational square roots
		return 1;

	x = (double)a0;
	y = 1.0;

	while(1)
	{
		double denominator = (n - x*x);
		double tmp = y * (sqrtn + x) / denominator;
		an = (int)floor(tmp);
		x = (an * denominator / y) - x;
		y = denominator / y;

		fraction[pos++] = an;

		if(an == 2*a0)
			break;
	}

	return pos;
}

const int max_period_size = 100;

int main(void)
{
	int d, i, maxd=0;
	mpz_t maxx, numerator, denominator, tmp1, tmp2;
	unsigned int* fraction = (unsigned int*) malloc(max_period_size*sizeof(unsigned int));

	mpz_init_set_ui(maxx, 0);
	mpz_init(numerator);
	mpz_init(denominator);
	mpz_init(tmp1);
	mpz_init(tmp2);

	for(d=2; d<=1000; d++)
	{

		memset(fraction, 0, max_period_size*sizeof(unsigned int));
		int frac_len = continued_fraction(fraction, d);

		if(frac_len == 1) // no solution for squares
			continue;

		for(i=0;;i++)
		{
			compute(numerator, denominator, i, fraction[0], &(fraction[1]), frac_len-1);

			// numerator^2 - denominator^2 * d
			mpz_mul(tmp1, numerator, numerator);
			mpz_mul(tmp2, denominator, denominator);
			mpz_submul_ui(tmp1, tmp2, d);
			if(mpz_cmp_ui(tmp1, 1) == 0)
				break;
		}

		if(mpz_cmp(numerator, maxx) > 0)
		{
			mpz_set(maxx, numerator);
			maxd = d;
		}
	}

	printf("%d\n", maxd);

	return 0;
}