Question
A positive fraction whose numerator is less than its denominator is called a proper fraction.
For any denominator, d, there will be d - 1 proper fractions; for example, with d = 12:
\frac{1}{12}, \frac{2}{12}, \frac{3}{12}, \frac{4}{12}, \frac{5}{12}, \frac{6}{12}, \frac{7}{12}, \frac{8}{12}, \frac{9}{12}, \frac{10}{12}, \frac{11}{12}.
We shall call a fraction that cannot be cancelled down a resilient fraction.
Furthermore we shall define the resilience of a denominator, R(d), to be the ratio of its proper fractions that are resilient; for example, R(12) = \frac{4}{11}.
In fact, d = 12 is the smallest denominator having a resilience R(d) < \frac{4}{10}.
Find the smallest denominator d, having a resilience R(d) < \frac{15499}{94744}.
Haskell
import Data.List (union)
import qualified Data.Set as Set
pairwise :: (a -> a -> a) -> [a] -> [a]
:ys:t) = f xs ys : pairwise f t
pairwise f (xs= t
pairwise _ t
primes :: [Int]
= 2 : _Y ((3 :) . gaps 5 . _U . map (\p-> [p*p, p*p+2*p..]))
primes where
= g (_Y g) -- recursion, Y combinator
_Y g :xs):t) = x : (union xs . _U . pairwise union) t -- ~= nub.sort.concat
_U ((x@(x:xs)
gaps k s| k < x = k : gaps (k+2) s -- ~= [k,k+2..]\\s, when
| otherwise = gaps (k+2) xs -- k <= head s && null(s\\[k,k+2..])
factorize :: Int -> [Int]
= primeFactors n primes where
factorize n 1 _ = []
primeFactors = []
primeFactors _ [] :ps) | m < p * p = [m]
primeFactors m (p| r == 0 = p : primeFactors q (p:ps)
| otherwise = primeFactors m ps
where (q, r) = quotRem m p
uniq :: Ord a => [a] -> [a]
= uniq' Set.empty xs where
uniq xs = []
uniq' _ [] :ys) | Set.member y set = uniq' set ys
uniq' set (y| otherwise = y : uniq' (Set.insert y set) xs
totient :: Int -> Double
1 = 1.0
totient = (fromIntegral n) * product [1.0 - (1.0 / (fromIntegral p)) | p <- uniq $ factorize n]
totient n
resilience :: Int -> Double
= (totient d) / (fromIntegral (d - 1))
resilience d
primorials :: [Int]
= scanl1 (*) primes
primorials
candidates :: [Int]
= expand 1 primorials where
candidates @(x:y:_) | m * x < y = m * x : expand (m+1) ps
expand m ps| otherwise = expand 1 (tail ps)
main :: IO ()
= print $ head [d | d <- candidates, resilience d < 15499 / 94744] main
$ ghc -O2 -o resilience resilience.hs
$ time ./resilience
real 0m0.002s
user 0m0.000s
sys 0m0.002s