Кот: оцените плз
И чё за слайс дурацкий? Ты его откуда взял вообще? Посмотри на питоновский, надо так и только так делать.
Так только пишут что-нибудь очень большое корпоративное с надеждой сдать это лет так через 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];
}
}
}
но основных фишек последних шарпов: 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
И чё за слайс дурацкий? Ты его откуда взял вообще?Руками наговнокодил.
ArraySegment<T> можно было бы преобразовать в массив, если бы разработчики дотнета об этом подумали, но они об этом не подумали, и никакого ToArray у него почему-то нет.
Посмотри на питоновский, надо так и только так делать.А как сделано в питоне?
Не понимаю, что тебе не нравится. Мне нужно именно получить кусок массива, и это решается одной строчкой (ну, на самом деле, тремя). Для того, чтобы было удобно им пользоваться - я сделал возможность указывать отрицательные offset (ещё три строчки) и count (ещё три). Не так уж и страшно всё это выглядит.
А если ты про скорость работы... если бы мне нужно было что-то супербыстрое, я бы использовал ArraySegment<T>. Но мне нужен именно T[].
Ничего личного, но я привык совсем не к таким отступам, и в твоём примере довольно сложно такие ошибки отлавливать; а тебе?
Потому что переменных в условии - хитрые (uint32 со знаком их надо реализовывать руками, и самому же руками реализовывать методы сложения, вычитания итп; для того, чтобы можно было их в другом месте заюзать - эти методы, конечно же, должны быть в классе переменной. И тогда уже анонимные методы в самом выполнении программы ничего не дадут.
Анонимных методов в 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-е он есть.
надо только покрутить настройки культуры и т.д, чтобы сортировалось так же как в условии.
А всё это реализовывать - довольно грязно.только с метками есть трудности: т.к. может быть переход вперед на еще необъявленную метку, но это можно обойти через двойной проход
нумерация переменных вообще легко делается
Кстати, у тебя там вообще баг на баге. Что делать будем, если кто-то обозвал переменную goto, end или if?согласен.
надо переставить блок с обработкой равенства на первое место
и в твоём примере довольно сложно такие ошибки отлавливать; а тебе?без проблем
Потому что переменных в условии - хитрые (uint32 со знаком их надо реализовывать рукаминет там ничего хитрого.
обычный знаковый int.
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];
}
}
}
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;
}
}
}
надо переставить блок с обработкой равенства на первое местои строчку с разбором not заменить на
else if (ss.Length == 4 && ss[2].ToLower == "not")
var keys = programContext.VarIndex.Keys.ToArray;
Array.Sort(keys, StringComparer.Ordinal);
foreach (var var in keys)
вот с идентификацией переменных по номеру. стало в два раза быстрее, и 10 лимонов укладывается в секунду у менятак это еще все в debug-е выполнялось.
в release-е стало еще быстрее процентов на 70%
в итоге: 10лимонов за 0.3 секунды
только с метками есть трудности: т.к. может быть переход вперед на еще необъявленную метку, но это можно обойти через двойной проходДа, но надо попотеть.
нумерация переменных вообще легко делается
а вот плодить тупо методы 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)
Видимо, запрещена у них криптография...

нет там ничего хитрого.А это что?
обычный знаковый int.
Предполагается, что в процессе вычислений все значения хранятся в виде 4--байтовых целых чисел, отрицательные числа кодируются в дополнительном коде.Кроме того, там у них побитовые операции и деление с остатком над такими числами, насколько я понял, хитрые.
А то, что я написал (где Func<T, TResult>) можно легко переписать под 2.0?достаточно добавить
public delegate TResult Func<T, TResult>(T arg);
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
А это что?System.Int32
Предполагается, что в процессе вычислений все значения хранятся в виде 4--байтовых целых чисел, отрицательные числа кодируются в дополнительном коде.а System.Int32 как по твоему отрицательные числа хранит?
Кроме того, там у них побитовые операции и деление с остатком над такими числами, насколько я понял, хитрые.а System.Int32 как по твоему эти операции делает?
а System.Int32 как по твоему отрицательные числа хранит?Насколько я понял, тут имеется в виду - "4байтовые беззнаковые целые + дополнительный флаг для знака", то есть, на один бит больше, чем в int32.
а System.Int32 как по твоему эти операции делает?Судя по обсуждению задачи - не так.
Впрочем, я особо не вчитывался.
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
public static readonly Func<Variable, Variable, Variable>а додиез разве не позволяет как-то сократить эту запись?
return (
Bytes[0] + 256*(
Bytes[1] + 256*(
Bytes[2] + 256*(
Bytes[3] + 256*(
Bytes[4] + 256*(
Bytes[5] + 256*(
Bytes[6] + 256*(
Bytes[7]
)
)
)
)
)
)
)
);
фак, мой мозг!
200 строк и 7 килобайт кода - я чуть глаза н сломал

это порт под 2.0, в 3.5 он лучше смотрелся.
в 3.5 он лучше смотрелся.
а в этом треде он был?
а то все читать - глаза жалко

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

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

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

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

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

задачи требующие автоматизации.
с таким определением много чего можно промышленным назвать

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

ЗЫ вообще мне на С# как-то пофиг в целом, просто вроде как не самый старый язык а на такой простой задаче решение ВЫГЛЯДИТ имхо просто ужасающе
Так ты бы написал реализацию задачи на другом языке. Чтобы работала так же быстро. И была бы хоть наполовину читаемой с нуля. А мы бы поглядели и согласились, что бывают очень удобные, читаемые, быстро работающие языки программирования.
Жаль, там на немейнстримных языках не принимают решения, нельзя узнать, все ли тесты проходит.
Ниже мое наколенное решение на 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.. Пришлось это учитывать отдельно.
Потому что естественное определение остатка от деления a на b>0: это такое число 0<=r<b, что a=b*q+r для некоторого целого q. Альтернативные варианты по-моему возникают от кривизны и непоследовательности.
Сравнил с Даркгреевским вариантом на C0 (C# 3.0 негде проверить получилось более чем в 2 раза короче по числу строк и объему исходникавариант -я для 3.0 занимает 4,733 bytes
твой вариант 4,593 bytes.
Где ты видишь два раза?
а сделай, плиз, чтобы она время выполнения печатала
Где ты видишь два раза?
Перечитай с каким вариантом я сравнивал.
2 = 3
4 = 2 * 2
print 4
Выводит 9.

а сделай, плиз, чтобы она время выполнения печаталаНовый вариант (исходник там же):
Перечитай с каким вариантом я сравнивал.так сравнивай с сильным вариантом
зачем сравнивать со слабым вариантом?
вот сильный вариант:
сейчас мой и твой вариант идут вровень. на моем компе: 0.22-0.24 секунды
ps
а запасы по ускорению у тебя еще есть?
стало так:
== 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
зачем сравнивать со слабым вариантом?
У меня просто нет ни компилятора C# 3.0, ни нужного фреймворка сейчас, поэтому ни скомпилить ни даже запустить твой свежий пример не могу.
Поставил качаться FW3.5, 200 мегов... Некорректный и нерелевантный оффтоп: мое решение не требует никаких фреймворков и работает сразу.
Запасы по ускорению... Не знаю. Без заметного изменения кода прямо сразу не вижу.
А какие времена получаются с учетом стартапа - от запуска программы до ее завершения? В исходной задаче ведь именно это время важно.
Edit: уже сам запустил и померял, твой вариант действительно быстрее (0,25 против 0,28 с).
сравнивай с сильным вариантом
Это последний? Он примерно втрое длиннее по строкам и вдвое по объему.
Это последний? Он примерно втрое длиннее по строкам и вдвое по объему.да, последний.
по объему он более раздутый - потому что это еще черновой вариант
меня интересует, что в нем такого, что он производственный, а, скажем, питон - нетсколько стоит настроить рабочее место разработчика под питон?
ЗЫ вообще мне на С# как-то пофиг в целом, просто вроде как не самый старый язык а на такой простой задаче решение ВЫГЛЯДИТ имхо просто ужасающе
сколько стоит разработка формочки с одним гридом под питон?
сколько стоит стыковка с правами AD под питон?
сколько стоит достижение максимально возможной скорости на отдельном куске кода под питон?
сколько стоит сделать сервис на одну функцию под питон?
сколько стоит вывести таблицу на принтер, в pdf, в word, в excel под питон?
сколько стоит возможность подключить дизайнера к оформлению пользовательского интерфеса под питон?
сколько стоит оформить кусок питона как отдельную готовую либу?
сколько стоит возможность распараллелить разработку одной программы на десять человек под питон?
и т.д.
сколько стоит настроить рабочее место разработчика под питон?"настроить рабочее место" - это типа стул отрегулировать под рост разработчика?
"настроить рабочее место" - это типа стул отрегулировать под рост разработчика?если брать в общем, то да:
настроить рабочее место = кусок помещения + мебель + СКС + железо + ПО + настройка всего этого под конкретного человека
здесь же интересовало только ПО и его настройка, т.к. все остальное в целом не зависит от языка разработки.
получилось более чем в 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

Ну скорость маленькая, конечно. Все таки интерпретатор.

Что за язык? Q? K? J?
Какова скорость в цифрах? Сколько времени ушло на написание?
Q. Писал долго, но это потому, что задача не очень хорошо на на векторный язык ложится. Скорость - в 100 раз медленнее чем у дарк грея, т.е. миллион за 3.4 секунды.
#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 строки (но с выводом отладочной и без вывода значений переменных)
поскольку это не интерпретатор, скорость феерическая
== 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 строк.
скорость феерическаяА в цифрах?

вот этот тест она же не проходит
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
== 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);
вот этот тест она же не проходитЭто я изначально пропустил условие "initialized to this moment variables", щас поправлю. По идее, старые варианты тоже могли лишние переменные выводить..
== 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
потом допишу тест инициализации переменных и вывод
лучше exe-шник запости

== 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
ps
теперь мой вариант в 1,5 раза быстрее компилирующего решения на С# при числе строк в 2.5 раза меньшемне совсем так, что и можно будет увидеть - если сделаешь настройку по кол-ву шагов.
оно не в 1.5 раза быстрее, а быстрее на 0.04 секунды
Число итераций указывается первым аргументом, если не указано, то 10 млн. Больше миллиарда ставить не советую - переполнение случится.
Результат на 500 млн:
-12
Program terminated. Variables state:
Value: 5
ValueA: 5
value: -124999999
profiling:
main 3.595241
внешняя ссылка пойдёт?
сделай,плиз, настройку - которая меняет макс. кол-во шаговМожешь тоже такую сделать?
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 не как у меня, а нормальный!
(так же как pair в с++)
Не знаю, может можно как-то это хитроумно обойти.
Индексы в массивах переменных и лабелей вычисляются при компиляции и упаковываются в лямбды (кстати я не знаю, чего вначале по крайней мере так не сделал. Уж функционалить - так функционалить!).полученная после парсинга "программа" становится не реентерабельна, т.к. начинает зависит от экземпляра context (или variables в твоем случае)
Добавил простейшую оптимизацию, теперь мой вариант вдвое быстрее самого быстрого на 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
вообщем, в 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
У тебя используется нативный инт, или тот, который "особый, окамловый инт"? Второй вариант объяснял бы разницу в скорости арифметических операций
Заменил в исходном тесте % на +, действительно компилирующий вариант на C# стал обгонять в несколько раз на большом числе итераций. Как-никак компилятор vs. интерпретатор сравнивается.
//только сейчас узнал новый адрес форума, спасибо гуглу, нашедшему ЖЖ бурарума.
Оставить комментарий
kruzer25
Неполное решение вот этой задачи: http://acm.timus.ru/problem.aspx?space=1&num=1438 (неполное, потому что пока что ещё не разбирался с тем, как оно должно работать при отрицательных значениях).Как вы думаете, усвоил ли я что-нибудь из принципов C# и .NET за те полтора месяца, которые с ними работаю? На эту конкретную задачу в общей сложности было потрачено около одного рабочего дня.