Здравствуйте, sergey_shandar, Вы писали:
_>Может здесь передавать указатель на какую то структуру состояния, вместо двух параметров? Интересно, замедлит это или наоборот ускорит? Но, по моему, это более симпатичнее.
Я не случайно указал __fastcall все параметры в функцию передаются через регистры чем компилятор и воспользовался.
; 14 : double* s=&stack[0];
; 15 : for(std::vector<token>::iterator i=tokens.begin(), e=tokens.end();i!=e;++i)
cmp esi, edi
mov eax, DWORD PTR [ecx+12]
mov DWORD PTR _s$[esp+12], eax
je SHORT $L113694
$L113692:
; 16 : i->operation_fn(s, *i);
mov edx, esi
lea ecx, DWORD PTR _s$[esp+12]
call DWORD PTR [esi]
add esi, 16 ; 00000010H
cmp esi, edi
jne SHORT $L113692
$L113694:
_>Тогда сдвиг итератора i WH>> for(std::vector<token>::iterator i=tokens.begin(), e=tokens.end();i!=e;++i) _>можно вынести в функции, если вынести i в процесс (это может быть полезно если в дальнейшем совершенствовать этот калькулятор, например сделать оператор if в выражениях). И условие выхода сделать в виде флага, а функция устанавливающая этот флаг пусть находиться в самом конце вектора tokens.
1)Это замедлит вычисления.
2)Этого в задаче небыло. И у меня нет жилания делать полноценный интерпритатор некоторого недо языка.
... << RSDN@Home 1.1.3 beta 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[5]: Частые вычисления по неопределенной формуле!!!
Здравствуйте, c-smile, Вы писали:
CS>Медленнее но "тильке трошки-трошки". CS>На самом деле ты прав наверное. Надо еще раз проверять. CS>С учетом function callв моем случае может и медленнее мой вариант.
Вот и проверь.
... << RSDN@Home 1.1.3 beta 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: Частые вычисления по неопределенной формуле!!!
Сначала о результатах. Вот результаты C#-варианта:
Парсинг 10 проходов. Выполнено за 1.09794569 сек.
Подсчет 10000 проходов. Выполнено за 0.00378456 сек.
Подсчет 10000 проходов. Выполнено за 0.00379629 сек.
А вот малость переработанного варианта от WolfHound скомпилированного в анменеджед-релиз на VCX 7.1:
calc1_calculate
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
average all = 0.134409
average middle = 0.133799
calc2_calculate
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
average all = 0.0775661
average middle = 0.0772016
calc3_calculate
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
average all = 0.0776748
average middle = 0.0774767
Переработка заключалась в том, что я для ххх_calculate-тестов вынес парсинг за пределы измеряемой зоны. Естественно это ничего не дало, так как 10 000 итераций не идут ни в какое сравнение с одним проходом парсинга, но все же... чистота эксперемента тык-сызыть.
В приведенной выше ссылке я обещал WolfHound, что мой вариант сделает его на порядок. Примерно так и вышло. Лучшее время его варианта примерно в 20 раз меньше.
Вы спросите как удалось добиться таких показателей? Гы-гы. Библиотеки у дотнета лучше. Ну, и как я уже говорил WolfHound выбрал принципиально далекое от оптимальности решение.
Чем не оптимальное? А... Он выбрал интерпретацию вместо компиляции. А она в худшем раскладе в разы медленнее. (Обычно на порядок.)
Суть моего решения элементарна. В программе где требуется вычислять формулы задаваемые строкой объявляется интерфейс в котором описываются сигнатуры методов. Далее они скармливаются простенькому энжину который на лету компилирует реализации и возвращает ссылку на сборку. От сборки получается ссылка на интерфейс, по которой и осуществляется вызов.
Вот так выглядит код теста:
class EntryPoint
{
const int CalcCount = 10000;
const int ParseCount = 10;
static void Main(string[] args)
{
//string formula = "asd + qwe";string formula =
"-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234"
+ "-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234"
+ "-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234"
+ "-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234"
+ "-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234-(asd-qwe)*3*3*asd/(asd-sin(qwe)+5/asd)-123.234";
PerfCounter timer = new PerfCounter();
//////////////////////////////////////////////////////////////////////
/// Разбор.
ICalc1 calc1 = null;
timer.Start();
for (int i = 0; i < ParseCount; i++)
calc1 = Calc1Impl.Prepare(formula);
// Пре-компиляция
calc1.Calc(1, 1);
Console.WriteLine("Парсинг {1} проходов. Выполнено за {0:F8} сек.",
timer.Finish(), ParseCount);
//////////////////////////////////////////////////////////////////////
/// Вычисления. Первый проход.
timer.Start();
for (int i = 0; i < CalcCount; i++)
calc1.Calc(i, i);
Console.WriteLine("Подсчет {1} проходов. Выполнено за {0:F8} сек.",
timer.Finish(), CalcCount);
//////////////////////////////////////////////////////////////////////
/// Вычисления. Второй проход.
timer.Start();
for (int i = 0; i < CalcCount; i++)
calc1.Calc(i, i);
Console.WriteLine("Подсчет {1} проходов. Выполнено за {0:F8} сек.",
timer.Finish(), CalcCount);
Console.WriteLine("Calc(1, 1) = {0}", calc1.Calc(1, 1));
Console.WriteLine("Calc(-1, 333) = {0}", calc1.Calc(-1, 333));
Console.WriteLine("...");
Console.ReadLine();
}
}
А вот и реализация...
Сначала энжин компиляции:
using System;
using Microsoft.CSharp;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Reflection;
namespace FuncEvalCs
{
public class CalcEngine
{
public static Assembly Prepare(string code)
{
CompilerParameters compparams = new CompilerParameters();
compparams.IncludeDebugInformation = false;
compparams.CompilerOptions = @"/optimize+";
compparams.GenerateExecutable = false;
// В релаьной программе скомпилированные сборки можно кэшировать.
// Для этого нужно отключить компиляцию в память и задать имя сборки
compparams.GenerateInMemory = true;
// compparams.OutputAssembly = @"c:\mySample.dll";
compparams.ReferencedAssemblies.Add("System.dll");
// Задаем ссылку на сборку производящую вызов. Это нужно для того
// чтобы создаваемая сборка могла использовать типы из нее.
// В частности чтобы можно было использовать интерфейсы через которые
// будет производиться вызов.
// В принципе если производить вызовы через рефлексию или делегаты,
// этот момент можно избежать.string thisAsmPath = Environment.CurrentDirectory + @"\FuncEvalCs.exe";
compparams.ReferencedAssemblies.Add(thisAsmPath);
CSharpCodeProvider cscp = new CSharpCodeProvider();
ICodeCompiler cscompiler = cscp.CreateCompiler();
// Компилируем код из строки.
CompilerResults compresult =
cscompiler.CompileAssemblyFromSource(compparams, code);
// Если есть ошибки выводим сообщения о них...if (compresult == null || compresult.Errors.Count > 0)
{
for (int i = 0; i < compresult.Output.Count; i++)
Console.WriteLine(compresult.Output[i]);
for (int i = 0; i < compresult.Errors.Count; i++)
Console.WriteLine(i + ": " + compresult.Errors[i].ToString());
return null;
}
// Возвращаем скомпилированную сборку.return compresult.CompiledAssembly;
}
}
}
Интерфейс используемый для вызова формулы (их может быть любое количество и они могут содержать любое количество методов, в данном случае один — калька с теста WolfHound-а):
public interface ICalc1
{
double Calc(double asd, double qwe);
}
А вот код необходимый для реализации интерфейса:
using System;
using System.Reflection;
namespace FuncEvalCs
{
public class Calc1Impl
{
public static ICalc1 Prepare(string formulaCode)
{
// замена sin на Math.Sin нужна исключительно для совместимости
// с примером WolfHound-а.
formulaCode = formulaCode.Replace("sin", "Math.Sin");
formulaCode = formulaCode.Replace("cos", "Math.Cos");
Assembly asm = CalcEngine.Prepare(
@"
using System;
using FuncEvalCs;
class EntryPoint : ICalc1
{
public double Calc(double asd, double qwe)
{
return " + formulaCode + @";
}
}
");
return (ICalc1)asm.CreateInstance("EntryPoint");
}
}
}
Естественно, что текст формул можно заменять динамически... как в прочем и реализацию вообще.
ЗЫ
Итого в сухом остатке мы имеет:
1. Более чем в 20 раз высокую скорость исполнения. А если учесть, что можно использовать и более быстрые типы (например, int), то и 20 раз не предел.
2. Возможности по оптимизации вычислений. Ведь Jit-компилятор производит довольно неплохую оптимизацию.
3. Динамическое расширению библиотек и фасадного кода.
4. Возможность использовать любых функций (как из стандартной библиотеки дотнета — FCL, так и собственны).
5. Намного более мощный энжин вычислений. Синтаксис Шарпа или Васика (который тоже можно сюда подключить) куда мощнее примитивных самопальных парсеров.
6. Возможность подключения любого доступного для дотнета языка. Например, можно подключить функциональные языки вроде SML-я или Ocaml-а.
7. Типизированный парсер. Интерфейс не обязан работать с double-ами, как у WolfHound-а. Параметры могут передаваться по ссылке, быть пользовательского типа или массива.
8. Можно кэшировать результат компиляции, что значительно сократит время на повторные запуски.
9. Полноценные сообщения об ошибках.
10. Размер исполняемого файла 20 килобайт. Перекомпилированный нэйтив-мидж 16 кил. Размер генерируемой сборки 4 кил. Для сравнения размер по сравнению с 180 килобайтами у WolfHound-а (это еще в моем, упрощенном варинтае изначально он занимал 250 кил (по словам WolfHound-а)). Самым же смешным оказалось сравнение места занимаемого данными тестами после компиляции в релиз и дебаг... Проект на Шарпе занял 146 кил. А вот проект на С++ занял (ни за что не догадаетесь) 104... но мегабайта! Все "богатство" естественно находится в каталогах Debug и Release. Первый занимает 49 мег., а второй 54. И все это "богатство", вы не поверите, с 19 кил исходников.
Если сравнивать размеры исходников, то один (самый шустрый) С++-вариант занимает 10 кил. Вариант же на Шарпе занимает 6 кил.
11. Более точные вычисления с плавающей точкой .NET использует для таких вычислений возможности текущего процессора. Например, на последних Intel-ах вычисления приводятся с точностью значительно превышающую возможности double-а. Так что если при вычислениях результаты превышают размеры double-а, точность не теряется.
Единственный минус — это скорость компиляции. Конечно полноценный компилятор, да к тому же двухфазный (сначала в MSIL, а потом ище и джит), не так шустр, но по условию темы — это вроде не критично.
Ну, и еще, если конечно это вообще недостаток — это дотнет.
2 WolfHound: Как я и говорил, разница в два раза между компиляторами просто фигня по сравнению с выбором оптимального решения/алгоритма/библиотеки.
Если же приспичит писать собственные парсеры, то нужно выбирать проверенные временем, дедовские способы — генераторы парсеров вроде yacc-а или Coca-и, а не заниматься извращениями на шаблонах. Тогда все не нужное в ратайме останется в компайл-тайме, а работа будет проще, качественнее и будет намного проще поддаваться расширению.
2 GrayWizard: Если тебе не приемлем .NET, то того же можно добиться и с помощью обычного компилятора C++. Правда повозиться придется несколько больше и скорость компиляции будет скорее всего ниже (особенно при массе инклюдов). Но тем не менее ты получишь значительно более шустрое и компактное решение нежели используя самопальный интерпретатор. На сегодня бесплатно доступны очень приличные компиляторы: бесплатный VC (правда похоже в нем нет многих оптимизаций как в коммерческом варианте, но все же это куда быстрее чем интерпретация), бесплатный BCC (Borland-овский компилятор добротен но не шустр), GCC (тянет за собой откровенно говоря не скромный по размерам runtime и не может поставляться совместно с коммерческим продуктом, так как GNU-ый, но зато самый быстрый из перечисленных вариантов). Ну, и если разработка внутренняя, то вообще нет проблем. Бери коммерческий VC или Intel C++. Будет и самый быстрый код.
... << RSDN@Home 1.1.3 beta 2 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Частые вычисления по неопределенной формуле!!!
Может я чего-то не понял, но ИМО говоря о плюсах использования компилятора в ран-тайме ты умолчал о минусах.
Близкий пример. Когда-то я слабал калькулятор на jscript, который использовал интерпретатор jscript для вычисления введенного мат. выражения, не производя самостоятельный разбор выражения. Так вот, если вместо "1+2" написать например "window.close()", то окно закрывалось.
Конечно приятно считать это фичей, но по существу для калькулятора это дыра.
Здравствуйте, folk, Вы писали:
F>Может я чего-то не понял, но ИМО говоря о плюсах использования компилятора в ран-тайме ты умолчал о минусах.
F>Близкий пример. Когда-то я слабал калькулятор на jscript, который использовал интерпретатор jscript для вычисления введенного мат. выражения, не производя самостоятельный разбор выражения. Так вот, если вместо "1+2" написать например "window.close()", то окно закрывалось. F>Конечно приятно считать это фичей, но по существу для калькулятора это дыра.
Для этого есть Code Access Security. И можно коду этих выражений так яйца в тиски закрутить, что он даже взгляд кинуть куда не надо не посмеет. Это вам не С++
... << RSDN@Home 1.1.3 beta 2 >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Частые вычисления по неопределенной формуле!!!
Здравствуйте, VladD2, Вы писали:
VD>В приведенной выше ссылке я обещал WolfHound, что мой вариант сделает его на порядок. Примерно так и вышло. Лучшее время его варианта примерно в 20 раз меньше.
Не так-то все однозначно. Допустим пользователю по каждой новой формуле нужно сделать не более N операций. Для каких N твоя реализация будет быстрее, чем WolfHound-а? N > 3000. Если, например, эти вычисления встроены в программу электронной таблицы, то N явно < 3000, и реализация с отдельным вызовом компилятора не годится. А если N ~ 100, то, наоборот, программа WolfHound-а становится в 20 раз быстрее твоей.
Re[2]: Частые вычисления по неопределенной формуле!!!
Уверен, что любой человек, хоть раз писавший на асме хоть чуть-чуть, способен в принципе сотворить подобное.
VD>Библиотеки у дотнета лучше.
Ну, библиотеки тут не причем.
VD>10. Размер исполняемого файла 20 килобайт. Перекомпилированный нэйтив-мидж 16 кил. Размер генерируемой сборки 4 кил. Для сравнения размер по сравнению с 180 килобайтами у WolfHound-а (это еще в моем, упрощенном варинтае изначально он занимал 250 кил (по словам WolfHound-а)). Самым же смешным оказалось сравнение места занимаемого данными тестами после компиляции в релиз и дебаг... Проект на Шарпе занял 146 кил. А вот проект на С++ занял (ни за что не догадаетесь) 104... но мегабайта! Все "богатство" естественно находится в каталогах Debug и Release. Первый занимает 49 мег., а второй 54. И все это "богатство", вы не поверите, с 19 кил исходников.
А теперь приплюсуй к размеру проекта на Шарпе размера дотнетовского рантайма.
VD>Если сравнивать размеры исходников, то один (самый шустрый) С++-вариант занимает 10 кил. Вариант же на Шарпе занимает 6 кил.
А вот вообще круто. На c++ написан какие-никакие, но парсер и интерпретатор, а на шарпе написано обращение к библиотеке содержащей эти самые парсер и интерпретатор. К слову сказать, минимальный проект, использующий, например, lua, занимает поменьше 6кб. Есть например возможность быстро и легко использовать JavaScript, правда там я размер минимального проекта не скажу, но тоже в том же порядке.
VD>2 WolfHound: Как я и говорил, разница в два раза между компиляторами просто фигня по сравнению с выбором оптимального решения/алгоритма/библиотеки.
VD>Если же приспичит писать собственные парсеры, то нужно выбирать проверенные временем, дедовские способы — генераторы парсеров вроде yacc-а или Coca-и, а не заниматься извращениями на шаблонах. Тогда все не нужное в ратайме останется в компайл-тайме, а работа будет проще, качественнее и будет намного проще поддаваться расширению.
Собственно spirit по простоте поддержки и расширения гораздо лучше старых дедовских способов вроде yacc'а. Да и сам он скоро перейдет в разряд старых, дедовских способов.
VD>2 GrayWizard: Если тебе не приемлем .NET, то того же можно добиться и с помощью обычного компилятора C++. Правда повозиться придется несколько больше и скорость компиляции будет скорее всего ниже (особенно при массе инклюдов). Но тем не менее ты получишь значительно более шустрое и компактное решение нежели используя самопальный интерпретатор. На сегодня бесплатно доступны очень приличные компиляторы: бесплатный VC (правда похоже в нем нет многих оптимизаций как в коммерческом варианте, но все же это куда быстрее чем интерпретация), бесплатный BCC (Borland-овский компилятор добротен но не шустр), GCC (тянет за собой откровенно говоря не скромный по размерам runtime и не может поставляться совместно с коммерческим продуктом, так как GNU-ый, но зато самый быстрый из перечисленных вариантов). Ну, и если разработка внутренняя, то вообще нет проблем. Бери коммерческий VC или Intel C++. Будет и самый быстрый код.
ИМХО если уж таскать за собой компилятор, то какой-нибудь маленький и простой. Есть же компиляторы с C, а не с C++ хотя бы.
Но интереснее всего, как предполагается осуществлять взаимодействие с скомпилированным результатом? Компилировать в dll и динамически ее подлинковывать?
... << RSDN@Home 1.1.3 beta 2 >>
Re[3]: Частые вычисления по неопределенной формуле!!!
Здравствуйте, folk, Вы писали:
F>Может я чего-то не понял, но ИМО говоря о плюсах использования компилятора в ран-тайме ты умолчал о минусах.
F>Близкий пример. Когда-то я слабал калькулятор на jscript, который использовал интерпретатор jscript для вычисления введенного мат. выражения, не производя самостоятельный разбор выражения. Так вот, если вместо "1+2" написать например "window.close()", то окно закрывалось. F>Конечно приятно считать это фичей, но по существу для калькулятора это дыра.
Есля и начну говорить о минусах связаных с С++, то меня тут могут и поубивать.
С точки зрения защиты конечно плюсы в этой ситуации походят плохо. Но ведь скрипты могут понадобится и в местах где защита в общем то не нужна. Вдруг у них там какие-то инженерные рассчеты или еще что. Человек же не сказал о целях задачи.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Частые вычисления по неопределенной формуле!!!
Здравствуйте, alexkro, Вы писали:
A>Не так-то все однозначно. Допустим пользователю по каждой новой формуле нужно сделать не более N операций. Для каких N твоя реализация будет быстрее, чем WolfHound-а? N > 3000. Если, например, эти вычисления встроены в программу электронной таблицы, то N явно < 3000, и реализация с отдельным вызовом компилятора не годится. А если N ~ 100, то, наоборот, программа WolfHound-а становится в 20 раз быстрее твоей.
Я исходил из условий задачи. Да и описанная тобой ситуация встречается редко.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Частые вычисления по неопределенной формуле!!!
Здравствуйте, Рома Мик, Вы писали:
РМ>Уверен, что любой человек, хоть раз писавший на асме хоть чуть-чуть, способен в принципе сотворить подобное.
Все меньше и меньше таких людей отстается. И по-моему — это правильно.
VD>>Библиотеки у дотнета лучше. РМ>Ну, библиотеки тут не причем.
Кому как.
РМ>А теперь приплюсуй к размеру проекта на Шарпе размера дотнетовского рантайма.
Я знал, что это кто-нить скажет. Так вот дотнет входит во второй сервиспак к ХРюше. Во все остальные ОС он встроен штатно. Ну, и даже если его и нет, то ставится он один раз.
РМ>А вот вообще круто. На c++ написан какие-никакие, но парсер и интерпретатор,
Во-во. Никакие.
РМ>а на шарпе написано обращение к библиотеке содержащей эти самые парсер и интерпретатор.
Это называется фрэймворк.
РМ>К слову сказать, минимальный проект, использующий, например, lua, занимает поменьше 6кб. Есть например возможность быстро и легко использовать JavaScript, правда там я размер минимального проекта не скажу, но тоже в том же порядке.
Ну, минимальный проект я тоже в пару сотин байт умещу, вот только зачем? Качество не заменишь краткостью.
РМ>Но интереснее всего, как предполагается осуществлять взаимодействие с скомпилированным результатом? Компилировать в dll и динамически ее подлинковывать?
Общий принцип я уже продемонстрировал. Описываешь интерфейсыю... (для С++ за основу нужно взять КОМ-интерфейсы, т.е. классы с чисто виртуальными методами и без данных) Далаешь фабрику классов (опять же на подобии КОМ-а) которая возвращает ссылку на интерфейс реализуемый классам... Получаешь указатель... Приводишь его к указателю на требуемый интерфейс и пользуешся.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Частые вычисления по неопределенной формуле!!!
А если потребуется какойнибудь синтаксис который не поддерживается CodeDom.Compiler'ом?
Допустим заказчик хочет возводить в степень так "asd^(qwe*asd)"
Я всеголишь добавлю выделеное(Это переделаный calculator3 я его еще маленько порефакторил)
Здравствуйте, VladD2, Вы писали:
VD>А требуется?
Допустим
VD>О. Задача из серии неберучек.
Чего?
VD>Я там в коде меняю sin на Math.Sin... Подход в народе называется препроцесирование. Твой случай решается им на ура.
Уверен? И чтобы приоритет операций учесть... И скобочки...
VD>И получишь еще 100 кил кода.
Сколько было столько и осталось... Размер байт в байт совпадает...
VD>Ну, я как бы выше скзал. А вообще это синтаксис Васика. Так что моно его подключить.
А потом еще чего захотят... Типа плюсового a<b?a:b...
VD>Если уж писать полноценные парсеры, то делать это лучше на базе кодогенератора вроде яка или каки. Но об этоя я уже гворил. Вот сам этим и пользуйся
... << RSDN@Home 1.1.3 beta 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: Частые вычисления по неопределенной формуле!!!
Здравствуйте, VladD2, Вы писали:
VD>Если уж писать полноценные парсеры, то делать это лучше на базе кодогенератора вроде яка или каки. Но об этоя я уже гворил.
Непонятное утверждение. Чем yacc лучше spirit'а? Тем что он написан на C и генерит сишный же код, что засунуть в программу два парсера уже проблема?
... << RSDN@Home 1.1.3 beta 2 >>
Re[5]: Частые вычисления по неопределенной формуле!!!
Здравствуйте, Рома Мик, Вы писали:
РМ>Непонятное утверждение. Чем yacc лучше spirit'а?
Тем что он не приводит к неоправданному разбуханию кода, порождает более оптимальных код, позволяет проще расширять прогрмму, позволяет более качественно обрабатывать ошибки, да и вообще лучше поддается расширению и удобнее в работе.
РМ> Тем что он написан на C и генерит сишный же код, что засунуть в программу два парсера уже проблема?
Нет конечно. Ты просто недооцениваешь современные yacc-и и им подобные программы. Они уже давно научились генерировать код не только на С. Парсер Моно — это модификация якак (по имени jay) генерирующая ОО-код на C# (или Яве), например.
Наш R# делается с использованием CocoR. Есть еще ANTLR и много других.
... << RSDN@Home 1.1.3 beta 2 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Частые вычисления по неопределенной формуле!!!
Здравствуйте, WolfHound, Вы писали:
VD>>А требуется? WH>Допустим
В том то и дело что задача больно гипотетическая. Время компиляции в десятые доли секунды вряд ли является проблемой для большинства задач. А вот идиальную скорость выполнения заполучить хочется очень часто.
VD>>О. Задача из серии неберучек. WH>Чего?
В детском саду била такая прилипчивая поговорка. "Ххх небуручка, кто взял, то ванючка." .
VD>>Я там в коде меняю sin на Math.Sin... Подход в народе называется препроцесирование. Твой случай решается им на ура. WH>Уверен? И чтобы приоритет операций учесть... И скобочки...
Скобки сами собой учтутся. В общем, что выдумывать. Создавать свой язык из-за вычислителя формул не размумно. Проще взять готовый.
VD>>И получишь еще 100 кил кода. WH>Сколько было столько и осталось... Размер байт в байт совпадает...
Ага. Я из твоего кода выкинул пару фигни и 40 кил как ххх сбрило.
VD>>Ну, я как бы выше скзал. А вообще это синтаксис Васика. Так что моно его подключить. WH>А потом еще чего захотят... Типа плюсового a<b?a:b...
У парня в задаче кажется было оговорена максимальная скорость. Ты мне пел что твое решение самое оптимальное, и ни на чем кроме плюсов его сделать эффективно нельзя (что само по себе ерунда). Я тебе сделал не напрягаясь. Получилось быстрее и проще. Заменил тык сызить одну либу на другую.
VD>>Если уж писать полноценные парсеры, то делать это лучше на базе кодогенератора вроде яка или каки. Но об этоя я уже гворил. WH> Вот сам этим и пользуйся
Сам и пользуюсь. А опечатки и у тебя не редкость. Хотя мои конечно круче.
... << RSDN@Home 1.1.3 beta 2 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.