Skip to content

Commit ecec548

Browse files
committed
P45, P46, P587: Added Haskell solutions.
Readme: Updated solution count.
1 parent f8dafad commit ecec548

File tree

4 files changed

+139
-1
lines changed

4 files changed

+139
-1
lines changed

Readme.markdown

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ A collection of Nayuki's program code to solve over 200 Project Euler math probl
55

66
Every solved problem has a program written in Java and usually Python. Some solutions also have Mathematica and Haskell programs. Some solution programs include a detailed mathematical explanation/proof in the comments to justify the code's logic.
77

8-
All problems from #1 to #100 have a Java and Python program, and problems #1 to #50 have a Mathematica program. This package contains at least 200 solutions in Java, at least 195 in Python, at least 120 in Mathematica, and at least 85 in Haskell.
8+
All problems from #1 to #100 have a Java and Python program, and problems #1 to #50 have a Mathematica program. This package contains at least 200 solutions in Java, at least 195 in Python, at least 120 in Mathematica, and at least 90 in Haskell.
99

1010
Java solutions require JDK 7+. Python solutions are tested to work on CPython 2.7.10 and 3.4.3. Mathematica solutions are tested to work on Mathematica 5.1.
1111

haskell/p045.hs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{-
2+
- Solution to Project Euler problem 45
3+
- Copyright (c) Project Nayuki. All rights reserved.
4+
-
5+
- https://www.nayuki.io/page/project-euler-solutions
6+
- https://github.com/nayuki/Project-Euler-solutions
7+
-}
8+
9+
10+
main = putStrLn (show ans)
11+
ans = compute 286 166 144
12+
13+
compute :: Integer -> Integer -> Integer -> Integer
14+
compute i j k = let
15+
triangle = div (i * (i + 1)) 2
16+
pentagon = div (j * (j * 3 - 1)) 2
17+
hexagon = k * (k * 2 - 1)
18+
minim = minimum [triangle, pentagon, hexagon]
19+
in if (minim == triangle && minim == pentagon && minim == hexagon) then minim
20+
else compute
21+
(condInc i (minim == triangle))
22+
(condInc j (minim == pentagon))
23+
(condInc k (minim == hexagon ))
24+
25+
condInc :: Integer -> Bool -> Integer
26+
condInc i c = i + (if c then 1 else 0)

haskell/p046.hs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{-
2+
- Solution to Project Euler problem 46
3+
- Copyright (c) Project Nayuki. All rights reserved.
4+
-
5+
- https://www.nayuki.io/page/project-euler-solutions
6+
- https://github.com/nayuki/Project-Euler-solutions
7+
-}
8+
9+
import qualified EulerLib
10+
11+
12+
main = putStrLn (show ans)
13+
ans = head $ filter (not . satisfiesConjecture) [9, 11 .. ]
14+
15+
satisfiesConjecture :: Integer -> Bool
16+
satisfiesConjecture n = (mod n 2) == 0 || EulerLib.isPrime n ||
17+
any (\i -> EulerLib.isPrime (n - i * i * 2)) (takeWhile (\i -> i * i * 2 <= n) [1 .. ])

haskell/p587.hs

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
{-
2+
- Solution to Project Euler problem 587
3+
- Copyright (c) Project Nayuki. All rights reserved.
4+
-
5+
- https://www.nayuki.io/page/project-euler-solutions
6+
- https://github.com/nayuki/Project-Euler-solutions
7+
-}
8+
9+
10+
{-
11+
- Start by defining the coordinate system in a convenient way. The position and scale of the diagram don't
12+
- matter because we only care about the ratio of areas, not the absolute areas. So, let the bottom left
13+
- of the diagram be the origin (x = 0, y = 0), and let each circle to have a radius of 1.
14+
-
15+
- The leftmost circle is centered at (1, 1), and its equation is (x - 1)^2 + (y - 1)^2 = 1.
16+
- The diagonal line has slope = s = 1 / n (for any positive n), and the line's equation is y = s * x.
17+
- From basic geometry, the area of the blue L-section is 1 - pi / 4.
18+
-
19+
- Let's find the x-coordinate where the diagonal line intersects the first circle.
20+
- Take the equation of the circle and substitute y = s * x for the line:
21+
-
22+
- (x - 1)^2 + (s*x - 1)^2 = 1.
23+
- (x^2 - 2x + 1) + (s^2 x^2 - 2s*x + 1) = 1.
24+
- (1 + s^2)x^2 + (-2 - 2s)x + 1 = 0.
25+
-
26+
- We can apply the quadratic formula with a = 1 + s^2, b = -2 - 2s, c = 1. There are two solutions for x,
27+
- and we only want the smaller value. Thus, let X = (-b - sqrt(b^2 - 4ac)) / (2a). Or equivalently
28+
- with more numerical stability (using the Citardauq formula), X = (2c) / (-b + sqrt(b^2 - 4ac)).
29+
-
30+
- The orange concave triangle can be divided into two parts by a vertical line:
31+
-
32+
- * The left part is a proper triangle, whose area is easily seen as x * y / 2 = X^2 * s / 2.
33+
-
34+
- * The right part is the region between the circle and the baseline. Let's re-express
35+
- the circle's equation in terms of y, and only keep the lower semicircle:
36+
-
37+
- (x - 1)^2 + (y - 1)^2 = 1.
38+
- (y - 1)^2 = 1 - (x - 1)^2.
39+
- y - 1 = -sqrt(1 - (x - 1)^2).
40+
- y = 1 - sqrt(1 - (x - 1)^2).
41+
- y = 1 - sqrt(1 - (x^2 - 2x + 1)).
42+
- y = 1 - sqrt(2x - x^2).
43+
-
44+
- Now, the indefinite integral of f(x) = 1 - sqrt(2x - x^2) with respect to x
45+
- is F(x) = (x - 1) - [sqrt(2x - x^2) * (x - 1) + asin(x - 1)] / 2.
46+
- Finding this integral is not obvious, but verifying it is a fairly straightforward
47+
- mechanical procedure involving differentiation and simplification.
48+
-
49+
- The area of the right part is the integral of f(x) for x from X to 1, because the start is
50+
- the x-coordinate where line meets the circle, and the end is where the circle meets the baseline.
51+
- Hence the area is equal to F(1) - F(X).
52+
-
53+
- All in all, for any given n, the area of the orange concave triangle is X^2 * s / 2 + F(1) - F(X).
54+
- The rest of the algorithm is a brute-force search with n = 1, 2, 3, ... until the ratio condition is met.
55+
-
56+
- Additional notes:
57+
- * Intuitively, as n increases and the slope gets smaller, the area of the orange concave triangle should strictly
58+
- decrease. This statement is in fact true, but proving it involves a big pile of differentiation and algebra.
59+
- 0. We need to show that X (which is the x-coordinate of the line-circle intersection) increases with n.
60+
- We'd differentiate X with respect to n, and get an expression that is always positive for any positive n.
61+
- 1. Because X increases with n, the area of the right part, with its always-positive integrand, must decrease.
62+
- 2. As for the left part, we'd differentiate X^2 * s / 2 with respect to n, and get a huge messy formula.
63+
- It turns out this formula is negative for all n > 1. Hence the area of this triangle also decreases with n.
64+
- After we prove that increasing n leads to decreasing orange area, we could use
65+
- binary search to find the minimum value of n needed to meet the ratio requirement.
66+
- * The use of floating-point arithmetic, for basic arithmetic operations (+ - * /) and irrational functions (sqrt,
67+
- asin) alike, is inherently difficult or impossible to prove the correctness of. Furthermore, the algorithms
68+
- for irrational functions are hard to understand and beyond the scope of this problem, and the error bounds for
69+
- all operations are difficult to reason about.
70+
- It should be possible to solve this particular problem using only integer arithmetic in a provably correct way.
71+
- The basic idea would be to round the result of each operation both down and up to an integer fraction,
72+
- keep track of pessimistic intervals that are guaranteed to contain the true value, accept a comparison only
73+
- if the intervals don't overlap, and recompute everything at a higher precision if a comparison is inconclusive.
74+
- Note: Because it doesn't seem easy to compute pi and asin(), it might be better to
75+
- approximate integrals directly using the Darboux definition of lower and upper sums.
76+
-}
77+
78+
lSectionArea = (1 :: Double) - pi / 4
79+
80+
main = putStrLn (show ans)
81+
ans = head $ filter cond [1 .. ]
82+
83+
cond :: Integer -> Bool
84+
cond i = let
85+
slope = 1.0 / (fromIntegral i)
86+
a = slope**2 + 1
87+
b = -2 * (slope + 1)
88+
c = 1
89+
x = (2 * c) / (-b + (sqrt (b**2 - 4 * a * c)))
90+
concaveTriangleArea = (x**2 * slope / 2) + ((integral 1) - (integral x))
91+
in concaveTriangleArea / lSectionArea < 0.001
92+
93+
integral :: Double -> Double
94+
integral x = let t = x - 1
95+
in t - ((sqrt (x * (2 - x))) * t + (asin t)) / 2

0 commit comments

Comments
 (0)