Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Религиозные войны > Попытка сравнить C/Java/C#/Python


Автор: APM 21.1.2008, 14:28
Вот решил попробовать сравнить эти языки. 
Сравнение проводилось на основе времени, которое требуется для сортировки 10000 случайных элементов методом пузырька.
С/С++ - 0,330 сек.
Python - 42 сек
Java - 0,515 сек (код для сортировки даже переписывать не пришлось)
С# - .NET 3.5 - 0,350 сек. 

Результаты довольно странные, получается что С# лишь немного хуже C, а Python отстает почти на два порядка.
Попробуем запустить эту же программу, но увеличим число элементов до 100000, Python естественно не участвует :(
С/С++ - 27,6 сек.
Java - 37,7 сек.
C# - 32, 5 сек.

Для меня такие результаты оказались неожиданность, уж никак не ожидал что на такой задаче С# будет таким шустрым, а Питон так провалится.

У кого какие мнения? =)

Автор: LSD 21.1.2008, 14:36
Цитата(APM @  21.1.2008,  14:28 Найти цитируемый пост)
У кого какие мнения? =)

1. Есть специальный раздел для тестов.
2. Без исходников, конфигурации и версий компиляторов это не тест, а баловство.

Автор: mr.DUDA 21.1.2008, 14:38
Поддерживаю предыдущего оратора  smile 

Автор: APM 21.1.2008, 15:23
C++ - компилятор из MSVS 2008 Express
C# - .NET 3.5
Java - Jre 1.6
Python - 2.5

Core 2 Duo T5500, 1Gb Ram

Автор: Ch0bits 21.1.2008, 16:11
Блин, сортировка пузырьком, не смешите мои подковы!  smile  smile 

Автор: Lazin 21.1.2008, 16:18
Питоном что запускал .py или .pyc? И вообще нечего сравнивать по скорости питон и С++(или любой другой язык со статической типизацией), это всеравно что палец известно с чем сравнивать)). У питона другие задачи.

Автор: MAKCim 21.1.2008, 17:45
APM, 
вот сортировка на Python
Код

sorted([randint(0, 0xFFFFFFFF) for x in xrange(0, 10000)])

0.04 секунд
Linux (x86-64, 2.6.18), CPU = C2D 1.86Ghz, PVM 2.5
 smile 

Автор: APM 21.1.2008, 17:54
Я не пытался выполнить сортировку как можно было быстрее, поэтому выбрал самый плохой для этого алгоритм. Затем код был одинаково написан для четырех языков. В итоге получились такие результаты. Я не пытался использовать "фишки", доступные для конкретного языка.

Автор: Void 21.1.2008, 18:24
Может мы хотя бы код увидим...

Автор: Sardar 21.1.2008, 18:54
Вы бы ещё сюда Haskell со строковыми и monadic I/O приписали  smile 
Простые истины (из пальца smile ):
  • пустая итерация в миллиард раз (к примеру инкремент целого) - быстрей на асме (при условии что итерация реально выполняется). 
  • фильтрация растровой картинки, представленной массивом пикселей быстрей на C
  • работа с массой строковых операций, юникод, без лимитов на размеры и беря во внимание лень программиста - вероятно PHP6/Java/C#. Да, на C можно быстро, но все тупо копируют байтовые массивы ;-)
  • собрать огромное DOM дерево с массой дополнительных интерфейсов, в итоге граф так на 10.000 нод - однозначно все со сборщиком мусора, т.е. Java/C#
  • IDE с массой взможностей, анализ кода на лету, плагины и т.д. (читаем NetBeans6) - однозначно Java/C#. Кто не уверен, запускайте NetBeans6 - штука реактивная.
  • парсеры, текстовы ввод (гибкость/скорость) - вероятно OCaml, Perl6
Всё упирается в лень программиста, если он робот, то и на ASM'е сможет шустрый Mozilla/FireFox написать (шанс нулевой, от лени будет пользоваться простейшими алгоритмами, в итоге будет тормозить). Сейчас лиса до жути задумчива, аргумент против C++ (за работу с памятью). Чем меньше оптимизированных решений в языке (алгоритмы), тем более отвратный софт в итоге. 

Автор: Mayk 21.1.2008, 19:12
Цитата(Sardar @  21.1.2008,  22:54 Найти цитируемый пост)
# парсеры, текстовы ввод (гибкость/скорость) - вероятно OCaml, Perl6

Более разумно использовать генераторов этих самых парсеров[привет, antlr и yacc]. 
Менять ради одной подзадачи язык — не очень здравая идея имхо.

Тем более что генераторы парсеров есть почти для всех языков. Ну для c,c++,java точно есть.

Автор: Void 21.1.2008, 19:13
Цитата(Sardar @  21.1.2008,  20:54 Найти цитируемый пост)
итерация в миллиард раз быстрей на асме (при условии что итерация реально выполняется). 

Неудачно предложение построил, я полминуты где-то пытался понять, откуда такое фантастическое быстродействие smile

Добавлено через 3 минуты и 29 секунд
Цитата(Mayk @  21.1.2008,  21:12 Найти цитируемый пост)
Менять ради одной подзадачи язык — не очень здравая идея имхо.

Подзадачи — да, если задача в целом связана с синтаксическим анализом, why бы и not.

Автор: Lazin 21.1.2008, 19:37
Невсегда важно быстродействие, иногда(почти всегда) важнее скорость разработки,масштабируемость, надежность. 
я этим посто кагбы открыл всем глаза на реальне положение дел в программировании 

Автор: Sardar 21.1.2008, 20:30
Цитата(Void @  21.1.2008,  18:13 Найти цитируемый пост)
Неудачно предложение построил, я полминуты где-то пытался понять, откуда такое фантастическое быстродействие

Точно, изменил smile

Цитата(Mayk @  21.1.2008,  18:12 Найти цитируемый пост)
Более разумно использовать генераторов этих самых парсеров[привет, antlr и yacc].

Помимо самого анализа нужно ещё и представление AST/других структур, манипуляции с ними и т.д.  Да хотя бы имея http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%B5%D0%B1%D1%80%D0%B0%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D1%82%D0%B8%D0%BF_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85 уже проще строить деревья и т.п.

Автор: Mayk 21.1.2008, 21:31
Цитата(Sardar @  22.1.2008,  00:30 Найти цитируемый пост)

Помимо самого анализа нужно ещё и представление AST/других структур, манипуляции с ними и т.д.  Да хотя бы имея алгебраические  типы уже проще строить деревья и т.п. 

 smile 

Автор: Sardar 21.1.2008, 22:31
Когда то http://forum.vingrad.ru/forum/topic-77053/unread-1/anchor-entry621247/15.html было. По началу немного сумбурно, тема была вырезана из другого топа smile

Лаба из прошлого блока, читает и выполняет FEM - простейший абстрактный функциональный язык (всего три операции). На вкус отвратна (специально без оптимизаций, учили рекурсию и partial application функций), писалась после первых недель знакомства с Haskell, но принцип понять можно smile
Код
{---------------------------------------------
 - FEM language implementation
 - Sardar Yumatov (1679848) and others (1609874)
 -
 - Usage: showw (parseFEMProgram FEM_Code >>= eval)
 - Example: showw (parseFEMProgram "foo a bb = a, ((T foo S P)) 5 6 7" >>= eval)
 ---------------------------------------------}
module FEM where
import List
import Char


type FemGetal = Int                -- Fem deals with numbers only
type FemVariabele = String            -- Any identifier
type CodePosition = (Int,Int)            -- Term position in the source file, can be extended with file name later



-- собсно AST, без лишних классов
---------- Parsed program representation --------------
data FemTerm =
      S            -- increment, native function
    | P            -- decrement, native function
    | T            -- test (if-else), native function
    | N FemGetal        -- constant (integer) value
    | V FemVariabele    -- recall variable
    | L [FemParsedTerm]    -- execute (apply) variable (function)


type FemParsedTerm = (FemTerm, CodePosition)                -- term annotated with position in source code
type FemDeclaratie = (FemVariabele, (CodePosition, [FemVariabele], FemParsedTerm))    -- function declaration
type FemProg = ([FemDeclaratie], FemParsedTerm)                -- FEM program definition


---------- Token stream (tokenizer) ------------------
data Token = HOpen | HClose | Comma | Equal | Natural FemGetal | Variable String | PToken | TToken | SToken
type TokenStream = [(Token, CodePosition)]


---------- Runtime program representation ------------
data FemRuntimeTerm =
      NR FemGetal                                            -- primitive value
    | LR CodePosition [FemArgument] [FemParsedTerm]                            -- dellayed L term
    | FR String CodePosition [FemArgument] [FemVariabele] (Either FemParsedTerm FemSystemCallback)    -- partially applied function

-- Lookup must not be a stack, the context always consist of top-level functions and current arguments set
type ContextLookup = ([FemDeclaratie], [FemArgument])
type FemArgument = (FemVariabele, FemRuntimeTerm)

-- Native function callback.
type FemSystemCallback = [FemDeclaratie] -> [FemArgument] -> (Result FemRuntimeTerm)



----------------- Error handling -----------------------
-- Result of any evaluation (Maybe like type, extended with error messages)
data Result a = Error String | Success a

-- Allows chaining multiple (a -> Result a) together
instance Monad Result where
    Error  msg >>= f = Error msg
    Success rs >>= f = f rs
    Error  msg >> _  = Error msg
    _ >> Error msg   = Error msg
    Success a  >> Success b = Success b
    return          = Success
    fail msg        = Error msg

------------------- Pretty prints --------------------
class Source a where
    toSource :: a -> String

instance Show FemTerm where
    show a = toSource a

instance Source FemTerm where
    toSource S               = "S"
    toSource P               = "P"
    toSource T               = "T"
    toSource (N n)           = "N " ++ (show n)
    toSource (V str)         = "V " ++ str
    toSource (L trms)        = "(" ++ concat (intersperse " " (map (toSource.fst) trms)) ++ ")"

instance Show Token where
    show HOpen          = "_(_"
    show HClose         = "_)_"
    show Comma          = ", "
    show Equal          = " = "
    show PToken         = "p "
    show TToken         = "t "
    show SToken         = "s "
    show (Natural int)  = "@" ++ (show int)
    show (Variable str) = "$" ++ str

-- for debugging only
instance Show FemRuntimeTerm where
    show (NR n) = "NR " ++ (show n)
    show (LR p ctx trms) = "(" ++ concat (intersperse " " (map show trms)) ++ ")"
    show (FR nm p args ac func) = "Func: " ++ nm


-- Convert compiled FEM program to source
toSourceProgram :: FemProg -> String
toSourceProgram (xs, (term, q)) = ("(\n\t" ++ (concat (intersperse ",\n\t" (map toSourceDecl xs))) ++ "\n,\n\t" ++ (toSource term))
    where    toSourceDecl (name, (cp, xs, term)) = (name ++ " " ++ (concat (intersperse " " xs)))

-- Retrive from Result monad
showw :: (Show a) => (Result a) -> String
showw (Success foo) = (show foo)
showw (Error foo) = (show foo)

-- Print term position. Used in error messages.
showPosition (a, b) = "L" ++ (show a) ++ ":C" ++ (show b)





--------------------------- Parser -----------------------------
-- Parse FEM program into an exutable
parseFEMProgram :: String -> Result FemProg
parseFEMProgram code = tokenize code >>= trimBrackets >>= shredTokens >>= parseParts
    where    parseParts (decl, term) = parseDeclarations ([], decl) >>= parseTerm term
        parseTerm term (decls, []) = parseTermStream term >>= assembleProgram decls
        assembleProgram decls (term, []) = return (decls, term)
        assembleProgram decls (term, (x:strm)) = fail ("Unexpected input after closing ')' at the end of the program: " ++ (show x))
        trimBrackets ((HOpen, p):ts) =
                       case reverse ts of
                               ((HClose,p):tts) -> return (reverse tts)
                               (tts)            -> fail "Global ) at the end of the code is required!"
        trimBrackets ts = return ts


-- Split FEM source code to tokens.
-- This function will parse the whole string at once (no lazy evaluation), in return
-- the function will fail correctly if given FEM code contains syntax errors.
tokenize :: String -> Result TokenStream
tokenize src = tryNextToken ([], (0,0), src) >>= returnStream
    where    returnStream (toks, p, rest) = return toks
        tryNextToken (toks, p, []) = return (toks, p, [])
        tryNextToken (toks, p, xs) = (nextToken p xs >>= addTok) >>= tryNextToken
            where    addTok (tok, pp, pn, rest) = return (toks ++ [(tok, pp)], pn, rest)

-- Read next token
nextToken :: CodePosition -> String -> Result (Token, CodePosition, CodePosition, String)
nextToken p@(r,c) (x:xs)
    | x == '='               = return (Equal, p, (r, c+1), xs)
    | x == '('               = return (HOpen, p, (r, c+1), xs)
    | x == ')'               = return (HClose, p, (r, c+1), xs)
    | x == ','               = return (Comma, p, (r, c+1), xs)
    | x == '\n'              = nextToken (r+1, 0) xs
    | elem x "\t \r"           = nextToken (r, c+1) xs
    | isAlpha x || isDigit x = tryToken p (break (not.isAlphaNum) (x:xs))
    | otherwise            = fail ("Not a valid FEM token. Unexpected: " ++ [x])


-- Try to parse a Variable, Natural, P, S or T Token from a String.
tryToken :: CodePosition -> (String, String) -> Result (Token, CodePosition, CodePosition, String)
tryToken p@(r,c) (term, rest)
    | term == "p" || term == "P" = return (PToken, p, (r, c+1), rest)
    | term == "s" || term == "S" = return (SToken, p, (r, c+1), rest)
    | term == "t" || term == "T" = return (TToken, p, (r, c+1), rest)
    | all isDigit term           = return (Natural (read term), p, (r, c+(length term)), rest)
    | isAlpha (head term)        = return (Variable term, p, (r, c+(length term)), rest)
    | otherwise                  = fail ("Not a valid number: " ++ term)



-- Split token stream to program declarations and the main term.
shredTokens :: TokenStream -> Result ([TokenStream], TokenStream)
shredTokens (x:xs) = return (decl, term)
    where    (term:decl) = map reverse (shred (reverse (x:xs)))
        shred [] = []
        shred ((Comma, p):ts) = shred ts    -- so (decl, , , term) is allowed, commas are ignored
        shred ts = y : shred ys
            where    (y, ys) = break isComma ts
                isComma (Comma, p) = True
                isComma _          = False


-- Parse list of variable declarations
parseDeclarations :: ([FemDeclaratie], [TokenStream]) -> Result ([FemDeclaratie], [TokenStream])
parseDeclarations (dcl, []) = return (dcl, [])
parseDeclarations (dcl, (s:sms)) = parseDeclaration s >>= addDeclaration
       where   addDeclaration decl = (return (decl:dcl, sms)) >>= parseDeclarations



-- Parse FEM declaration (variable)
parseDeclaration :: TokenStream -> Result FemDeclaratie
parseDeclaration []  = fail "Software bug detected: empty variable declaration. Probably parser's (shredTokens) error!"
parseDeclaration str = possibleBrakets str >>= combineResults
    where    combineResults ((nm,p), arg, term, []) = return (nm, (p, arg, term))
        combineResults ((nm,pp), arg, term, ((t,p):ts)) = fail ((showPosition p) ++ " - Unexpected token after closing ')' of variable declaration: " ++ nm)

        possibleBrakets ((HOpen, p):ts) = (parseDecl p ts) >>= expectClose    -- consume (
        possibleBrakets ((t,p):ts) = parseDecl p ((t,p):ts)                -- no brakets variant

        expectClose (n,a,t,[(HClose,p)]) = return (n,a,t,[])        -- consume )
        expectClose ((n,p),a,t,[]) = fail ((showPosition p) ++ " - Expecting ')' at the end of variable declaration: " ++ n)
        expectClose ((n,pp),a,t,((o,p):ts)) = fail ((showPosition p) ++ " - Expecting only ')' at the end of variable declaration: " ++ n)

        parseDecl p [] = fail ((showPosition p) ++ " - Expecting variable declaration, but there is no more terms.")
        parseDecl p ts = parseName ts >>= parseArguments >>= parseBody

        parseName (((Variable nm), p):str) = return ((nm,p), str)
        parseName ((t,p):xs) = fail ((showPosition p) ++ " - fuck Expecting variable name, got: " ++ (show t))

        parseArguments ((n, p), str) = nextArgument ([], str) >>= combineArg
            where    combineArg (arg, ts) = return ((n,p), arg, ts)
                nextArgument (arg, []) = fail ((showPosition p) ++ " - Expecting body for variable: " ++ n)
                nextArgument (arg, (((Variable nm), p):ts)) = (return (arg ++ [nm], ts)) >>= nextArgument
                nextArgument (arg, ((Equal, p):ts)) = return (arg, ts)
                nextArgument (arg, ((t, pt):ts)) = fail ((showPosition pt) ++ " - Expecting variable name or '=', got: " ++ (show t))

        parseBody ((n,p), a, []) = fail ((showPosition p) ++ " - Expecting body (code) for variable: " ++ n)
        parseBody (n, a, str) = parseTermStream str >>= returnBody
            where    returnBody (term, rest) = return (n, a, term, rest)


-- Parse FEM term (program body)
parseTermStream :: TokenStream -> Result (FemParsedTerm, TokenStream)
parseTermStream [] = fail "Software bug detected: no input for parseTermStream!"
parseTermStream str = parseSingleTerm ([], str) >>= optimizeNesting
    where    optimizeNesting (tt@((t, p):trs), ts) = return (optimizeList (L tt, p), ts)
        parseSingleTerm (trms, [])                   = return (trms, [])
        parseSingleTerm (trms, ((Natural n, p):ts))  = return (trms ++ [(N n,p)], ts) >>= parseSingleTerm
        parseSingleTerm (trms, ((Variable n, p):ts)) = return (trms ++ [(V n,p)], ts) >>= parseSingleTerm
        parseSingleTerm (trms, ((PToken, p):ts))     = return (trms ++ [(P,p)], ts)   >>= parseSingleTerm
        parseSingleTerm (trms, ((TToken, p):ts))     = return (trms ++ [(T,p)], ts)   >>= parseSingleTerm
        parseSingleTerm (trms, ((SToken, p):ts))     = return (trms ++ [(S,p)], ts)   >>= parseSingleTerm
        parseSingleTerm (trms, ((Equal, p):ts))      = fail ((showPosition p) ++ " - Unexpected '=', probably ',' is missing.")
        parseSingleTerm (trms, ((HClose, p):ts)) = return (trms, ts)
        parseSingleTerm (trms, ((HOpen, p):ts)) = parseSingleTerm ([], ts) >>= addTermList >>= parseSingleTerm
            where    addTermList (trs, rest) = return (trms ++ [(L trs, p)], rest)

        --parseSingleTerm (trms, ((t,p):ts)) = fail ((showPosition p) ++ " - Software bug detected. Unexpected token: " ++ (show t))

        optimizeList ((L [x]), q)                = (optimizeList x)
        optimizeList ((L xs ), q)                = ((L (map optimizeList xs)), q)
        optimizeList (x, q)                      = (x, q)




------------------------------------ FEM Runtime --------------------------------------------
-- Evaluate program. The result will be an number or error message.
eval :: FemProg -> Result FemGetal
eval (decl, term) = evaluableTerm (decl, []) term >>= execTerm decl >>= evalTerm
    where    evalTerm (NR n) = return n
        evalTerm (FR n p a ac f) = fail ("Can't execute partially applied function: " ++ n ++ ", expecting arguments: " ++ (concat $intersperse ", " ac))
        evalTerm d = fail "Software bug detected: not number nor partial function in evalTerm!"


-- Convert an expression to evaluable object (lazy evaluation).
evaluableTerm::ContextLookup->FemParsedTerm->Result FemRuntimeTerm
evaluableTerm _  (S,p)               = return (FR "S" p [] ["arg"] (Right femNative_S))    -- introduce natives
evaluableTerm _  (P,p)               = return (FR "P" p [] ["arg"] (Right femNative_P))
evaluableTerm _  (T,p)               = return (FR "T" p [] ["arg","true","false"] (Right femNative_T))
evaluableTerm _  ((N n), p)          = return (NR n)        -- introduce primitive constant
evaluableTerm _  ((L []), p)         = fail ((showPosition p) ++ " - Empty group ()")
evaluableTerm (f,a) ((L (t:trms)),p) = return (LR p a (t:trms))
evaluableTerm (f,a) ((V name), p)    =
    case (lookup name a) of
        Just term    -> return term                            -- inject partially applied function
        Nothing    -> case lookup name f of
            (Just (pf, arg, term))    -> return (FR name pf [] arg (Left term))    -- introduce top level function
            Nothing            -> fail ((showPosition p) ++ " - Variable not found: " ++ name)


{- Execute delayed/lazy term
 - Function will terminate with either primitive value or partially applied FEM variable. -}
execTerm::[FemDeclaratie]->FemRuntimeTerm->Result FemRuntimeTerm
execTerm _ d@(NR n) = return d                    -- primitive value
execTerm flc (LR p alc (lamfunc:args)) = evaluableTerm (flc,alc) lamfunc >>= evaluableLambda args >>= execTerm flc
    where    evaluableLambda [] r = return r    -- L [ single term ] => single term
        evaluableLambda (t:ts) (NR n) = fail ((showPosition p) ++ " - Variable with at least one parameter expected, but got primitive: " ++ (show n))
        evaluableLambda (t:ts) (FR nm p arg (a:ags) f) = evaluableTerm (flc,alc) t >>= addArgument >>= evaluableLambda ts    -- fill in arguments. for partial application the function runs in own context, while arguments are from current context
            where    addArgument rt = return (FR nm p ((a,rt):arg) ags f)
        evaluableLambda (t:ts) trm = execTerm flc trm >>= evaluableLambda (t:ts)    -- full FR or L term, evaluate and apply the rest of arguments

execTerm _ d@(FR nm p ctx (a:as) func) = return d    -- partially applied function
execTerm flc (FR nm p ctx [] func) = applyFunc func    -- until either primitive val or partially applied func
    where    applyFunc (Left term) =
            case evaluableTerm (flc,ctx) term of
                Success term    -> execTerm flc term
                Error msg    -> Error (msg ++ "\n" ++ (showPosition p) ++ " - Failed to execute: " ++ nm)

        applyFunc (Right term) = 
            case term flc ctx of
                Error msg -> Error (msg ++ "\n       - Executed at: " ++ (showPosition p))
                Success val -> execTerm flc val    -- usually NR n






----------------------- Native bindings -------------------------
-- Increment
femNative_S :: FemSystemCallback
femNative_S lk [(a,t)] = execTerm lk t >>= updateWaarde
    where    updateWaarde (NR n) = return (NR (n+1))        -- direct execute
        updateWaarde d@(FR n p a ac f) = return (FR "<anonymous>" (-1,-1) [] ac (Right (femLambda [] (femNative_S lk) d)))

-- Decrement
femNative_P :: FemSystemCallback
femNative_P lk [(a,t)] = execTerm lk t >>= updateWaarde
    where    updateWaarde (NR 0) = return (NR 0)        -- direct execute
        updateWaarde (NR n) = return (NR (n-1))
        updateWaarde d@(FR n p a ac f) = return (FR "<anonymous>" (-1,-1) [] ac (Right (femLambda [] (femNative_P lk) d)))

-- Test (not)
femNative_T :: FemSystemCallback
femNative_T lk args = execTerm lk (takejust (lookup "arg" args)) >>= executeT -- executeT (takejust (lookup "arg" args)) -- 
    where    executeT (NR 0) = return taakTrue
        executeT (NR n) = return taakFalse
        executeT d@(FR n p a ac f) = return (FR "<anonymous>" (-1,-1) [] ac (Right (femLambda args (femNative_T lk) d)))
        taakTrue = takejust (lookup "true" args)
        taakFalse = takejust (lookup "false" args)
        takejust (Just n) = n


-- Native lambda, used to wrap native (black-box) functions
femLambda oargs nat (FR n p a ac f) lk args = (return (FR n p (a++args) [] f)) >>= execTerm lk >>= execNative >>= nat
    where    execNative rt = return ([("arg", rt)] ++ oargs)



Это простейший LL(1) парсер-интерпретатор + пара debug функций.  Коррктно выводит контекст ошибки (parsing, runtime) и т.п. отсюда много кода. Просто парсер укладывается в пару десятков строк. Кстати пример как реализуются не типичные для чистых декларативных языков последовательные операции посредством монад.

Автор: mr.DUDA 21.1.2008, 22:47
Какой кошмарный язык. Напомнило мне времена когда не зная ничего кроме бейсика пытался вникнуть в примеры из книги Страуструпа...

Автор: Real 18.4.2008, 20:41
Цитата(LSD @ 21.1.2008,  14:36)
Цитата(APM @  21.1.2008,  14:28 Найти цитируемый пост)
У кого какие мнения? =)

1. Есть специальный раздел для тестов.
2. Без исходников, конфигурации и версий компиляторов это не тест, а баловство.

Где этот раздел?

Автор: Ch0bits 18.4.2008, 21:23
http://forum.vingrad.ru/forum/Testing.html

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)