-- verify 2: given a possible Ramanujan number, generate all its components; -- try to check random failures of computers, on the theory that even if one -- or two sums-of-components get corrupted during a run, there will still be -- something; thus, if the output of this test is the same as the input, -- then there was (probably) no such corruption. module Main where import Text.ParserCombinators.Parsec -- data describing a Ramanujan sum: the Ramanumber, then individual -- components which when cubed and added combine to Ramanumber data Rama = Rama Integer [(Integer,Integer)] deriving Show -- parser for a file containing a bunch of Ramanujan sums: -- this generates a list of Rama objects pair_comp = do oneOf [' ', '\t'] val1 <- many1 digit oneOf [' '] val2 <- many1 digit return ((read val1),(read val2)) rama_line = do sum <- many1 digit pairs <- many1 pair_comp newline return (Rama (read sum) pairs) rama_lines = do lines <- many1 rama_line eof return lines get_rsum (Rama i (xs)) = i -- functions to regenerate the list of components given the Ramanumber -- various things dealing with cube roots cbrt x = floor (0.5 + exp ((1.0/3.0) * log (fromInteger x))) cbrth x = ceiling (exp ((1.0/3.0) * log (0.5*(fromInteger x)))) iscube x = x == ((cbrt x)^3) dif r i = (r, i, (r - i^3)) isc (i,j,k) = iscube k mog (r,i,d) = (r, i, (cbrt d)) srt (i,j,k) = (j < k) {- From right to left: generate a list of integers from 1 to (cube-root of 0.5*Rama-candidate): these are the possible c1 transform this into a list of triples containing filter this list to keep only those where the third component of the triple is a perfect cube: ie, Rama-candidate is a Ramanujan number transform the list of triples to replace the third component with its cube root, ie, the actual c2 we're seeking filter this list to toss out possible corner case where the last pair of components is a repeat of the previous one, but with the components reversed; this is due to taking the ceil in the def'n of cbrth above Done! wasn't that easy? :-} rama_gen x = filter srt (map mog (filter isc (map (dif x) [1 .. cbrth x]))) -- A bunch of stuff to format the output exactly the way that ari* does it. tailOrNot [] = "meh" tailOrNot lst = tail lst gl m a b = a ++ m ++ b gls = gl " " gln = gl "\n" comp1 (i,j,k) = gls (show j) (show k) comp2 l = tailOrNot (foldl gls "" (map comp1 l)) glom [] [] = [] glom (r:rs) (c:cs) = (gl "\t" (show r) c) : glom rs cs main = do input <- getContents let val = case parse rama_lines "stdin" input of Left err -> error $ "Input:\n" ++ show input ++ "\nError:\n" ++ show err Right result -> result ramas = map get_rsum val internal = map comp2 (map rama_gen ramas) display = glom ramas internal putStrLn (foldl gln "Haskell sez:" display)