However, for this problem, I found that in order to apply the algorithm accurately, more than the standard amounts of Double and Int precision were necessary. So, I had to use a FixedPoint package to give me access to 128-bit Integers and 256-bit fixed fractions. The use of these custom data types increased the runtime to about 2 minutes on my machine, but it's still fairly reasonable.
And now that I have "freed up Python", a solution I wrote a while ago will be able to cause the first forward momentum on problems in a long time.
import Data.List
import Data.FixedPoint
import Debug.Trace
-- Replace Double with Rational or with FixedPoint
cfr :: FixedPoint256256 -> (Int -> Int128)
cfr = repindex . cfr_helper
repindex :: ([Int128], Int) -> Int -> Int128
repindex (coeffs, rep) index
| index < (length coeffs) = coeffs !! index
| otherwise = coeffs !! (rep + ((index - (rep)) `mod` ((length coeffs) - rep)))
cfr_helper :: FixedPoint256256 -> ([Int128], Int)
cfr_helper alpha = let a0 = floor alpha in
let alpha1 = alpha - (fromIntegral a0) in
cfr_rec alpha1 [a0, floor (1.0/alpha1)] [alpha1]
cfr_rec :: FixedPoint256256 -> [Int128] -> [FixedPoint256256] -> ([Int128], Int)
gauss_map :: FixedPoint256256 -> FixedPoint256256
gauss_map alpha = (1.0 / alpha) - (fromIntegral (floor(1.0 / alpha)))
fuzzyIndex :: FixedPoint256256 -> [FixedPoint256256] -> Maybe Int
fuzzyIndex _ [] = Nothing
fuzzyIndex x (y:ys)
| abs(x - y) < 1e-5 = Just 0
| otherwise = case (fuzzyIndex x ys) of
Just i -> Just (i + 1)
Nothing -> Nothing
cfr_rec alpha0 as alphas = let alpha1 = gauss_map(alpha0) in
case fuzzyIndex alpha1 alphas of
Just i -> (as,i+1)
Nothing -> cfr_rec alpha1 (as ++ [floor(1.0 / alpha1)]) (alphas ++ [alpha1])
min_soln :: Int -> (Int128,Int)
min_soln d = let coeffs = ((cfr . sqrt' . fromIntegral) d) in
min_soln_rec d (coeffs) (coeffs 0) 1 1 0 1
min_soln_rec :: Int -> (Int -> Int128) -> Int128 -> Int128 -> Int128 -> Int128 -> Int -> (Int128,Int)
min_soln_rec d coeffs p1 q1 p0 q0 n = let an = coeffs n in
let (pn,qn) = (p1 * an + p0, q1 * an + q0) in
if (pn^2 - (fromIntegral d)*qn^2) == 1 then (pn,d)
else min_soln_rec d coeffs pn qn p1 q1 (n+1)
maxSoln :: (Int128,Int) -> (Int128,Int) -> (Int128,Int)
maxSoln (x1,d1) (x2,d2)
| x1 > x2 = (x1,d1)
| otherwise = (x2,d2)
ans :: Int -> Int
isNotSquare :: Int -> Bool
isNotSquare x = let xx = fromIntegral x in (floor (sqrt xx))^2 /= (floor xx)
ans b = snd . foldr maxSoln (0,0) $ map min_soln $ filter isNotSquare [1..b]
main = putStrLn $ show $ ans 1000
No comments:
Post a Comment