Кот: оцените плз

kruzer25

Неполное решение вот этой задачи: http://acm.timus.ru/problem.aspx?space=1&num=1438 (неполное, потому что пока что ещё не разбирался с тем, как оно должно работать при отрицательных значениях).
Как вы думаете, усвоил ли я что-нибудь из принципов C# и .NET за те полтора месяца, которые с ними работаю? На эту конкретную задачу в общей сложности было потрачено около одного рабочего дня.
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace CodeRunner {




internal class Util {

public static T[] ArraySlice<T>(T[] Source, int Offset, int Count) {

if(Offset < 0) Offset = Source.Length - Offset;
if(Count <= 0) Count = Source.Length - Offset + Count;

T[] Result = new T[Count];
Array.Copy(Source, Offset, Result, 0, Count);
return Result;
}

public static T[] ArraySlice<T>(T[] Source, int Offset) {
return ArraySlice<T>(Source, Offset, 0);
}
}



internal class Variable {

private UInt32 Value;

public Variable(UInt32 Value) {
this.Value = Value;
}

public override string ToString {
return this.Value.ToString;
}

public bool IsTrue {
return this.Value != 0;
}

public static Variable Not(Variable Var) {
return new Variable(~ Var.Value);
}

public static Variable Copy(Variable Var) {
return Var;
}

public static Variable Plus(Variable Var1, Variable Var2) {
return new Variable(Var1.Value + Var2.Value);
}

public static Variable Minus(Variable Var1, Variable Var2) {
return new Variable(Var1.Value - Var2.Value);
}

public static Variable Mul(Variable Var1, Variable Var2) {
return new Variable(Var1.Value * Var2.Value);
}

public static Variable Div(Variable Var1, Variable Var2) {
return new Variable(Var1.Value / Var2.Value);
}

public static Variable Mod(Variable Var1, Variable Var2) {
return new Variable(Var1.Value % Var2.Value);
}

public static Variable Or(Variable Var1, Variable Var2) {
return new Variable(Var1.Value | Var2.Value);
}

public static Variable And(Variable Var1, Variable Var2) {
return new Variable(Var1.Value & Var2.Value);
}

public static Variable Xor(Variable Var1, Variable Var2) {
return new Variable(Var1.Value ^ Var2.Value);
}

private static Variable CreateFromBool(bool Value) {
return Value ? (new Variable(1 : (new Variable(0;
}

public static Variable Eq(Variable Var1, Variable Var2) {
return CreateFromBool(Var1.Value == Var2.Value);
}

public static Variable NE(Variable Var1, Variable Var2) {
return CreateFromBool(Var1.Value != Var2.Value);
}

public static Variable GT(Variable Var1, Variable Var2) {
return CreateFromBool(Var1.Value > Var2.Value);
}

public static Variable GE(Variable Var1, Variable Var2) {
return CreateFromBool(Var1.Value >= Var2.Value);
}

public static Variable LT(Variable Var1, Variable Var2) {
return CreateFromBool(Var1.Value < Var2.Value);
}

public static Variable LE(Variable Var1, Variable Var2) {
return CreateFromBool(Var1.Value <= Var2.Value);
}

}




internal class Variables {

private Dictionary<string, Variable> Storage;

public Variables {
this.Storage = new Dictionary<string,Variable>
}

public Variable GetVariable(string Name) {
return this.Storage[Name];
}

public void SetVariable(string Name, Variable Value) {
this.Storage[Name] = Value;
}

}




internal abstract class VarNum {

abstract public Variable GetVariable(Variables Data);

public static VarNum CreateByString(string Word) {
if(Regex.IsMatch(Word, "^-?\\d+$" {
return new VarNum_Number(Word);
} else {
return new VarNum_Variable(Word);
}
}

private class VarNum_Variable : VarNum {

private string Name;

public VarNum_Variable(string Name) {
this.Name = Name;
}

public override Variable GetVariable(Variables Data) {
return Data.GetVariable(this.Name);
}

}

private class VarNum_Number : VarNum {

private string Num;

public VarNum_Number(string Number) {
this.Num = Number;
}

public override Variable GetVariable(Variables Data) {
return new Variable(UInt32.Parse(Num;
}
}

}




internal abstract class Calculation {

abstract public Variable Calculate(Variables Data);

public static Calculation CreateByString(string[] Words) {

if(Words.Length == 1) {
return new Calculation1(Calculation1.COPY, VarNum.CreateByString(Words[0];
} else if(Words.Length == 2) {
return new Calculation1(Calculation1.Creator.Instance.Operator2Type[Words[0].ToLower], VarNum.CreateByString(Words[1];
} else if(Words.Length == 3) {
return new Calculation2(Calculation2.Creator.Instance.Operator2Type[Words[1].ToLower], VarNum.CreateByString(Words[0] VarNum.CreateByString(Words[2];
} else {
throw new ApplicationException("Unknown calculation '" + String.Join(" ", Words) + "'");
}
}

private class Calculation1 : Calculation {

public static readonly Func<Variable, Variable> NOT = Variable.Not;
public static readonly Func<Variable, Variable> COPY = Variable.Copy;

private static readonly Dictionary<string, Func<Variable, Variable>> Operator2Type = new Dictionary<string,Func<Variable,Variable>> {
};

private Func<Variable, Variable> Type;

private VarNum Var1;

public Calculation1(Func<Variable, Variable> Type, VarNum Var1) {
this.Type = Type;
this.Var1 = Var1;
}

public override Variable Calculate(Variables Data) {
return this.Type(this.Var1.GetVariable(Data;
}

public class Creator {

public static readonly Creator Instance = new Creator;

public readonly Dictionary<string, Func<Variable, Variable>> Operator2Type;

private Creator {

this.Operator2Type = new Dictionary<string, Func<Variable, Variable>>

this.Operator2Type["not"] = NOT;
}

}

}

private class Calculation2 : Calculation {

public static readonly Func<Variable, Variable, Variable> PLUS = Variable.Plus;
public static readonly Func<Variable, Variable, Variable> MINUS = Variable.Minus;
public static readonly Func<Variable, Variable, Variable> MUL = Variable.Mul;
public static readonly Func<Variable, Variable, Variable> DIV = Variable.Div;
public static readonly Func<Variable, Variable, Variable> MOD = Variable.Mod;
public static readonly Func<Variable, Variable, Variable> AND = Variable.And;
public static readonly Func<Variable, Variable, Variable> OR = Variable.Or;
public static readonly Func<Variable, Variable, Variable> XOR = Variable.Xor;
public static readonly Func<Variable, Variable, Variable> EQ = Variable.Eq;
public static readonly Func<Variable, Variable, Variable> N

bleyman

Какой-то это быдлокод. Завтра попробую сам, ну я не знаю, гораздо короче должно быть!
И чё за слайс дурацкий? Ты его откуда взял вообще? Посмотри на питоновский, надо так и только так делать.

Dasar

Стиль очень громоздкий.
Так только пишут что-нибудь очень большое корпоративное с надеждой сдать это лет так через 50.
усвоил ли я что-нибудь из принципов C# и .NET за те полтора месяца, которые с ними работаю?
что-то усвоил, но основных фишек последних шарпов: 2.0-3.5 не вижу, хотя те же самые анонимные методы были бы как раз кстати.
вот минут за 30 накатал

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

namespace CodeRunner
{
class Program
{
static readonly Regex LabelRegex = new Regex(@"^(\w+)\:(.*)$", RegexOptions.Compiled);
static void Main(string[] args)
{
var reader = Console.In;
if (args.Length != 0)
reader = new StreamReader(args[0]);

var lines = reader.ReadToEnd.Split(new[]{"\r\n"}, StringSplitOptions.RemoveEmptyEntries);
var labels = new Dictionary<string, int>
var actions = new List<Action<ProgramContext>>
foreach (var _line in lines)
{
var line = _line.Trim;
var labelMatch = LabelRegex.Match(line);
if (labelMatch.Success)
{
labels[labelMatch.Groups[1].Value.ToLower] = actions.Count;
line = labelMatch.Groups[2].Value;
}
line = line.Trim;
if (line != "")
actions.Add(ParseAction(line;
}

var programContext = new ProgramContext{Labels = labels};
for (int i=0; !programContext.IsEnd; ++i)
{
if (i == 1000000)
{
Console.WriteLine("Program terminated. Variables state:");
foreach (var var in programContext.Vars.Keys.OrderBy(name => name
Console.WriteLine("{0}: {1}", var, programContext.Vars[var]);
break;
}
actions[programContext.ip++](programContext);
}
}
static Action<ProgramContext> ParseAction(string line)
{
var ss = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (ss[0].ToLower == "end")
return context => { context.IsEnd = true; };
else if (ss[0].ToLower == "print")
{
var varNum = ParseVarNum(ss[1]);
return context => { Console.WriteLine(varNum(context; };
}
else if (ss[0].ToLower == "goto")
return context => { context.Goto(ss[1]); };
else if (ss[0].ToLower == "if")
{
var cond1 = ParseVarNum(ss[1]);
var cond2 = ParseVarNum(ss[3]);
var operation = ParseBoolOperation(ss[2]);
return context => { if (operation(cond1(context cond2(context context.Goto(ss[5]); };
}
else if (ss[1] == "=")
{
if (ss.Length == 3)
{
var varNum = ParseVarNum(ss[2]);
return context => { context.Vars[ss[0]] = varNum(context); };
}
else if (ss[2].ToLower == "not")
{
var varNum = ParseVarNum(ss[3]);
return context => { context.Vars[ss[0]] = ~varNum(context); };
}
else
{
var varNum = ParseVarNum(ss[2]);
var varNum2 = ParseVarNum(ss[4]);
var operation = ParseOperation(ss[3]);
return context => { context.Vars[ss[0]] = operation(varNum(context varNum2(context; };
}
}
Console.WriteLine("invalid action: {0}", line);
return context => { };
}
static Func<ProgramContext, int> ParseVarNum(string varNum)
{
if (char.IsLetter(varNum[0]
return context => context.Vars[varNum];
int value = int.Parse(varNum);
return context => value;
}
static Func<int, int, int> ParseOperation(string operation)
{
switch (operation)
{
case "+": return (x, y) => x + y;
case "-": return (x, y) => x - y;
case "*": return (x, y) => x * y;
case "/": return (x, y) => x / y;
case "%": return (x, y) => x % y;
case "or": return (x, y) => x | y;
case "and": return (x, y) => x & y;
case "xor": return (x, y) => x ^ y;
}
Console.WriteLine("неизвестная операция: {0}", operation);
return (x, y) => 0;
}
static Func<int, int, bool> ParseBoolOperation(string operation)
{
switch (operation)
{
case "==": return (x, y) => x == y;
case "!=": return (x, y) => x != y;
case ">=": return (x, y) => x >= y;
case ">": return (x, y) => x > y;
case "<=": return (x, y) => x <= y;
case "<": return (x, y) => x < y;
}
Console.WriteLine("неизвестная операция: {0}", operation);
return (x, y) => false;
}
}
public class ProgramContext
{
public int ip = 0;
public bool IsEnd = false;
public Dictionary<string, int> Labels;
public Dictionary<string, int> Vars = new Dictionary<string, int>

public void Goto(string label)
{
this.ip = Labels[label.ToLower];
}
}
}

kruzer25

но основных фишек последних шарпов: 2.0-3.5 не вижу, хотя те же самые анонимные методы были бы как раз кстати
Анонимных методов в 2.0 вроде же ещё не было? А писалось изначально под 2.0...
Так только пишут что-нибудь очень большое корпоративное
К чему привык...
надеждой сдать это лет так через 50.
Ну хз, у нас "большое корпоративное" работает прямо сечйас, а не "лет через 50".
вот минут за 30 накатал
Действительно за 30 минут?
Но (непонятно, то ли это у тебя код такой, то ли у меня глаза к такому непривычны) очень сложно понять, что там, где и как происходит.
И, кстати, у меня всё существенно легче поддерживать, по-моему. У тебя всё в одну кучу сброшено, и, например, в теле if-ов может быть только goto.
Кстати, задача оказалась хитрее, чем казалось раньше.
Во-первых, я забыл про дебаг (который надо выдавать при зависании вот с ним:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace CodeRunner {




internal class Util {

public static T[] ArraySlice<T>(T[] Source, int Offset, int Count) {

if(Offset < 0) Offset = Source.Length - Offset;
if(Count <= 0) Count = Source.Length - Offset + Count;

T[] Result = new T[Count];
Array.Copy(Source, Offset, Result, 0, Count);
return Result;
}

public static T[] ArraySlice<T>(T[] Source, int Offset) {
return ArraySlice<T>(Source, Offset, 0);
}
}



internal class Variable {

private UInt32 Value;

public Variable(UInt32 Value) {
this.Value = Value;
}

public override string ToString {
return this.Value.ToString;
}

public bool IsTrue {
return this.Value != 0;
}

public static Variable Not(Variable Var) {
return new Variable(~ Var.Value);
}

public static Variable Copy(Variable Var) {
return Var;
}

public static Variable Plus(Variable Var1, Variable Var2) {
return new Variable(Var1.Value + Var2.Value);
}

public static Variable Minus(Variable Var1, Variable Var2) {
return new Variable(Var1.Value - Var2.Value);
}

public static Variable Mul(Variable Var1, Variable Var2) {
return new Variable(Var1.Value * Var2.Value);
}

public static Variable Div(Variable Var1, Variable Var2) {
return new Variable(Var1.Value / Var2.Value);
}

public static Variable Mod(Variable Var1, Variable Var2) {
return new Variable(Var1.Value % Var2.Value);
}

public static Variable Or(Variable Var1, Variable Var2) {
return new Variable(Var1.Value | Var2.Value);
}

public static Variable And(Variable Var1, Variable Var2) {
return new Variable(Var1.Value & Var2.Value);
}

public static Variable Xor(Variable Var1, Variable Var2) {
return new Variable(Var1.Value ^ Var2.Value);
}

private static Variable CreateFromBool(bool Value) {
return Value ? (new Variable(1 : (new Variable(0;
}

public static Variable Eq(Variable Var1, Variable Var2) {
return CreateFromBool(Var1.Value == Var2.Value);
}

public static Variable NE(Variable Var1, Variable Var2) {
return CreateFromBool(Var1.Value != Var2.Value);
}

public static Variable GT(Variable Var1, Variable Var2) {
return CreateFromBool(Var1.Value > Var2.Value);
}

public static Variable GE(Variable Var1, Variable Var2) {
return CreateFromBool(Var1.Value >= Var2.Value);
}

public static Variable LT(Variable Var1, Variable Var2) {
return CreateFromBool(Var1.Value < Var2.Value);
}

public static Variable LE(Variable Var1, Variable Var2) {
return CreateFromBool(Var1.Value <= Var2.Value);
}

}




internal class Variables : IEnumerable<KeyValuePair<string, Variable>> {

private Dictionary<string, Variable> Storage;

public Variables {
this.Storage = new Dictionary<string,Variable>
}

public Variable GetVariable(string Name) {
return this.Storage[Name];
}

public void SetVariable(string Name, Variable Value) {
this.Storage[Name] = Value;
}

public IEnumerator<KeyValuePair<string, Variable>> GetEnumerator {
List<string> Keys = new List<string>(this.Storage.Count);
foreach(KeyValuePair<string, Variable> kvp in this.Storage) {
Keys.Add(kvp.Key);
}
Keys.Sort;

for(int i=0; i<Keys.Count; i++) {
yield return new KeyValuePair<string, Variable>(Keys[i], this.Storage[Keys[i]]);
}
}

IEnumerator IEnumerable.GetEnumerator {
return GetEnumerator;
}

}




internal abstract class VarNum {

abstract public Variable GetVariable(Variables Data);

public static VarNum CreateByString(string Word) {
if(Regex.IsMatch(Word, "^-?\\d+$" {
return new VarNum_Number(Word);
} else {
return new VarNum_Variable(Word);
}
}

private class VarNum_Variable : VarNum {

private string Name;

public VarNum_Variable(string Name) {
this.Name = Name;
}

public override Variable GetVariable(Variables Data) {
return Data.GetVariable(this.Name);
}

}

private class VarNum_Number : VarNum {

private string Num;

public VarNum_Number(string Number) {
this.Num = Number;
}

public override Variable GetVariable(Variables Data) {
return new VariableUInt32)int.Parse(Num;
}
}

}




internal abstract class Calculation {

abstract public Variable Calculate(Variables Data);

public static Calculation CreateByString(string[] Words) {

if(Words.Length == 1) {
return new Calculation1(Calculation1.COPY, VarNum.CreateByString(Words[0];
} else if(Words.Length == 2) {
return new Calculation1(Calculation1.Creator.Instance.Operator2Type[Words[0].ToLower], VarNum.CreateByString(Words[1];
} else if(Words.Length == 3) {
return new Calculation2(Calculation2.Creator.Instance.Operator2Type[Words[1].ToLower], VarNum.CreateByString(Words[0] VarNum.CreateByString(Words[2];
} else {
throw new ApplicationException("Unknown calculation '" + String.Join(" ", Words) + "'");
}
}

private class Calculation1 : Calculation {

public static readonly Func<Variable, Variable> NOT = Variable.Not;
public static readonly Func<Variable, Variable> COPY = Variable.Copy;

private static readonly Dictionary<string, Func<Variable, Variable>> Operator2Type = new Dictionary<string,Func<Variable,Variable>> {
};

private Func<Variable, Variable> Type;

private VarNum Var1;

public Calculation1(Func<Variable, Variable> Type, VarNum Var1) {
this.Type = Type;
this.Var1 = Var1;
}

public override Variable Calculate(Variables Data) {
return this.Type(this.Var1.GetVariable(Data;
}

public class Creator {

public static readonly Creator Instance = new Creator;

public readonly Dictionary<string, Func<Variable, Variable>> Operator2Type;

private Creator {

thi

kruzer25

И чё за слайс дурацкий? Ты его откуда взял вообще?
Руками наговнокодил.
ArraySegment<T> можно было бы преобразовать в массив, если бы разработчики дотнета об этом подумали, но они об этом не подумали, и никакого ToArray у него почему-то нет.
Посмотри на питоновский, надо так и только так делать.
А как сделано в питоне?
Не понимаю, что тебе не нравится. Мне нужно именно получить кусок массива, и это решается одной строчкой (ну, на самом деле, тремя). Для того, чтобы было удобно им пользоваться - я сделал возможность указывать отрицательные offset (ещё три строчки) и count (ещё три). Не так уж и страшно всё это выглядит.
А если ты про скорость работы... если бы мне нужно было что-то супербыстрое, я бы использовал ArraySegment<T>. Но мне нужен именно T[].

kruzer25

Кстати, у тебя там вообще баг на баге. Что делать будем, если кто-то обозвал переменную goto, end или if?
Ничего личного, но я привык совсем не к таким отступам, и в твоём примере довольно сложно такие ошибки отлавливать; а тебе?

kruzer25

И ещё, за счёт этих анонимных функций в данном случае ничего сэкономить не получится.
Потому что переменных в условии - хитрые (uint32 со знаком их надо реализовывать руками, и самому же руками реализовывать методы сложения, вычитания итп; для того, чтобы можно было их в другом месте заюзать - эти методы, конечно же, должны быть в классе переменной. И тогда уже анонимные методы в самом выполнении программы ничего не дадут.

Dasar

Анонимных методов в 2.0 вроде же ещё не было? А писалось изначально под 2.0...
есть анонимные делегаты, они чуть более громоздкие, но суть та же.
Действительно за 30 минут?
да
И, кстати, у меня всё существенно легче поддерживать, по-моему.
у тебя много лишнего.
да, вместо простых delegate-ов, можно использовать делегат обернутый в класс - например, такое было бы удобно, если бы нужно было бы выводить кусок кода.
а вот плодить тупо методы Mul, Div и т.д. - излишне, когда все это можно сделать одним for-ом.
У тебя всё в одну кучу сброшено, и, например, в теле if-ов может быть только goto.
см. условие задачи.
если тебя интересует, как это бы модифицировалось, если в if надо было бы больше, чем goto, то это было бы как-то так:

else if (ss[0].ToLower == "if")
{
var cond1 = ParseVarNum(ss[1]);
var cond2 = ParseVarNum(ss[3]);
var operation = ParseBoolOperation(ss[2]);
var action = ParseAction(string.Join(" ", ss.GetRange(4;
return context => { if (operation(cond1(context cond2(context action(context); };
}


Во-вторых, в этом дебаге надо хитрым способом сортировать имена переменных, этот способ ещё и реализовать надо.
это стандартный способ, и в .net-е он есть.
надо только покрутить настройки культуры и т.д, чтобы сортировалось так же как в условии.
А всё это реализовывать - довольно грязно.
только с метками есть трудности: т.к. может быть переход вперед на еще необъявленную метку, но это можно обойти через двойной проход
нумерация переменных вообще легко делается

Dasar

Кстати, у тебя там вообще баг на баге. Что делать будем, если кто-то обозвал переменную goto, end или if?
согласен.
надо переставить блок с обработкой равенства на первое место
и в твоём примере довольно сложно такие ошибки отлавливать; а тебе?
без проблем

Dasar

Потому что переменных в условии - хитрые (uint32 со знаком их надо реализовывать руками
нет там ничего хитрого.
обычный знаковый int.

Dasar

вот с идентификацией переменных по номеру. стало в два раза быстрее, и 10 лимонов укладывается в секунду у меня

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Diagnostics;

namespace CodeRunner
{
class Program
{
static readonly Regex LabelRegex = new Regex(@"^(\w+)\:(.*)$", RegexOptions.Compiled);
static void Main(string[] args)
{
var reader = Console.In;
if (args.Length != 0)
reader = new StreamReader(args[0]);

var watch = new Stopwatch;
watch.Start;
Run(reader);
watch.Stop;
Console.WriteLine(watch.Elapsed);
}

private static void Run(TextReader reader)
{
var lines = reader.ReadToEnd.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
var labels = new Dictionary<string, int>
var actions = new List<Action<ProgramContext>>
var varIndex = new Dictionary<string, int>
foreach (var _line in lines)
{
var line = _line.Trim;
var labelMatch = LabelRegex.Match(line);
if (labelMatch.Success)
{
labels[labelMatch.Groups[1].Value.ToLower] = actions.Count;
line = labelMatch.Groups[2].Value;
}
line = line.Trim;
if (line != "")
actions.Add(ParseAction(line, varIndex;
}

var programContext = new ProgramContext { Labels = labels, Vars = new int?[varIndex.Count], VarIndex=varIndex };
for (int i = 0; !programContext.IsEnd; ++i)
{
if (i == 10000000)
{
Console.WriteLine("Program terminated. Variables state:");
foreach (var var in programContext.VarIndex.Keys.OrderBy(name => name
{
var value = programContext.Vars[programContext.VarIndex[var]];
if (value == null)
continue;
Console.WriteLine("{0}: {1}", var, value);
}
break;
}
actions[programContext.ip++](programContext);
}
}
static Action<ProgramContext> ParseAction(string line, Dictionary<string, int> varIndex)
{
var ss = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (ss[1] == "=")
{
var rvalue = ParseVarId(ss[0], varIndex);
if (ss.Length == 3)
{
var varNum = ParseVarNum(ss[2], varIndex);
return context => { context.Vars[rvalue] = varNum(context); };
}
else if (ss[2].ToLower == "not")
{
var varNum = ParseVarNum(ss[3], varIndex);
return context => { context.Vars[rvalue] = ~varNum(context); };
}
else
{
var varNum = ParseVarNum(ss[2], varIndex);
var varNum2 = ParseVarNum(ss[4], varIndex);
var operation = ParseOperation(ss[3]);
return context => { context.Vars[rvalue] = operation(varNum(context varNum2(context; };
}
}
else if (ss[0].ToLower == "end")
return context => { context.IsEnd = true; };
else if (ss[0].ToLower == "print")
{
var varNum = ParseVarNum(ss[1], varIndex);
return context => { Console.WriteLine(varNum(context; };
}
else if (ss[0].ToLower == "goto")
return context => { context.Goto(ss[1]); };
else if (ss[0].ToLower == "if")
{
var cond1 = ParseVarNum(ss[1], varIndex);
var cond2 = ParseVarNum(ss[3], varIndex);
var operation = ParseBoolOperation(ss[2]);
return context => { if (operation(cond1(context cond2(context context.Goto(ss[5]); };
}
Console.WriteLine("invalid action: {0}", line);
return context => { };
}
static int ParseVarId(string varNum, Dictionary<string, int> varIndex)
{
if (varIndex.ContainsKey(varNum
return varIndex[varNum];
else
{
var varId = varIndex.Count;
varIndex[varNum] = varId;
return varId;
}
}
static Func<ProgramContext, int> ParseVarNum(string varNum, Dictionary<string, int> varIndex)
{
if (char.IsLetter(varNum[0]
{
var varId = ParseVarId(varNum, varIndex);
return context => context.Vars[varId].Value;
}
int value = int.Parse(varNum);
return context => value;
}
static Func<int, int, int> ParseOperation(string operation)
{
switch (operation)
{
case "+": return (x, y) => x + y;
case "-": return (x, y) => x - y;
case "*": return (x, y) => x * y;
case "/": return (x, y) => x / y;
case "%": return (x, y) => x % y;
case "or": return (x, y) => x | y;
case "and": return (x, y) => x & y;
case "xor": return (x, y) => x ^ y;
}
Console.WriteLine("неизвестная операция: {0}", operation);
return (x, y) => 0;
}
static Func<int, int, bool> ParseBoolOperation(string operation)
{
switch (operation)
{
case "==": return (x, y) => x == y;
case "!=": return (x, y) => x != y;
case ">=": return (x, y) => x >= y;
case ">": return (x, y) => x > y;
case "<=": return (x, y) => x <= y;
case "<": return (x, y) => x < y;
}
Console.WriteLine("неизвестная операция: {0}", operation);
return (x, y) => false;
}
}
public class ProgramContext
{
public int ip = 0;
public bool IsEnd = false;
public Dictionary<string, int> Labels;
public Dictionary<string, int> VarIndex;// = new Dictionary<string, int>
public int?[] Vars;

public void Goto(string label)
{
this.ip = Labels[label.ToLower];
}
}
}

Dasar

да, замена label-ов на int-ы - дала ускорение еще в 2 раза

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Diagnostics;

namespace CodeRunner
{
class Program
{
static readonly Regex LabelRegex = new Regex(@"^(\w+)\:(.*)$", RegexOptions.Compiled);
static void Main(string[] args)
{
var reader = Console.In;
if (args.Length != 0)
reader = new StreamReader(args[0]);

var watch = new Stopwatch;
watch.Start;
Run(reader);
watch.Stop;
Console.WriteLine(watch.Elapsed);
}

private static void Run(TextReader reader)
{
var lines = reader.ReadToEnd.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
var labels = new Dictionary<string, int>
var varIndex = new Dictionary<string, int>

var textActions = new List<string>

foreach (var _line in lines)
{
var line = _line.Trim;
var labelMatch = LabelRegex.Match(line);
if (labelMatch.Success)
{
labels[labelMatch.Groups[1].Value.ToLower] = textActions.Count;
line = labelMatch.Groups[2].Value;
}
line = line.Trim;
if (line != "")
textActions.Add(line);
}
var actions = textActions.Select(textAction => ParseAction(textAction, varIndex, labels.ToArray;


var programContext = new ProgramContext { Labels = labels, Vars = new int?[varIndex.Count], VarIndex=varIndex };
for (int i = 0; !programContext.IsEnd; ++i)
{
if (i == 10000000)
{
Console.WriteLine("Program terminated. Variables state:");
foreach (var var in programContext.VarIndex.Keys.OrderBy(name => name
{
var value = programContext.Vars[programContext.VarIndex[var]];
if (value == null)
continue;
Console.WriteLine("{0}: {1}", var, value);
}
break;
}
actions[programContext.ip++](programContext);
}
}
static Action<ProgramContext> ParseAction(string line, Dictionary<string, int> varIndex, Dictionary<string, int> labels)
{
var ss = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (ss[1] == "=")
{
var rvalue = ParseVarId(ss[0], varIndex);
if (ss.Length == 3)
{
var varNum = ParseVarNum(ss[2], varIndex);
return context => { context.Vars[rvalue] = varNum(context); };
}
else if (ss[2].ToLower == "not")
{
var varNum = ParseVarNum(ss[3], varIndex);
return context => { context.Vars[rvalue] = ~varNum(context); };
}
else
{
var varNum = ParseVarNum(ss[2], varIndex);
var varNum2 = ParseVarNum(ss[4], varIndex);
var operation = ParseOperation(ss[3]);
return context => { context.Vars[rvalue] = operation(varNum(context varNum2(context; };
}
}
else if (ss[0].ToLower == "end")
return context => { context.IsEnd = true; };
else if (ss[0].ToLower == "print")
{
var varNum = ParseVarNum(ss[1], varIndex);
return context => { Console.WriteLine(varNum(context; };
}
else if (ss[0].ToLower == "goto")
{
var newIp = labels[ss[1]];
return context => { context.Goto(newIp); };
}
else if (ss[0].ToLower == "if")
{
var cond1 = ParseVarNum(ss[1], varIndex);
var cond2 = ParseVarNum(ss[3], varIndex);
var operation = ParseBoolOperation(ss[2]);
var newIp = labels[ss[5]];
return context => { if (operation(cond1(context cond2(context context.Goto(newIp); };
}
Console.WriteLine("invalid action: {0}", line);
return context => { };
}
static int ParseVarId(string varNum, Dictionary<string, int> varIndex)
{
if (varIndex.ContainsKey(varNum
return varIndex[varNum];
else
{
var varId = varIndex.Count;
varIndex[varNum] = varId;
return varId;
}
}
static Func<ProgramContext, int> ParseVarNum(string varNum, Dictionary<string, int> varIndex)
{
if (char.IsLetter(varNum[0]
{
var varId = ParseVarId(varNum, varIndex);
return context => context.Vars[varId].Value;
}
int value = int.Parse(varNum);
return context => value;
}
static Func<int, int, int> ParseOperation(string operation)
{
switch (operation)
{
case "+": return (x, y) => x + y;
case "-": return (x, y) => x - y;
case "*": return (x, y) => x * y;
case "/": return (x, y) => x / y;
case "%": return (x, y) => x % y;
case "or": return (x, y) => x | y;
case "and": return (x, y) => x & y;
case "xor": return (x, y) => x ^ y;
}
Console.WriteLine("неизвестная операция: {0}", operation);
return (x, y) => 0;
}
static Func<int, int, bool> ParseBoolOperation(string operation)
{
switch (operation)
{
case "==": return (x, y) => x == y;
case "!=": return (x, y) => x != y;
case ">=": return (x, y) => x >= y;
case ">": return (x, y) => x > y;
case "<=": return (x, y) => x <= y;
case "<": return (x, y) => x < y;
}
Console.WriteLine("неизвестная операция: {0}", operation);
return (x, y) => false;
}
}
public class ProgramContext
{
public int ip = 0;
public bool IsEnd = false;
public Dictionary<string, int> Labels;
public Dictionary<string, int> VarIndex;
public int?[] Vars;

public void Goto(string label)
{
this.ip = Labels[label.ToLower];
}
public void Goto(int newIp)
{
this.ip = newIp;
}
}
}

Dasar

надо переставить блок с обработкой равенства на первое место
и строчку с разбором not заменить на

else if (ss.Length == 4 && ss[2].ToLower == "not")

Dasar

сортировка такая как в условии делается так:

var keys = programContext.VarIndex.Keys.ToArray;
Array.Sort(keys, StringComparer.Ordinal);
foreach (var var in keys)

Dasar

вот с идентификацией переменных по номеру. стало в два раза быстрее, и 10 лимонов укладывается в секунду у меня
так это еще все в debug-е выполнялось.
в release-е стало еще быстрее процентов на 70%
в итоге: 10лимонов за 0.3 секунды

kruzer25

только с метками есть трудности: т.к. может быть переход вперед на еще необъявленную метку, но это можно обойти через двойной проход
нумерация переменных вообще легко делается
Да, но надо попотеть.
а вот плодить тупо методы Mul, Div и т.д. - излишне, когда все это можно сделать одним for-ом.
В любом случае нужен класс-переменная, потому что значения переменных - хитрые.
В любом случае надо расписывать, как на этих переменных будет работать сложение, умножение итп.
Так какая разница - анонимные методы это будут или нет? Имхо, как раз лучше, если нет - потому что тогда их можно будет, если понадобится, заюзать ещё где-нибудь.
есть анонимные делегаты, они чуть более громоздкие, но суть та же.
А то, что я написал (где Func<T, TResult>) можно легко переписать под 2.0?
ЗЫ: Чорд, хотел всех наобмануть в этой задаче: http://acm.timus.ru/problem.aspx?space=1&num=1423, и написал такое наколенное ненадёжное (даже без проверок) решение, работающее за O(N^1.5):
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;

namespace Task1423 {
class Program {

private static Int64 Bytes2Int(Byte[] Bytes) {

return (
Bytes[0] + 256*(
Bytes[1] + 256*(
Bytes[2] + 256*(
Bytes[3] + 256*(
Bytes[4] + 256*(
Bytes[5] + 256*(
Bytes[6] + 256*(
Bytes[7]
)
)
)
)
)
)
)
);
}

private static SHA1Managed Provider = new SHA1Managed;

private static Int64 String2Int(string ToEncrypt) {

UnicodeEncoding UE = new UnicodeEncoding;
return Bytes2Int(Provider.ComputeHash(UE.GetBytes(ToEncrypt + "abracadabra";
}

static void Main(string[] args) {

int Length = int.Parse(Console.ReadLine;

int SplitBy = (int)Math.Sqrtfloat)Length);

string Before = Console.ReadLine;
Before = Before + Before;
string After = Console.ReadLine;
After = After + After;

Int64[] HashCodes = new Int64[Length * 2];

int tmp = Length - SplitBy;

for(int i=0; i<Length; i++) {

string ToHash;
ToHash = After.Substring(i, SplitBy);
HashCodes[i] = String2Int(ToHash);
}

for(int i=0; i<Length; i++) {
HashCodes[i+Length] = HashCodes[i];
}

Int64[] BeforeHashCodes = new Int64[SplitBy+1];

for(int j=0; j<=SplitBy; j++) {

int i=j*SplitBy;

string ToHash;
ToHash = Before.Substring(i, SplitBy);
BeforeHashCodes[j] = String2Int(ToHash);

}
bool Found = false;
int FoundIn = -1;

for(int i=0; i<Length; i++) {

if(HashCodes[i] == BeforeHashCodes[0]) {

bool NotFound = false;

for(int j=1; j<=SplitBy; j++) {
if(HashCodes[i+j*SplitBy] != BeforeHashCodes[j]) {
NotFound = true;
break;
}
}

if(!NotFound) {
Found = true;
FoundIn = i;
break;
}
}
}

if(!Found) {
Console.WriteLine("-1");
} else {
Console.WriteLine(FoundIn);
}

}
}
}

А оно свалилось на первом же тесте (Crash)
Видимо, запрещена у них криптография... :(

kruzer25

нет там ничего хитрого.
обычный знаковый int.
А это что?
Предполагается, что в процессе вычислений все значения хранятся в виде 4--байтовых целых чисел, отрицательные числа кодируются в дополнительном коде.
Кроме того, там у них побитовые операции и деление с остатком над такими числами, насколько я понял, хитрые.

Dasar

А то, что я написал (где Func<T, TResult>) можно легко переписать под 2.0?
достаточно добавить

public delegate TResult Func<T, TResult>(T arg);
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);

Dasar

А это что?
System.Int32
Предполагается, что в процессе вычислений все значения хранятся в виде 4--байтовых целых чисел, отрицательные числа кодируются в дополнительном коде.
а System.Int32 как по твоему отрицательные числа хранит?
Кроме того, там у них побитовые операции и деление с остатком над такими числами, насколько я понял, хитрые.
а System.Int32 как по твоему эти операции делает?

kruzer25

а System.Int32 как по твоему отрицательные числа хранит?
Насколько я понял, тут имеется в виду - "4байтовые беззнаковые целые + дополнительный флаг для знака", то есть, на один бит больше, чем в int32.
а System.Int32 как по твоему эти операции делает?
Судя по обсуждению задачи - не так.
Впрочем, я особо не вчитывался.

Dasar

Вот такой код в итоге все тесты прошел

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Diagnostics;

public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
public delegate TResult Func<T, TResult>(T arg);

namespace CodeRunner
{
class Program
{
static readonly Regex LabelRegex = new Regex(@"^(\w+)\:(.*)$", RegexOptions.Compiled);
static void Main(string[] args)
{
if (args.Length == 0)
{
Run(Console.In);
}
else
{
Stopwatch watch = new Stopwatch;
watch.Start;
using (StreamReader reader = new StreamReader(args[0]
Run(reader);
watch.Stop;
Console.WriteLine(watch.Elapsed);
}
}

private static void Run(TextReader reader)
{
string[] lines = reader.ReadToEnd.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
Dictionary<string, int> labels = new Dictionary<string, int>
Dictionary<string, int> varIndex = new Dictionary<string, int>

List<string> textActions = new List<string>

foreach (string _line in lines)
{
string line = _line.Trim;
Match labelMatch = LabelRegex.Match(line);
if (labelMatch.Success)
{
labels[labelMatch.Groups[1].Value.ToLower] = textActions.Count;
line = labelMatch.Groups[2].Value;
}
line = line.Trim;
if (line != "")
textActions.Add(line);
}

Action<ProgramContext>[] actions = new Action<ProgramContext>[textActions.Count];
for (int i = 0; i < actions.Length; ++i)
actions[i] = ParseAction(textActions[i], varIndex, labels);


ProgramContext programContext = new ProgramContext;
programContext.Labels = labels;
programContext.Vars = new int[varIndex.Count];
programContext.VarInit = new bool[varIndex.Count];
programContext.VarIndex = varIndex;
for (int i = 0; ; ++i)
{
if (i == 10000000)
{
Console.WriteLine("Program terminated. Variables state:");
string[] keys = new List<string>(programContext.VarIndex.Keys).ToArray;
Array.Sort(keys, StringComparer.Ordinal);
foreach (string var in keys)
{
if (!programContext.VarInit[programContext.VarIndex[var]])
continue;
int value = programContext.Vars[programContext.VarIndex[var]];
Console.WriteLine("{0}: {1}", var, value);
}
break;
}
if (programContext.ip >= actions.Length)
break;
actions[programContext.ip++](programContext);
}
}
static Action<ProgramContext> ParseAction(string line, Dictionary<string, int> varIndex, Dictionary<string, int> labels)
{
string[] ss = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (ss.Length == 1 && ss[0].ToLower == "end")
return delegate(ProgramContext context) { context.ip = 1000000; };
else if (ss[1] == "=")
{
int rvalue = ParseVarId(ss[0], varIndex);
if (ss.Length == 3)
{
KeyValuePair<bool, int> varNum = ParseVarNum(ss[2], varIndex);
return delegate(ProgramContext context) { context.Vars[rvalue] = varNum.Key ? context.Vars[varNum.Value] : varNum.Value ; context.VarInit[rvalue] = true; };
}
else if (ss.Length == 4 && ss[2].ToLower == "not")
{
KeyValuePair<bool, int> varNum = ParseVarNum(ss[3], varIndex);
return delegate(ProgramContext context) { context.Vars[rvalue] = ~(varNum.Key ? context.Vars[varNum.Value] : varNum.Value); context.VarInit[rvalue] = true; };
}
else
{
KeyValuePair<bool, int> varNum = ParseVarNum(ss[2], varIndex);
KeyValuePair<bool, int> varNum2 = ParseVarNum(ss[4], varIndex);
Func<int, int, int> operation = ParseOperation(ss[3].ToLower;
return delegate(ProgramContext context) { context.Vars[rvalue] = operation(varNum.Key ? context.Vars[varNum.Value] : varNum.Value, varNum2.Key ? context.Vars[varNum2.Value] : varNum2.Value); context.VarInit[rvalue] = true; };
//return delegate(ProgramContext context) { context.Vars[rvalue] = operation(context.Vars[rvalue] ? 4, context.Vars[rvalue]?6); };
}
}
else if (ss[0].ToLower == "print")
{
KeyValuePair<bool, int> varNum = ParseVarNum(ss[1], varIndex);
return delegate(ProgramContext context) { Console.WriteLine(varNum.Key ? context.Vars[varNum.Value] : varNum.Value); };
}
else if (ss[0].ToLower == "goto")
{
int newIp = labels[ss[1].ToLower];
return delegate(ProgramContext context) { context.Goto(newIp); };
}
else if (ss[0].ToLower == "if")
{
KeyValuePair<bool, int> cond1 = ParseVarNum(ss[1], varIndex);
KeyValuePair<bool, int> cond2 = ParseVarNum(ss[3], varIndex);
Func<int, int, bool> operation = ParseBoolOperation(ss[2]);
int newIp = labels[ss[5].ToLower];
return delegate(ProgramContext context) { if (operation(cond1.Key ? context.Vars[cond1.Value] : cond1.Value, cond2.Key ? context.Vars[cond2.Value] : cond2.Value context.Goto(newIp); };
}
throw new Exception(string.Format("invalid action: {0}", line;
return delegate(ProgramContext context) { };
}
static int ParseVarId(string varNum, Dictionary<string, int> varIndex)
{
if (varIndex.ContainsKey(varNum
return varIndex[varNum];
else
{
int varId = varIndex.Count;
varIndex[varNum] = varId;
return varId;
}
}
//static Func<ProgramContext, int> ParseVarNum(string varNum, Dictionary<string, int> varIndex)
//{
// if (char.IsLetter(varNum[0]
// {
// int varId = ParseVarId(varNum, varIndex);
// return delegate(ProgramContext context) {return context.Vars[varId];};
// }
// int value = int.Parse(varNum);
// return delegate(ProgramContext context) { return value; };
//}
static KeyValuePair<bool, int> ParseVarNum(string varNum, Dictionary<string, int> varIndex)
{
if (char.IsLetter(varNum[0]
{
int varId = ParseVarId(varNum, varIndex);
return new KeyValuePair<bool,int>(true, varId);
}
int value = int.Parse(varNum);
return new KeyValuePair<bool, int>(false, value);
}
static Func<int, int, int> ParseOperation(string operation)
{
switch (operation)
{
case "+": return delegate(int x, int y){return x + y;};
case "-": return delegate(int x, int y){return x - y;};
case "*": return delegat

Andbar

public static readonly Func<Variable, Variable, Variable>
а додиез разве не позволяет как-то сократить эту запись?

vall

			return (
Bytes[0] + 256*(
Bytes[1] + 256*(
Bytes[2] + 256*(
Bytes[3] + 256*(
Bytes[4] + 256*(
Bytes[5] + 256*(
Bytes[6] + 256*(
Bytes[7]
)
)
)
)
)
)
)
);

фак, мой мозг!

zya369

блин, я конечно извиняюсь, но после этого говорить о удобности С# имхо несколько странно
200 строк и 7 килобайт кода - я чуть глаза н сломал :)

Dasar

это порт под 2.0, в 3.5 он лучше смотрелся.

zya369

в 3.5 он лучше смотрелся.

а в этом треде он был?
а то все читать - глаза жалко :)

sergeikozyr

это порт под 2.0, в 3.5 он лучше смотрелся.
я бы не стал называть это "лучше" ;)

timefim

>но после этого говорить о удобности С# имхо несколько странно
А где говорится об его удобстве?

Dasar

а в этом треде он был?
предыдущие мои - это 3.5

zya369

предыдущие мои - это 3.5

я, если что, про последний вариант говорил

zya369

А где говорится от его удобстве?

а зачем его используют?
мне в целом интересно - чем он так хорош, что на каждом углу встречается ?:)

timefim

>чем он так хорош, что на каждом углу встречается ?:)
Низкий порог вхождения.

kokoc88

блин, я конечно извиняюсь, но после этого говорить о удобности С# имхо несколько странно
200 строк и 7 килобайт кода - я чуть глаза н сломал
Так ты бы написал реализацию задачи на другом языке. Чтобы работала так же быстро. И была бы хоть наполовину читаемой с нуля. А мы бы поглядели и согласились, что бывают очень удобные, читаемые, быстро работающие языки программирования. А то у участников данного раздела есть интересная привычка возмущаться без арументов и без практики. Видите ли им лень писать тривиальный код, но зато они на тысячу процентов уверены, что когда они его напишут он будет минимум в десятки раз лучше.

Dasar

мне в целом интересно - чем он так хорош, что на каждом углу встречается ?:)
потому что это очень приличный промышленный язык

zya369

Так ты бы написал реализацию задачи на другом языке. Чтобы работала так же быстро. И была бы хоть наполовину читаемой с нуля.

Так же быстро - это как?
данный пример имхо ни разу не читаем, так что требовать и того и другого несколько неверно, имхо. либо быстрее, либо читаемее :)

zya369

промышленный

что это значит?
что на нем промышляют? :D

kokoc88

Так же быстро - это как?
данный пример имхо ни разу не читаем, так что требовать и того и другого несколько неверно, имхо. либо быстрее, либо читаемее
Так же быстро - это скорость вычислений. Задача в теме есть. Выбери свой классный язык и напиши реализацию. Чтобы она укладывалась по времени работы и проходила все тесты, как и программа на C#.

apl13

Это пехапе, не цешарп,
Мы не принимаем профанацию!
Йо, выбери свой язык,
Выбери свою реализацию!
:singer:

Dasar

что на нем промышляют?
задачи требующие автоматизации.

Dasar

подумал - понравилось, подумал еще...
более правильный термин: производственный, чем промышленный

zya369

что на нем промышляют?
задачи требующие автоматизации.

я имел ввиду, что это определение - "промышленный язык - язык, на котором промышляют" :)
задачи требующие автоматизации.

с таким определением много чего можно промышленным назвать :)

Dasar

с таким определением много
какой вопрос такой и ответ...
так тебя что интересует? почему именно C# - производственный язык? что-то еще?

sergeikozyr

жабко - промышленный Ъ-ынтерпрайз езыг, цешарп - пионерская поделка :mad:

zya369

меня интересует, что в нем такого, что он производственный, а, скажем, питон - нет
ЗЫ вообще мне на С# как-то пофиг в целом, просто вроде как не самый старый язык а на такой простой задаче решение ВЫГЛЯДИТ имхо просто ужасающе

karkar

Так ты бы написал реализацию задачи на другом языке. Чтобы работала так же быстро. И была бы хоть наполовину читаемой с нуля. А мы бы поглядели и согласились, что бывают очень удобные, читаемые, быстро работающие языки программирования.

Жаль, там на немейнстримных языках не принимают решения, нельзя узнать, все ли тесты проходит.
Ниже мое наколенное решение на OCaml. Сравнил с Даркгреевским вариантом на C0 (C# 3.0 негде проверить получилось более чем в 2 раза короче по числу строк и объему исходника и в 1.4 раза быстрее по скорости исполнения. Но медленнее по скорости написания (часа полтора ушло, очень не хватает нормальной IDE с подсказкой по функциям).
Не уверен насчет читаемости, особенно для людей незнакомых с языком.
Исходник:
open ExtString;;
open ExtArray;;
open ExtHashtbl;;
let (|>) x f = f x;;
let vars = DynArray.make 1000;; (* values *)
let varnames = Hashtbl.create 1000;;
let cmds = DynArray.make 1000;;
let labels = Hashtbl.create 1000;;

let var_index varnum =
try Hashtbl.find varnames varnum with Not_found->
let value = try int_of_string varnum with Failure _-> 0 in
let idx = DynArray.length vars in
DynArray.add vars value;
Hashtbl.add varnames varnum idx;
idx;;

exception Nocmd;;
exception End;;
let (@=) s p = String.lowercase s = p;;
let dget = DynArray.unsafe_get;;
let dset = DynArray.unsafe_set;;
let ip = ref 0;;
let next = incr ip;;
let rem a b = let r = a mod b in if r < 0 then r + abs b else r;;

let compile_line line =
let cmd_str = try
let lblend = String.index line ':' in
let lblstart = try String.rindex_from line lblend ' ' with Not_found -> 0 in
let lbl = String.sub line lblstart (lblend - lblstart) in
Hashtbl.add labels (String.lowercase lbl) (DynArray.length cmds);
String.slice ~first:(lblend+1) line
with Not_found-> line in
match String.nsplit cmd_str " " |> List.filter (fun s-> String.length s > 0) with
| print :: varnum :: [] when print @= "print" ->
let idx = var_index varnum in
(fun k-> Printf.printf "%d\n" (dget vars idx); next None
| var :: "=" :: varnum :: [] ->
let idst = var_index var and isrc = var_index varnum in
(fun k-> dset vars idst (dget vars isrc); next None
| var :: "=" :: not :: varnum :: [] when not @= "not" ->
let idst = var_index var and isrc = var_index varnum in
(fun k-> dset vars idst (lnot (dget vars isrc; next None
| var :: "=" :: varnum1 :: op :: varnum2 :: [] ->
let idst = var_index var and isrc1 = var_index varnum1 and isrc2 = var_index varnum2 in
(match String.lowercase op with
| "+" -> (fun k-> dset vars idst (dget vars isrc1 + dget vars isrc2); next None
| "-" -> (fun k-> dset vars idst (dget vars isrc1 - dget vars isrc2); next None
| "*" -> (fun k-> dset vars idst (dget vars isrc1 * dget vars isrc2); next None
| "/" -> (fun k-> dset vars idst (dget vars isrc1 / dget vars isrc2); next None
| "%" -> (fun k-> dset vars idst (rem (dget vars isrc1) (dget vars isrc2; next None
| "or" -> (fun k-> dset vars idst (dget vars isrc1 lor dget vars isrc2); next None
| "and" -> (fun k-> dset vars idst (dget vars isrc1 land dget vars isrc2); next None
| "xor" -> (fun k-> dset vars idst (dget vars isrc1 lxor dget vars isrc2); next None
| _ -> failwith "unknown binary op" )
| _end :: [] when _end @= "end" -> (fun k -> re End None
| goto :: label :: [] when goto @= "goto" ->
(fun k-> k Some label
| _if :: varnum1 :: op :: varnum2 :: goto :: label :: [] when (_if @= "if") && (goto @= "goto") ->
let isrc1 = var_index varnum1 and isrc2 = var_index varnum2 in
(match op with
| "==" -> (fun k-> if dget vars isrc1 = dget vars isrc2 then k else next Some label
| "!=" -> (fun k-> if dget vars isrc1 <> dget vars isrc2 then k else next Some label
| ">=" -> (fun k-> if dget vars isrc1 >= dget vars isrc2 then k else next Some label
| ">" -> (fun k-> if dget vars isrc1 > dget vars isrc2 then k else next Some label
| "<=" -> (fun k-> if dget vars isrc1 <= dget vars isrc2 then k else next Some label
| "<" -> (fun k-> if dget vars isrc1 < dget vars isrc2 then k else next Some label
| _ -> failwith "unknown logical op" )
| _ -> re Nocmd;;

let parse_line line = try DynArray.add cmds (compile_line line) with Nocmd->;

let convert_labels (f, lbl_opt) =
match lbl_opt with
| None -> f, (fun -> print_string "k called when it shouldn't! ")
| Some lbl -> let idx = Hashtbl.find labels (String.lowercase lbl) in f, (fun -> ip := idx);;

let debug =
print_endline "Program terminated. Variables state:";
let a = Hashtbl.enum varnames |> Enum.filter (fun (s,i)-> s.[0]>'9') |> Array.of_enum in
Array.sort compare a;
Array.iter (fun (name,idx) -> Printf.printf "%s: %d\n" name (dget vars idx a;;

Std.input_lines stdin |> Enum.iter parse_line;;

let prg = cmds |> DynArray.enum |> Enum.map convert_labels |> Array.of_enum;;

let rec runloop n =
if n=0 then debug else
if !ip >= Array.length prg then else
let f,k = prg.(!ip) in (f k; runloop (n-1;;

try runloop 10000000 with End -> ;;

Бинарник:
Только я не очень понял, почему в задании подразумевается, что -9 % 6 = 3.. Пришлось это учитывать отдельно.

Dmitriy82

Потому что естественное определение остатка от деления a на b>0: это такое число 0<=r<b, что a=b*q+r для некоторого целого q. Альтернативные варианты по-моему возникают от кривизны и непоследовательности.

6yrop

Сравнил с Даркгреевским вариантом на C0 (C# 3.0 негде проверить получилось более чем в 2 раза короче по числу строк и объему исходника
вариант -я для 3.0 занимает 4,733 bytes
твой вариант 4,593 bytes.
Где ты видишь два раза?

Dasar

а сделай, плиз, чтобы она время выполнения печатала

karkar

Где ты видишь два раза?

Перечитай с каким вариантом я сравнивал.

karkar

Прикольно, у меня очередной фортран получился:
2 = 3
4 = 2 * 2
print 4

Выводит 9. :)

karkar

а сделай, плиз, чтобы она время выполнения печатала
Новый вариант (исходник там же):

Dasar

Перечитай с каким вариантом я сравнивал.
так сравнивай с сильным вариантом
зачем сравнивать со слабым вариантом?
вот сильный вариант:
сейчас мой и твой вариант идут вровень. на моем компе: 0.22-0.24 секунды
ps
а запасы по ускорению у тебя еще есть?

Dasar

вспомнил, что в C# 3.5 появились expression-ы переписал "бинарное присваивание" на expression-ах (остальное позже перепишу).
стало так:

== ocaml ==
-12
Program terminated. Variables state:
Value: 3
ValueA: 3
value: -2499999

profiling:
main 0.229044
== c# 3.5 ==
-12
Program terminated. Variables state:
Value: 3
ValueA: 3
value: -2499999
00:00:00.1754122

karkar

зачем сравнивать со слабым вариантом?

У меня просто нет ни компилятора C# 3.0, ни нужного фреймворка сейчас, поэтому ни скомпилить ни даже запустить твой свежий пример не могу.
Поставил качаться FW3.5, 200 мегов... Некорректный и нерелевантный оффтоп: мое решение не требует никаких фреймворков и работает сразу.
Запасы по ускорению... Не знаю. Без заметного изменения кода прямо сразу не вижу.
А какие времена получаются с учетом стартапа - от запуска программы до ее завершения? В исходной задаче ведь именно это время важно.
Edit: уже сам запустил и померял, твой вариант действительно быстрее (0,25 против 0,28 с).
сравнивай с сильным вариантом

Это последний? Он примерно втрое длиннее по строкам и вдвое по объему.

Dasar

Это последний? Он примерно втрое длиннее по строкам и вдвое по объему.
да, последний.
по объему он более раздутый - потому что это еще черновой вариант

Dasar

меня интересует, что в нем такого, что он производственный, а, скажем, питон - нет
ЗЫ вообще мне на С# как-то пофиг в целом, просто вроде как не самый старый язык а на такой простой задаче решение ВЫГЛЯДИТ имхо просто ужасающе
сколько стоит настроить рабочее место разработчика под питон?
сколько стоит разработка формочки с одним гридом под питон?
сколько стоит стыковка с правами AD под питон?
сколько стоит достижение максимально возможной скорости на отдельном куске кода под питон?
сколько стоит сделать сервис на одну функцию под питон?
сколько стоит вывести таблицу на принтер, в pdf, в word, в excel под питон?
сколько стоит возможность подключить дизайнера к оформлению пользовательского интерфеса под питон?
сколько стоит оформить кусок питона как отдельную готовую либу?
сколько стоит возможность распараллелить разработку одной программы на десять человек под питон?
и т.д.

Marinavo_0507

сколько стоит настроить рабочее место разработчика под питон?
"настроить рабочее место" - это типа стул отрегулировать под рост разработчика?

Dasar

"настроить рабочее место" - это типа стул отрегулировать под рост разработчика?
если брать в общем, то да:
настроить рабочее место = кусок помещения + мебель + СКС + железо + ПО + настройка всего этого под конкретного человека
здесь же интересовало только ПО и его настройка, т.к. все остальное в целом не зависит от языка разработки.

Papazyan

получилось более чем в 2 раза короче по числу строк и объему исходника

isD:{""~x except "-0123456789"}
val:{$[isD x; "I"$x; `$x]}

ev:{$[-6h=type x; x; vars[x]]}
ea:{[v1;v2;d] vars[v1]::ev v2;}
eg:{[op;v1;v2;v3;d] vars[v1]::op[ev v2;ev v3];}
ed:{[v1;v2;v3;d] vars[v1]::`int$(ev v2)%ev v3;}
en:{[v1;v2;d] vars[v1]::`int$not ev v2;}
pr:{[v;d] 1 (string ev v"\n";}
go:{[l;d] l}
ig:{[op;v1;v2;l;d] $[op[ev v1;ev v2]; l; ]}
vars!

ls!;
p:{[env;c]
r:pl[c];
if[0=count r; :(env 0;(env 1pa c)];
ls[env 0]:env 1;
r};

pl:{[c]
if[not ":"=last c 0; ];
(`$-1_c 0pa[1_c])};

ops:(`$("-";"+";"*";"%";"/";"and";"or";"xor"!(eg[(-)];eg[(+)];eg[(*)];eg[mod];ed;eg[and];eg[or];eg[or]);
ifs:(`$("==";"!=";">=";">";"<=";"<"!(ig[(=)];ig[(<>)];ig[(>=)];ig[(>)];ig[(<=)];ig[(<)]);
pa:{[c]
if["end"~cl:lower c 0; :exit];
if["print"~cl; :pr[val c 1]];
if["goto"~cl; :go[`$c 1]];
if["if"~cl; :(ifs `$lower c 2)[val c 1;val c 3;`$c 5]];
if[not (enlist "=")~c 1; ];
if[3=count c; :ea[`$c 0;val c 2]];
if[4=count c; :en[`$c 0;val c 3]];
(ops `$lower c 3)[`$c 0;val c 2;val c 4]};

p/[(`" " vs' read0 `:./t.txt) except\: enlist ""enlist enlist 1#":"]
ls:(key ls)!reverse {y,x}\[reverse value ls];

abort:{1 "Program terminated. Variables state:\n"; {1 (string x": "string vars x"\n"} each key vars; exit 0};

cy:{cnt+::1;if[cnt>1000000; abort[]]; r:(x 0)[0];$[-11h=type r; ls r;1_x]}
cnt:0; cy//[ls`];

ls -l
-rw-r----- 1 ? ? 1380 2008-07-24 13:16 t.q
:cool:
Ну скорость маленькая, конечно. Все таки интерпретатор.

karkar

:)
Что за язык? Q? K? J?
Какова скорость в цифрах? Сколько времени ушло на написание?

Papazyan

Q. Писал долго, но это потому, что задача не очень хорошо на на векторный язык ложится. Скорость - в 100 раз медленнее чем у дарк грея, т.е. миллион за 3.4 секунды.

agaaaa

Ботал на этом примере F#
 
#light

open System
open System.Collections.Generic
open System.Reflection
open System.Reflection.Emit

let text = IO.File.ReadAllLines("source")

let labels = Dictionary<string, Label>
let vars = Dictionary<string, LocalBuilder>
let name = AssemblyName("dynAssembly")
let assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run)
let moduleBuilder = assemblyBuilder.DefineDynamicModule(name.Name)
let typeBuilder = moduleBuilder.DefineType("program", TypeAttributes.Public)
let methodBuilder = typeBuilder.DefineMethod("Run", MethodAttributes.Static ||| MethodAttributes.Public)
let il = methodBuilder.GetILGenerator

Console.Write("compiling...")

let counter = il.DeclareLocal(int(0).GetType

il.Emit(OpCodes.Ldc_I4_0)
il.Emit(OpCodes.Stloc, counter)

let timeLimit = il.DefineLabel

type varnum =
| Local of LocalBuilder
| Num of int

let to_varnum value =
if Char.IsLetter(value, 0) then Local(vars.Item(value else Num(Int32.Parse(value

let load string =
match to_varnum string with
| Local(local) ->
il.Emit(OpCodes.Ldloc, local)
| Num(num) ->
il.Emit(OpCodes.Ldc_I4, num)

let get_label label =
if labels.ContainsKey(label) then labels.Item(label)
else
let result = il.DefineLabel
labels.Add(label, result)
result

let mutable currentLabel = Label
let mutable currentLabelName = null

let rec compile (command: string list) =
match command with
| label :: xs when label.EndsWith(":") ->
let labelName = label.Substring(0, label.Length - 1).ToLower
let label = get_label labelName
il.MarkLabel(label)
compile xs
| endcmd :: [] when endcmd.ToLower = "end" ->
il.Emit(OpCodes.Ret)
| print :: varnum :: [] when print.ToLower = "print" ->
match to_varnum varnum with
| Local(local) ->
il.EmitWriteLine(local)
| Num(num) ->
il.EmitWriteLine(num.ToString
| var :: assign :: varnum :: xs when (assign = "=") && (varnum.ToLower <> "not") ->
load varnum
match xs with
| [] ->

| op :: left :: [] ->
load left
match op.ToLower with
| "+" -> il.Emit(OpCodes.Add)
| "-" -> il.Emit(OpCodes.Sub)
| "*" -> il.Emit(OpCodes.Mul)
| "/" -> il.Emit(OpCodes.Div)
| "%" -> il.Emit(OpCodes.Rem)
| "or" -> il.Emit(OpCodes.Or)
| "and" -> il.Emit(OpCodes.And)
| "xor" -> il.Emit(OpCodes.Xor)
| _ -> failwith "invalid binary op"
| _ -> failwith "invalid op"
if not(vars.ContainsKey(var then vars.Add(var, il.DeclareLocal0).GetType
il.Emit(OpCodes.Stloc, vars.Item(var
| var :: assign :: not :: varnum :: [] when (assign = "=") && (not.ToLower = "not") ->
load varnum
il.Emit(OpCodes.Not)
il.Emit(OpCodes.Stloc, vars.Item(var
| ifs :: left :: op :: right :: goto :: label :: [] when (ifs.ToLower = "if") && (goto.ToLower = "goto") ->
load left
load right
match op with
| "==" -> il.Emit(OpCodes.Beq, get_label(label.ToLower
| "!=" -> il.Emit(OpCodes.Bne_Un, get_label(label.ToLower
| ">=" -> il.Emit(OpCodes.Bge, get_label(label.ToLower
| ">" -> il.Emit(OpCodes.Bgt, get_label(label.ToLower
| "<=" -> il.Emit(OpCodes.Ble, get_label(label.ToLower
| "<" -> il.Emit(OpCodes.Blt, get_label(label.ToLower
| _ -> failwith "invalid comprasion"
| goto :: label :: [] when goto.ToLower = "goto" ->
il.Emit(OpCodes.Br, get_label(label
| [] -> begin end
| _ -> failwith "invalid command"

il.Emit(OpCodes.Ldloc, counter)
il.Emit(OpCodes.Ldc_I4, 10000000)
il.Emit(OpCodes.Bge, timeLimit)
il.Emit(OpCodes.Ldloc, counter)
il.Emit(OpCodes.Ldc_I4_1)
il.Emit(OpCodes.Add)
il.Emit(OpCodes.Stloc, counter)

for line in System.IO.File.ReadAllLines("source") do
let tokenList = Array.to_list(line.Split([|' '|]
let tokens = List.filter ( fun (token: string) -> token.Trim <> "") tokenList
compile tokens

il.Emit(OpCodes.Ret)
il.MarkLabel(timeLimit)
il.EmitWriteLine("Program terminated. Variables state:")

let compiledType = typeBuilder.CreateType
let compiledMethod = compiledType.GetMethod("Run")

Console.WriteLine("OK")

compiledMethod.Invoke(null, [| |])

Console.WriteLine("done.")
Console.ReadKey

132 строки (но с выводом отладочной и без вывода значений переменных)
поскольку это не интерпретатор, скорость феерическая

karkar

Добавил простейшую оптимизацию, теперь мой вариант вдвое быстрее самого быстрого на C# 3:
== OCaml ==
-12
Program terminated. Variables state:
Value: 3
ValueA: 3
value: -2499999

profiling:
main 0.095364

== C# ==
-12
Program terminated. Variables state:
Value: 3
ValueA: 3
value: -2499999
00:00:00.1970976

Исходник вырос до 108 строк.

karkar

скорость феерическая
А в цифрах?

Dasar

простейшая оптимизация, заключается в подгонке под конкретный тест?.. :)
вот этот тест она же не проходит
test

value = 15
value = not value
value = value or 4
print value
value = 0
loop:
value = value - 1
Value = value % 6
ValueA = value % -6
goto loop

x = 5


должно быть

-12
Program terminated. Variables state:
Value: 3
ValueA: 3
value: -24999999

а твой код выводит

-12
Program terminated. Variables state:
Value: 3
ValueA: 3
value: -2499999
x: 0

Dasar

hardcore вариант

== ocaml ==
-12
Program terminated. Variables state:
Value: 3
ValueA: 3
value: -2499999
x: 0

profiling:
main 0.079053
== c# 3.5 ==
-12
Program terminated. Variables state:
Value: 3
ValueA: 3
value: -2499999

00:00:00.1076006

на парсинге - куда-то деваются 0.03 секунды, пока лень разбираться куда

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection.Emit;

namespace CodeRunner
{
public static class Program
{
static readonly Regex LabelRegex = new Regex(@"^(\w+)\:(.*)$", RegexOptions.Compiled);
static void Main(string[] args)
{
if (args.Length == 0)
{
Run(Console.In);
}
else
{
var watch = new Stopwatch;
watch.Start;
using (var reader =new StreamReader(args[0]
Run(reader);
watch.Stop;
Console.WriteLine;
Console.WriteLine(watch.Elapsed);
}

}

const int maxIteration = 10*1000*1000;
private static void Run(TextReader reader)
{
var lines = reader.ReadToEnd.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
var labels = new Dictionary<string, int>

var textActions = new List<string>

foreach (var _line in lines)
{
var line = _line.Trim;
var labelMatch = LabelRegex.Match(line);
if (labelMatch.Success)
{
labels[labelMatch.Groups[1].Value.ToLower] = textActions.Count;
line = labelMatch.Groups[2].Value;
}
line = line.Trim;
if (line != "")
textActions.Add(line);
}


var dynamicMethod = new DynamicMethod("S", typeof(int new[] { typeof(ProgramContext) }, typeof(ProgramContext;
var il = dynamicMethod.GetILGenerator;

var label_markers = new Dictionary<string, Label>
foreach (var label in labels.Keys)
label_markers[label] = il.DefineLabel;

var varIndex = new Dictionary<string, ValueReference>


var labelIndex = labels.GroupBy(pair => pair.Value, pair => pair.Key).ToDictionary(group => group.Key, group => group.ToArray;
il.Constant(maxIteration);

var traceLabel = il.DefineLabel;
for (int i = 0; i < textActions.Count; ++i)
{
string[] currentLabels;
if (labelIndex.TryGetValue(i, out currentLabels
{
foreach (var label in currentLabels)
il.MarkLabel(label_markers[label]);
}

il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Sub);
ParseAction(textActions[i], varIndex, label_markers, il);
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Brfalse, traceLabel);
}
il.Emit(OpCodes.Ret);
il.MarkLabel(traceLabel);

il.Emit(OpCodes.Call, typeof(Program).GetMethod("TraceHeader";
var keys = varIndex.Keys.ToArray;
Array.Sort(keys, StringComparer.Ordinal);
foreach (var var in keys)
{
var valueRef = varIndex[var];
il.Emit(OpCodes.Ldstr, var);
il.Emit(OpCodes.Ldloc, valueRef.ValueRef);
il.Emit(OpCodes.Ldloc, valueRef.ValueIsInitRef);
il.Emit(OpCodes.Call, typeof(Program).GetMethod("Trace";
}

il.Emit(OpCodes.Ret);
var program = (Func<ProgramContext, int>)dynamicMethod.CreateDelegate(typeof(Func<ProgramContext, int>
var programContext = new ProgramContext { };
program(programContext);


}

static void ParseAction(string line, Dictionary<string, ValueReference> varIndex, //Dictionary<string, int> labels,
Dictionary<string, Label> label_marks,
ILGenerator il)
{
var ss = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (ss.Length == 1 && ss[0].ToLower == "end")
//il.Goto(label_marks[""]);
il.Emit(OpCodes.Ret);
else if (ss[1] == "=")
{
var rvalue = il.ParseVarId(ss[0], varIndex);
if (ss.Length == 3)
{
il.ParseGetValue(ss[2], varIndex);
}
else if (ss.Length == 4 && ss[2].ToLower == "not")
{
il.ParseGetValue(ss[3], varIndex);
il.Emit(OpCodes.Not);
}
else
{
il.ParseGetValue(ss[2], varIndex);
il.ParseGetValue(ss[4], varIndex);
il.ParseBinaryOperation(ss[3].ToLower;
}
il.SetValue(rvalue);
}
else if (ss[0].ToLower == "print")
{
il.ParseGetValue(ss[1], varIndex);
il.Out;
}
else if (ss[0].ToLower == "goto")
{
var label = label_marks[ss[1].ToLower];
il.Goto(label);
}
else if (ss[0].ToLower == "if")
{
il.ParseGetValue(ss[1], varIndex);
il.ParseGetValue(ss[3], varIndex);
il.ParseBinaryOperation(ss[2]);
var label = label_marks[ss[5].ToLower];
il.IfGoto(label);
}
else
throw new Exception(string.Format("invalid action: {0}", line;
}
static ValueReference ParseVarId(this ILGenerator il, string varNum, Dictionary<string, ValueReference> varIndex)
{
if (varIndex.ContainsKey(varNum
return varIndex[varNum];
else
{
var valueRef = new ValueReference { ValueRef = il.DeclareLocal(typeof(int ValueIsInitRef = il.DeclareLocal(typeof(bool };
varIndex[varNum] = valueRef;
return valueRef;
}
}
class ValueReference
{
public LocalBuilder ValueRef;
public LocalBuilder ValueIsInitRef;
}
public static int Mod(int x, int y)
{
int result = x % y;
if (result < 0)
{
if (y > 0)
return result + y;
else
return result - y;
}
return result;
}

static void ParseBinaryOperation(this ILGenerator generator, string operation)
{
switch(operation)
{
case "%":
generator.Emit(OpCodes.Call, typeof(Program).GetMethod("Mod";
return;
case "!=":
generator.Emit(OpCodes.Ceq);
generator.Emit(OpCodes.Ldc_I4_0);
generator.Emit(OpCodes.Ceq);
return; ;
case ">=":
{
Label label3 = generator.DefineLabel;
Label label4 = generator.DefineLabel;
generator.Emit(OpCodes.Bge_S, label3);
generator.Emit(OpCodes.Ldc_I4_0);
generator.Emit(OpCodes.Br_S, label4);
generator.MarkLabel(label3);
generator.Emit(OpCodes.Ldc_I4_1);
generator.MarkLabel(label4);
return;
}
case "<=":
{
Label label3 = generator.DefineLabel;
Label label4 = generator.DefineLabel;
generator.Emit(OpCodes.Ble_S, label3);
generator.Emit(OpCodes.Ldc_I4_0);

karkar

вот этот тест она же не проходит
Это я изначально пропустил условие "initialized to this moment variables", щас поправлю. По идее, старые варианты тоже могли лишние переменные выводить..

Dasar

0.01 секунду нашел, где терялась

== ocaml ==
-12
Program terminated. Variables state:
Value: 3
ValueA: 3
value: -2499999
x: 0

profiling:
main 0.080718
== c# 3.5 ==
-12
Program terminated. Variables state:
Value: 3
ValueA: 3
value: -2499999

00:00:00.0941693

agaaaa

185 мс на второй тест
потом допишу тест инициализации переменных и вывод

Dasar

> 185 мс на второй тест
лучше exe-шник запости

karkar

Нашел у себя более серьезную ошибку, чем вывод лишних переменных. Переделал оптимизацию, теперь вроде нормально, заодно скорость поднялась: теперь мой вариант в 1,5 раза быстрее компилирующего решения на С# при числе строк в 2.5 раза меньшем (по объему в 1,5 раза). :)
== ocaml == 
-12
Program terminated. Variables state:
Value: 3
ValueA: 3
value: -2499999

profiling:
main 0.072100

== c# 3.5 ==
-12
Program terminated. Variables state:
Value: 3
ValueA: 3
value: -2499999

00:00:00.1109740

Dasar

сделай,плиз, настройку - которая меняет макс. кол-во шагов (которое сейчас 10 миллионов).
ps
теперь мой вариант в 1,5 раза быстрее компилирующего решения на С# при числе строк в 2.5 раза меньшем
не совсем так, что и можно будет увидеть - если сделаешь настройку по кол-ву шагов.
оно не в 1.5 раза быстрее, а быстрее на 0.04 секунды

karkar

Вот.
Число итераций указывается первым аргументом, если не указано, то 10 млн. Больше миллиарда ставить не советую - переполнение случится.
Результат на 500 млн:
 -12
Program terminated. Variables state:
Value: 5
ValueA: 5
value: -124999999

profiling:
main 3.595241

agaaaa

с зависимостями не влезет
внешняя ссылка пойдёт?

karkar

сделай,плиз, настройку - которая меняет макс. кол-во шагов
Можешь тоже такую сделать?

bleyman

Хо-хо, я тоже написал немножко кода, вот
http://pastebin.com/f57395eb3
Типа, это скорее "красивый", чем "быстрый" вариант. Строк довольно много, но в основном они на утилиты всякие ушли, сам парсер занимает 70 строчек, ну и вообще, я как бы к читабельности стремился, а не к минимизации количества строк.
А насчёт скорости - хз. Индексы в массивах переменных и лабелей вычисляются при компиляции и упаковываются в лямбды (кстати я не знаю, чего вначале по крайней мере так не сделал. Уж функционалить - так функционалить!). То есть совсем вот так:
		Func<int> Arg(string s)
{
int val;
if (int.TryParse(s, out val
{
return => val;
}
else
{
val = variables[s];
return => variables[val].Value;
}
}

А писать настоящий компилятор что-то влом =)
Люто-бешено не хватает всё-таки в шарпе каких-нибудь туплов. Чё за ёбаный стыд вообще, даже в C++0x будут туплы! Хочу туплы! И возможность написать Bind не как у меня, а нормальный!

Dmitriy82

А в чём проблема сделать туплы шаблоном?
(так же как pair в с++)

bleyman

Проблема в том, что, кажется, невозможно в результате по ним полиморфиться. В плюсах шаблоны всё-таки тьюринг-полные, тут не так. Ну, ты ж посмотрел на мой код, наверное: вот я хотел бы иметь возможность объявить T Bind<T>(string[] values, tuple<Z> args, Func<tuple<Z>, T> f внутри которой я мог бы ходить по args и в зависимости от типа делать всякое. Ну, то есть вообще нет никакого аналога питоновской звёздочки в параметрах. Если у меня есть Func<int, int, int>, то я обязан вызвать её именно с двумя интами, а не с Pair<int, int>.
Не знаю, может можно как-то это хитроумно обойти.

Dasar

Индексы в массивах переменных и лабелей вычисляются при компиляции и упаковываются в лямбды (кстати я не знаю, чего вначале по крайней мере так не сделал. Уж функционалить - так функционалить!).
полученная после парсинга "программа" становится не реентерабельна, т.к. начинает зависит от экземпляра context (или variables в твоем случае)

Dasar

Добавил простейшую оптимизацию, теперь мой вариант вдвое быстрее самого быстрого на C# 3:
оказалось, что основная херотень в операции % (она делается как-то жутко медленно)
если этой операции нет, то C# в 3 раза быстрее - позже попробую посмотреть почему

value = 15
value = not value
value = value or 4
print value
value = 0
loop:
value = value - 1
tmp_1 = value / 6
tmp_2 = value * 6
Value = value - tmp_2
tmp_3 = Value / -6
tmp_4 = value * -6
ValueA = value - tmp_4
goto loop

x = 5


результат

== ocaml ==
-12
Program terminated. Variables state:
Value: 312499995
ValueA: -437499993
tmp_1: -10416666
tmp_2: -375000000
tmp_3: -52083332
tmp_4: 374999994
value: -62500000

profiling:
main 6.558936
== c# 3.5 ==
-12
Program terminated. Variables state:
Value: 312499995
ValueA: -437499993
tmp_1: -10416666
tmp_2: -375000000
tmp_3: -52083332
tmp_4: 374999994
value: -62500000

00:00:02.0252661

Dasar

разобрался.
вообщем, в C# операции деления и взятия остатка тормозные, потому что туда запихивается код проверки на 0 и код кидания managed исключения в этом случае
соотвественно если тест состоит из одних делений(остатков от деления) - то он получается проигрышный для C#.
если команд делений нет, то ocaml проигрывает в 15 раз

== ocaml ==
-12
Program terminated. Variables state:
Value: 0
ValueA: 0
atmp_1: -62500006
atmp_2: -62500000
atmp_3: -124999998
atmp_4: -62499999
value: -62500000

profiling:
main 9.380737
== c# 3.5 ==
-12
Program terminated. Variables state:
Value: 0
ValueA: 0
atmp_1: -62500006
atmp_2: -62500000
atmp_3: -124999998
atmp_4: -62499999
value: -62500000

00:00:00.5670065


value = 15
value = not value
value = value or 4
print value
value = 0
loop:
value = value - 1
atmp_1 = value - 6
atmp_2 = atmp_1 + 6
Value = value - atmp_2
atmp_3 = value * 2
atmp_4 = atmp_3 - value
ValueA = value - atmp_4
goto loop

x = 5


т.е. команда без деления делается C#-ом где-то в 15 раз быстрее ocaml, а команда с делением в 3 раза тормознее ocaml-а
вариант с изменением кол-ва итераций
вызов
coderunner 3.timus 500000000

sergeikozyr

У тебя используется нативный инт, или тот, который "особый, окамловый инт"? Второй вариант объяснял бы разницу в скорости арифметических операций

karkar

У меня "особый, окамловый инт". Не уверен, что Int32 будет быстрее - с ним работа не очень прямая, вроде. Но можно попробовать..
Заменил в исходном тесте % на +, действительно компилирующий вариант на C# стал обгонять в несколько раз на большом числе итераций. Как-никак компилятор vs. интерпретатор сравнивается.
//только сейчас узнал новый адрес форума, спасибо гуглу, нашедшему ЖЖ бурарума.
Оставить комментарий
Имя или ник:
Комментарий: