Есть две реализации на хаскель:
{-# LANGUAGE LambdaCase #-}
module Main (main) where
import System.Clock (Clock(ProcessCPUTime), getTime, toNanoSecs)
import System.Environment (getArgs)
import System.Exit (exitFailure)
import Text.Printf (printf)
type Matrix = `Double`
main :: IO ()
main = do
n <- getArgs >>= \case
[a] -> pure (read a)
_ -> exitFailure
let a = newMatrix n
b = newMatrix n
c = newMatrix n
t1 <- clock
let c' = matrixMult n a b c
t2 <- clock
printf "%dns\n" (t2 - t1)
printf "% 8.6f\n" (c' !! (n `div` 2) !! (n `div` 2))
newMatrix :: Int -> Matrix
newMatrix n =
let tmp = 1 / fromIntegral n / fromIntegral n in
[ [ tmp * (i - j) * (i + j)
| j <- [0 .. fromIntegral (pred n)]
]
| i <- [0 .. fromIntegral (pred n)]
]
matrixMult :: Int -> Matrix -> Matrix -> Matrix -> Matrix
matrixMult n a b _ =
let t = [ [ b!!j!!i
| j <- [0 .. pred n]
]
| i <- [0 .. pred n]
]
c = [ [ sum [ a!!i!!k * t!!j!!k | k <- [0 .. pred n] ]
| j <- [0 .. pred n]
]
| i <- [0 .. pred n]
]
in c
matrixPrint :: Int -> Matrix -> String
matrixPrint _ = unlines . fmap (unwords . fmap (printf "% 8.6f")
clock :: IO Integer
clock = toNanoSecs <$> getTime ProcessCPUTime
{-# LANGUAGE LambdaCase #-}
module Main (main) where
import System.Clock (Clock(ProcessCPUTime), getTime, toNanoSecs)
import System.Environment (getArgs)
import System.Exit (exitFailure)
import Text.Printf (printf)
import Data.Array.Unboxed
import Data.Array.IO
import Data.Array.Base
import GHC.Arr (unsafeIndex)
-- Matrix multiplication benchmark
type Matrix = UArray (Int, Int) Double
main :: IO ()
main = do
[n] <- getArgs >>= \case
[a] -> pure ([read a :: Int])
_ -> exitFailure
t1 <- clock
let a = newMatrix n
b = newMatrix n
let c' = matrixMult a $ transpose b
printf "% 8.6f\n" (c' ! ((n `div` 2), (n `div` 2)) )
t2 <- clock
printf "%ds\n" $ (t2 - t1) `div` 1000000000
newMatrix :: Int -> Matrix
newMatrix n =
let tmp = 1 / fromIntegral n / fromIntegral n :: Double in
array ((0, 0), (pred n, pred n))
[((i,j), tmp * fromIntegral(i - j) * fromIntegral (i + j))
| i <- range (0, pred n),
j <- range (0, pred n) ]
transpose :: Matrix -> Matrix
transpose x = array resultBounds [((j,i), x!(i,j))
| i <- range (li,ui),
j <- range (lj,uj) ]
where ((li,lj),(ui,uj)) = bounds x
resultBounds = ((lj,li),(uj,ui))
matrixMult :: Matrix -> Matrix -> Matrix
matrixMult x y = array resultBounds [((i,j),
let basei = rowIndex x i
basej = rowIndex y j
in sum [unsafeAt x ( basei + k ) * unsafeAt y ( basej + k )
| k <- range (lj,uj) ]
)
| i <- range (li,ui),
j <- range (li',ui') ]
where ((li,lj),(ui,uj)) = bounds x
((li',lj'),(ui',uj')) = bounds y
resultBounds | (lj,uj)==(lj',uj') = ((li,li'),(ui,ui'))
| otherwise = error "matMult: incompatible bounds"
rowIndex arr n = index (bounds arr) (n,0)
clock :: IO Integer
clock = toNanoSecs <$> getTime ProcessCPUTime
Есть код на C++:
#include <range/v3/view.hpp>
#include <range/v3/numeric/inner_product.hpp>
#include <chrono>
using namespace ranges::view;
int main(int argc, char * argv[]) {
size_t N = 3000;
if(argc > 1) N = std::atol(argv[1]);
auto matrix = [](size_t n) {
return iota(0ul, n * n) | transform([n, tmp = 1. / n / n](auto x) {
ssize_t i = x / n, j = x % n;
return tmp * (i - j) * (i + j);
});
};
auto a = matrix(N), b = matrix(N);
auto column = [N](const auto & m, size_t n) {
return slice(m, n, m.size()) | stride(N);
};
auto row = [N](const auto & m, size_t n) {
return slice(m, n * N, n * N + N);
};
auto mul = [=](const auto & a, const auto & b) {
return iota(0ul, N) | transform([=](auto i) {
return iota(0ul, N) | transform([=](auto j) {
return ranges::inner_product(row(a, i), column(b, j), 0.);
});
});
};
auto start = std::chrono::high_resolution_clock::now();
auto c = mul(a, b);
auto time = std::chrono::high_resolution_clock::now() - start;
fprintf(stderr, "%luns\n", size_t(std::chrono::duration_cast<std::chrono::nanoseconds>(time).count()));
fprintf(stderr, "%f\n", c[N/2][N/2]);
}
Собирать код так:
$ git clone github.com/ericniebler/range-v3.git
$ g++ main.cpp -std=gnu++2a -march=native -Ofast -fwhole-program -funroll-all-loops -fconcepts -Irange-v3/include -o cpp
//либо
$ clang++ main.cpp -std=gnu++2a -march=native -Ofast -Irange-v3/include -o cpp
$ ghc main.hs -o hs
Запускать так:
$ time ./cpp 123
61ns
-11.620506
real 0m0,001s
user 0m0,000s
sys 0m0,001s
$ time ./hs 123
-11.620506
0s
real 0m0,152s
user 0m0,146s
sys 0m0,005s
Нужно запустить и написать сюда результаты. Так же, желательно дать оценки коду(по мотивам троек).