Welcome, guest! Login / Register - Why register?
Psst.. new poll here.
Psst.. new forums here.
Microsoft is blocking us again (TY IP Reputation!) so dont bother with any of their useless mail servers here and just use oauth login instead. Thank the nice Russians for causing that. :)

Paste

Pasted as Haskell by Minoru ( 15 years ago )
import Data.List (intersperse, zip4, zipWith5, zipWith6)
import Text.Printf (printf)

main :: IO()
main = do
  let points = [-5.0, -3.0, -1.0, 1.0, 3.0]
      ys = map f points

  putStrLn $ unlines $ (interpolate points ys) ++ ["          : 0"]

-- function defined by a variant
f :: Double -> Double
f x = (sin x) + cubeRoot (2*x)

cubeRoot :: Double -> Double
cubeRoot x = signum x * (abs x) ** (1/3)

interpolate :: [Double] -> [Double] -> [String]
interpolate points values = zipWith splineToString [0..(length $ tail values)] $
    computeSplines $ back $ forth $ prepareCoefficients points values
  where
    -- h is a length between two successive points
    hs = zipWith (-) (tail points) points

    -- in:  list of x and y coordinates of knots
    -- out: list of coefficients for three-diagonal matrix (a, c, b, f)
    prepareCoefficients :: [Double] -> [Double] -> [(Double, Double, Double, Double)]
    prepareCoefficients _ ys = zip4 as cs bs fs
      where
        as = 0 : hs
        cs = map (2*) $ zipWith (+) (tail hs) hs -- c = 2(h_i-1 + h_i)
        bs = (tail hs) ++ [0] -- bs starts from second element of hs
        fs = zipWith6 (\a b c d e g -> 6*(((a-b)/c) - (d-e)/g))
                      (drop 2 ys)
                      (tail ys)
                      (tail hs)
                      (tail ys)
                      ys
                      hs

    -- in:  list of (a, c, b, f)
    -- out: list of (alpha, beta) (in reverse order)
    --      first pair in out would be (0, x), where x is x_n - part of a solution
    forth :: [(Double, Double, Double, Double)] -> [(Double, Double)]
    forth coeffs = compAlphaBeta coeffs [(0, 0)]
      where
        compAlphaBeta :: [(Double, Double, Double, Double)] -> [(Double, Double)] -> [(Double, Double)]
        compAlphaBeta [] ac = ac
        compAlphaBeta ((a, c, b, f):cs) ac@((x, y):_) = compAlphaBeta cs ((alpha, beta) : ac)
          where
            -- x and y are alpha and beta for i-1
            alpha = -b/(a * x + c)
            beta  = (f - a * y)/(a * x + c)

    -- in:  list of (alpha, beta) (in reverse order)
    --      first pair in this list would be (_, x), where x is x_n; we should just extract it
    -- out: list of c
    back :: [(Double, Double)] -> [Double]
    back ((_, x_nth):pairs) = compResults pairs [x_nth]
      where
        compResults :: [(Double, Double)] -> [Double] -> [Double]
        compResults [] ac = 0 : ac ++ [0]
        compResults ((a, b):ps) ac@(x_prev:_) = compResults ps ((a * x_prev + b) : ac)

    -- in:  list of c
    -- out: list of (a, b, c, d) -- spline coefficients
    computeSplines :: [Double] -> [(Double, Double, Double, Double)]
    computeSplines s = zip4 as bs cs ds
      where
         as = zipWith3 (\x y z -> (x-y)/(6*z))
                (tail s)
                s
                hs
         bs = map (/2) s
         cs = zipWith5 (\a b c d e -> ((a-b)/c) - ((2*c*d + c*e)/6))
                (tail values)
                values
                hs
                s
                (tail s)
         ds = values

    -- in:  i and (a, b, c, d)
    -- out: string representation of given spline function
    splineToString :: Int -> (Double, Double, Double, Double) -> String
    splineToString i (a, b, c, d)
      | i == 0    = "spline(x) = " ++ eq ++ " \\"
      | otherwise = "          : " ++ eq ++ " \\"
      where
        eq = "x >= " ++ printf "%.0f" (points !! i) ++ " && " ++
             "x < "  ++ printf "%.0f" (points !! (i+1)) ++ " ? "
             ++ smartPrintDouble a ++ "*(x" ++ x_i ++ ")**3"
             ++ smartPrintDouble b ++ "*(x" ++ x_i ++ ")**2"
             ++ smartPrintDouble c ++ "*(x" ++ x_i ++ ")"
             ++ printf "%+.6f" d
        x_i = smartPrintInt $ -(points !! (i+1))


smartPrint :: String -> Double -> String
smartPrint format x
  | x > 0     = " + " ++ printf format x
  | otherwise = " - " ++ (printf format $ abs x)

smartPrintDouble, smartPrintInt :: Double -> String
smartPrintDouble = smartPrint "%.6f"
smartPrintInt = smartPrint "%.0f"

 

Revise this Paste

Your Name: Code Language: