Юрий, я вообще-то не теоретик, а весьма приземленный практик. Поэтому я постараюсь перевести разговор в более практическое русло.
Собственно говоря, я сам не первый год замужем, являюсь ортодоксальным фанатом C++ и по мере сил стараюсь отбивать нападки на C++ в "Философии программирования". Более того, мне самому нравится использовать C++ шаблоны (см., например, А generic-и так могут?
). И меня, как C++ программиста, интересуют и радуют всякие неожиданные находки в языке. Это забавно, познавательно, иногда полезно. Но...
Но многие изыски в области шаблонов и метапрограммирования на шаблонах кажутся мне вопиющим нарушением принципа KISS.
Хочу, чтобы меня поняли правильно. Я фанат C++, я хочу, чтобы C++ процветал, сообщество C++ программистов росло, а количество C++ проектов постоянно увеличивалось. Как мне кажется, для этого необходимо, чтобы программировать на C++ было легко (просто) и удобно.
Легкость (простота) программирования проистекает из двух составляющих: наличие продвинутой, объемной стандартной библиотеки, и удобством самого языка. По поводу стандартной библиотеки C++ находится по сравнению с Java, C#, Python, Perl или Ruby в глубоком заднем проходе (мягко говоря). Поэтому эту тему я затрагивать не буду.
Обратимся к самому языку. Понятно, что C++ не самый простой язык, не только в изучении, но и, к сожалению, в использовании. В нем уже сейчас слишком много подводных камней. Но нам этого мало. Складывается впечатление, что мы хотим извести C++ вообще. Превратить его в элитарный инструмент, доступный лишь немногим избранным.
Говорю об этом так уверено, потому что я сейчас смотрю на C++ с двух совершенно разных точек зрения. Во-первых, уже второй год я веду занятия по C++ с группами студентов, из числа которых мы отбирам для себя практикантов, чтобы затем сделать из них наших сотрудников. Я вижу сейчас, как тяжело идет процесс обучения. Как легко люди ошибаются при написании таких элементарных функий, как strcmp или strcpy. Как не понимают, чем различаются вектора и указатели. И как тяжело объяснять, почему сейчас, на двадцать первом году жизни С++ люди пользуются компиляторами, позволяющими применять оператор -- к булевской переменной. Я представляю, сколько нужно дать материала, чтобы объяснить им адресную арифметику, перегрузку операторов, классы и наследования, шаблоны, исключения. Это огромный материал. И даже после этого требуется большой опыт, чтобы не допускать ошибок выхода за пределы массива или возврата из функции ссылки на автоматический объект. В результате срок допуска среднего студента-практиканта к производству production кода растягивается на долгие месяцы, если не годы. А тут мы еще и шаблонное метапрограммирование сверху. Бздынь!
Во-вторых, повезло мне познакомиться с языком Ruby. В частности с некоторыми его возможностями
. Тут уж точно срабатывает поговорка: "К хорошему быстро привыкаешь". В частности, посмотрев, как выглядит метапрограммирование на Ruby (да и на Lisp-е (обсуждения Metaprogramming et al
Понятно, что это моя личная идея фикс, но все же. Давай задумаемся, что проще -- научиться программировать на Python/Perl/Ruby или освоить метапрограммирование на C++ных шаблонах? Имхо, задачи практически одной сложности, может даже освоение Python/Ruby попроще будет. А вот что полезнее? Мне кажется, что знание еще одного динамического языка. По крайней мере, многие вещи (вспомогательные скрипты для администрирования чего-нибудь) на нем делать будет проще, чем на C++.
А в результате соединения C++ и динамического языка можно получить гораздо более существенный результат. Т.е. 1+1=3, а то и 4
Ну, например, за последний месяц мне потребовалось создать пять или шесть классов, которые были предназначены только для хранения конфигурационных параметров. Т.е. штук пять-семь атрибутов, конструктор по-умолчанию, setter-/getter-ы для каждого атрибута. Писать все это вручную -- муторно. Прятать за макросами -- не читабельно. Да и с инициализацией атрибутов в конструкторе по умолчанию не все просто. А я представил себе, как бы было интересно, если бы я в hpp-файле просто написал такой фрагмент:
#ifdef MXX_RU_INPLACE_CODEGEN
<...>
#else//inplace_codegen:md5:....class cfg_t
{
std::string m_listening_mbox;
int m_interception_priority;
unsigned int m_low_watermark;
unsigned int m_high_watermark;
unsigned int m_cprov_high_watermark;
unsigned int m_max_life_time;
unsigned int m_check_life_time_period;
public :
cfg_t();
void set_listening_mbox( const std::string & v );
const std::string & listening_mbox() const;
...
void set_check_life_time_period( unsigned int v );
unsigned int check_life_time_period() const;
};
#endif
Вот это я понимаю, вот это метапрограммирование!
На шаблонах еще попробовать это сделать нужно
А вот на Ruby, как мне представляется, реализация будет не столь сложной. И что не маловажно для меня, для ее сопровождения совсем не нужно будет быть гуру в Ruby. Поэтому подобный кодогенератор при использовании в реально проекте вполне можно будет передать "в наследство" менее опытному коллеге. В отличии от многих моих шаблонных конструкций. Хотя мне до boost-овских наворотов еще расти и расти.
В общем, уважаемые коллеги по C++ цеху, давайте не будем stupid, и будет пытаться "Keep it simple"
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
.
E>Хотелось бы поговорить о наболевшем, о шаблонных наворотах. На примере compile-time вычислений в частности.
E>Вот мне и интересно, есть ли не академические примеры использования compile-time вычислений? И если есть, то что это за примеры, и оправдали ли себя compile-time вычисления в плане сопровождаемости?
Эх, чувствовал что придется это написать.
Только начну я немного издалека (что бы была понятна моя точка зрения), а именно с тех сущностей, которые начинаются с приставки 'мета'. Например, метапрограммирование. Что это такое? Часто применяемое определение этого термина гласит, что это всего лишь программирование на метаязыке. Метаязык это язык более высокого уровня чем 'объектный' язык, понятиями которого и оперирует метаязык. Зачем оно надо? Согласно теореме Геделя, как бы не стройна и логична была некая формальная система, найдется утверждение(выраженное терминами этой ФС) об истинности которого невозможно ничего сказать. Кстати существование многих парадоксов обусловлено именно существованием таких утверждений. Чтобы можно было делать выводы об истиности таких утверждений приходится приходится вводить новый уровень формализации(или метаязык в рассматриваемом контексте). Здесь можно вспомнить Тарского (который и ввел понятие 'метаязык') с его 'белым снегом':
"Снег белый" — утверждение на объектном языке,
"Утверждение "Снег белый" истинно" — утверждение на метаязыке.
Отсюда следует заключение, что на метаязыке можно _доказывать_ утверждения, выраженные в терминах объектного языка (можно поднять еще на ступеньку выше и 'доказывать' метязык и т.д).
Это было небольшое отступление. Теперь про метапрограммирование.
Метапрограммы оперируют 'объектными программами' либо их фрагментами. Существует две (основных и местами перекрывающихся) категории метапрограмм — генераторы и анализаторы. К первым можно отнести различные DSL, генераторы компиляторов и т.п. Анализирующие метапрограммы используют информацию об объектном языке для получения некого результата. Результатом может являться, например оптимизированный вариант исходной программы, набор некой статистики и т.п.
Какие преимущества дает метапрограммирование (здесь под этим понятием я подразумеваю любой способ получения программы на объектном языке)?
В первую очередь это производительность, которую можно рассматривать с двух точек зрения:
1)Удобство и скорость написания программ.
Например boost::spirit, и тому подобные domain-oriented средства заметно упрощают процесс написания программ. Также упрощается модификация и дальнейшие сопровождение.
1)Производительность как таковая. Для достижения максимального роста производительности необходимо идентифицировать и выполнить как можно больше вычислений в течении компиляции (это утверждение спорно — разумеется нужно соблюдать какие-либо ограничения, но в данном контесте, смысл, я думаю понятен). Таким образом, процесс оптимизации распадается на две фазы – анализа и специализации. Анализ (Binding-Time Analysis) – это процесс определения вычислений, выполнение которых возможно до времени выполнения. Фаза специализации использует результаты BTA для порождения оптимизированных вариантов участков кода. Хорошим примером для С++ является возможность определения POD классов (фаза анализа) с дальнейшим применением к ним bitwise копирования (специализация).
Доказательство правильности программ. Так как программы пишут на неком формальном языке, то анализируя эту программу можно обнаружить ее свойства. Эти свойства могут быть использованы для оптимизации (см.выше), выявления ошибок и доказательства правильности. Более того, при модификации участков объектного кода необходимо гарантировать что оптимизированная программа по функциональности будет идентична исходной (особенно актуально для оптимизирующих компиляторов).
Это основные (ИМХО) плюсы, которые дает метапрограммирование. Еще можно добавить получение различных метрик, графов зависимостей и т.п.
О сложности метапрограммирования.
Чем обусловлена сложность метапрограммирования? Как не странно ответ банален – сложностью программ. Для управления сложностью программных систем программисты используют множество механизмов встроенных в язык, например систему типов, области видимости, разнообразные механизмы абстракции. При применении метапрограмм эта сложность возрастает дважды, поскольку используется фактически два языка. Хорошая система метапрограммирования имеет дело непосредственно со сложностями объектного языка(опять же boost::spirit). В противном случае необходимо явно описать специфику объектного языка(yacc/cocor, etc.), что в свою очередь еще больше увеличивает сложность метапрограммирования (когда метаязык и целевой язык не совпадают, иногда пользуются термином 'гетерогенное метапрограммирование').
Все вышесказанное является моим пониманием метапрограммирования.
О cttl.
Во-первых cttl это _экспериментальная_ бибилиотека. Писалась (и пишется) для построения сложных анализаторов кода(то что выложено — это далеко не все) и КА. Не заточена для обработки чисел. Основное назначение cttl::recursion предоставить максимально обощенный интерфейс для рекурсии. Первоначальные параметры — исходный тип, функция перехода к следующему(next), критерий остановки(stop) и тело рекурсии(body). Причем основной фичей является то что в этих функциях можно использовать данные о: текущем значении, номере итерации и обрабатываемом элементе. Функции next_list для перехода к следующему списку типа(как и plus в приведенных примерах) является _очень_ примитивной для перехода к следующему элементу. В реальности там сильно ветвящийся алгоритм. Попросили показать как считать простые числа используя cttl::recursion — показал, и это говорит о том что даже такие вещи можно выразить, хотя и выглядит как стрельба из пушки по воробьям. Пример с факториалам я привел для сравнения, поскольку это наверное самый первый пример с которого начинают глубоко изучать шаблоны.
О compile-time(CT) вычислениях.
Работа с числами в CT действительно не часто требуется(ИМХО). Мне например, вряд ли понадобится считать простые числа. Числа можно рассматривать как некие аттрибуты типов(размер, позиция), в этом случае несложные алгоритмы вполне оправданы. Про дробные числа здесь:"Floating point arithmetic in C++ templates" . Цитата оттуда: "The code to generate the convolution kernel takes 7 minutes to compile on a Xeon 2.4". Красиво, но реальное использование, IMHO сомнительное.
На мой взгляд гораздо более востребованы алгоритмы оперирующие типами(и их списками)
для последующей генерации классов/функций/учасков кода.
Хотелось бы поговорить о наболевшем, о шаблонных наворотах. На примере compile-time вычислений в частности.
Можно ли привести примеры, когда compile-time вычисления оправдывают сложность связанных с ними шаблонов. Такие академические примеры, как вычисления небольших факториалов или простых чисел (от одного до 20) меня не убеждают. Если посмотреть
на приведенное решение, то его объем и сложность таковы, что проще в программе вручную задать все простые числа из этого диапазона (подсчитанные в уме). Либо вообще сделать вспомогательный скрипт на Ruby или Python-е:
1.upto( 10000 ) {
|x|
prime = true
2.upto( x - 1 ) {
|y|
if 0 == ( x % y )
prime = false
break
end
}
puts "#{x}" if prime
}
который за приемлимое время расчитает гораздо больше простых чисел, чем самый продвинутый C++ компилятор в compile-time (с учетом органичений на глубину инстанцирования шаблонов). То же самое и с факториалами.
Вот здесь есть уже более реальные примеры. Скажем подсчет количества установленных в байте битов (но там и шаблоны-то на порядок попроще) или вычисление синусов для константных величин. Особенно меня впечатляет пример с синусом. Но и здесь, имхо, не так все однозначно. Например, такие вычисления возможны только для констант, а как мне представляется, во-первых, подобных констант в вычислениях не так уж и много, в основном переменные используются. Во-вторых, если где-то в коде есть фрагмент:
float f = Sine<32,5>::sin();
то этот фрагмент содержит две за-hardcod-ленные константы 32 и 5, и на самом деле означает sin(2*pi*5/32), да еще и вычисленный с органиченной в реализации Sine::sin точностью.
А что, если у меня выражение более сложное:
float r = d * Sine< 32, 5 >::sin() + c * Cos< 16, 5 >::cos() + 1 / Sine< 3, 5 >::sin();
И если так, то не проще ли мне будет вообще в объявлении констант sin_32, cos_16, sin_3 поместить заранее вычисленные на калькуляторе значения с нужной мне точностью?
const float sin_32 = 0.8314696123f;
const float cos_16 = ...;
const float sin_3 = ...;
r = d * sine_32 + c * cos_16 + 1 / sin_3;
Конечно, может показаться, что в варианте с Sine<...>::sin лучше сопровождаемость, т.к. легко можно забыть изменить какую-нибудь из констант sin_32, cos_16, ..., sin_3. Но ведь можно сделать и так:
#include"consts.h"
r = d * sine_32 + c * cos_16 + 1 / sin_3;
Вот мне и интересно, есть ли не академические примеры использования compile-time вычислений? И если есть, то что это за примеры, и оправдали ли себя compile-time вычисления в плане сопровождаемости?
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[7]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, eao197, Вы писали:
E>А можно подробнее? Для каких hash, random алгоритмов нужно, чтобы размер буфера был простым числом?
Немогу привести полноценных примеров (они большие и принадлежат не мне а фирмам) поэтому ограничусь "тупым" генератором псевдослучайных чисел и "тупым" хэшем.
template<unsigned int A,unsigned int B,unsigned int C>
class random{
unsigned int state;
public:
unsigned int operator()(){
return state=(A*state+B)%C;
}
};
Если числа в парах [a,b] [b,c] [a,c] взаимно просты то случайные характеристики генератора сносны и выдаваемые значения более-менее равномерно распределены в одномерном пространстве и период генератора равен C. Если нет то мы можем сильно "проколоться" как с периодом так и с корреляцией значений.
А проверить это можно так:
//Расширенный алгоритм Евклида для поиска наибольшего общего делителя result
//и коэффициентов X,Y таких что result = A*X+B*Y
//Глубина рекурсии ("фибоначчи" логарифм max(a,b)) и число инстанцированных типов не доставляют проблем компиляторам.template<unsigned int a,unsigned int b>
struct euclid_ex{
typedef euclid_ex<b,a%b> d;
enum{result=d::result, x=d::y, div=a/b, y=d::x-div*d::y };
};
template<unsigned int a>
struct euclid_ex<a,0u>{enum{result=a,x=1u,y=0u};};
#define STATIC_ASSERT(C0ND1T10N) typedef int blablabla[(C0ND1T10N)?1:-1]
template<unsigned int A,unsigned int B,unsigned int C>
class random{
unsigned int state;
STATIC_ASSERT(euclid_ex<A,B>::result==1);
STATIC_ASSERT(euclid_ex<A,C>::result==1);
STATIC_ASSERT(euclid_ex<B,C>::result==1);
public:
unsigned int operator()(){
return state=(A*state+B)%C;
}
};
Теперь о хэше.
Часто функция хэширования выдаёт целое значение вне диапазона хэш-буфера и нужно брать это эначение по модулю размера буфера. Если размер буфера есть степень двойки (любим мы это делить не надо)
STATIC_ASSERT((size&(size-1))==0);
то никак не используются старшие биты значения и может увеличиваться вероятность коллизий и осталять при этом неиспользуемые элементы в буфере. Да и разрешение коллизий тормозит работу хэша. Взятие по модулю простого числа сильно тасует биты индекса и приводит к равномерному заполнению буфера хэша.
// Проверка числа на простоту методом близким к решету Эратосфена.
// Практически не может превысить лимиты компилятора на число инстанцированных типов.
// для простых N инстанцируется около sqrt(N)/6 типов для составных гораздо меньше.
// для чётных N только два, для нечётных N кратных трём три.
// Мне в MSVC 7.1 удалось проинстанцировать все is_prime от нуля до 1900 одновременно
// и не удалось найти N превышающих лимиты компилятора.template<unsigned int N>
class is_prime{
template<unsigned int K>
struct ask{
enum{
tmp=(N<K*K),//Временных переменных никто не отменял :-)
answer=tmp|ask<(K+6u)*(!tmp&&(N%K)&&(N%(K+2u))&&(N%(K+4u)))>::answer
};
};
template<>struct ask<0u>{enum{answer=0u};};//Признак окончания разбора.public:
enum{result=ask<3u*(N&1u)>::answer};
};
template<>class is_prime<1u>{public:enum{result=0u};};
template<>class is_prime<2u>{public:enum{result=1u};};
//Это только пример. Не ругайтесь.template<class KEY,class DATA,unsigned int size,unsigned int(*hash_fun)(KEY const&)>
class hash{
STATIC_ASSERT(is_prime<size>::result);
std::list<std::pair<KEY,DATA> > buffer[size];
public:
...
void insert(KEY const&k,DATA const&d){
//Кто не любит делить может посмотреть ассемблерный код
//взятия по известному компилятору модулю при полной оптимизации.
//только не ищите команду div
buffer[((*hash_fun)(k))%size].insert(std::make_pair(k,d));
}
...
};
Re[5]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, eao197, Вы писали:
E>Тем не менее, все перечисленные в его презентации недостатки шаблонов остаются. И задалбывают по тихоньку.
Не скажу, что я от них тоже в полном восторге, но и "пятиминутку ненависти" устраивать тоже вроде бы рано.
В наших проектах (как на работе, так и "частных") сложилась практика широкого применения "сторонних" шаблонов. То есть, они припролзают в приложение из библиотек (STL, WTL, boost). Но в самом приложении шаблоны за малым исключением не определяются. Это малое исключение — различные мелкие предикаты и функторы определяемые зачастую на уровне одного файла.
И это, как мне кажется, очень правильно. Шаблоны — это метод обобщенного программирования. Приложение же решает вполне конкретную задачу. Вот и получается, что во время разработки приложения не "обобщать" надо, а выдавать на-гора функциональность. Зачастую очень специфичную и какому-либо обобщению не поддающуюся.
Впрочем, когда приложение сделано, я (по личной личной инициативе) некоторые "интересные" куски от него откусываю, и обобщаю в виде шаблонов с тем, чтобы применять это дело в других проектах... Например, один из таких кусков — "кэширующий итератор". Его главное назначение — преобразование InputIterator'а в RandomAccessIterator. Или sprintf(), который возвращает string и тп.
__________
16.There is no cause so right that one cannot find a fool following it.
Re[4]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, Юрий Жмеренецкий, Вы писали:
E>>Хочу, чтобы меня поняли правильно. Я фанат C++, я хочу, чтобы C++ процветал, сообщество C++ программистов росло, а количество C++ проектов постоянно увеличивалось. Как мне кажется, для этого необходимо, чтобы программировать на C++ было легко (просто) и удобно.
ЮЖ>Имхо, легко и просто не получится, поскольку так устроен язык: практически полный контроль и огромное количество возможностей. Если динамический массив с контролем выхода за границы будет являтся частью языка, то мы потеряем возможность самостоятельного управления памятью, также возникнут потери производитльности в критических точках. Нужен такой массив с С++? если нужен, то его легко реализовать, причем с самым невероятным набором возможностей.
Знаешь почему Java и .Net в последнее время так популярны (так же, как и Ruby, и Python, и Perl)? Потому, что подход C++ это "сделай сам то, что тебе нужно". А подход Java/.Net -- "все уже сделано". В смысле, что если ты решаешь типовую задачу, то JDK или .Net Framework уже содержит готовые инструменты. Поэтому типовые (мейнстримовые) задачи вне C++ решаются проще, чем на C++.
Можно, конечно, говорить, что решающим фактором является наличие большого количества готовых библиотек. И рассуждать о деньгах, которые были вложенны крупнейшими корпорациями в создание стандартных библиотек для Java/.Net. Да только меня больше интересует другой вопрос -- почему для C++ этого нет? Никто не вкладывал таких средств? Не вкладывали. Но ведь и в Ruby/Python/Perl не вкладывали.
Причин множество. Одна и из них, весьма важная, -- это сложность самого языка. Например, отсутствие сборки мусора. Была бы сборка мусора, написание библиотек для C++ серьезно бы упростилось. Тот же Ruby или Python это доказывают. ИМХО.
Ну так вот, в сложности C++ и его сила и его проблемы. Но давайте не будем создавать новую сложность на ровном месте. Вот сравни два решения: Re[13]: Простота, эффективность и usabillity
. Стоила ли здесь овчинка выделки (имеется в виду привлечение простых чисел)? Лично я сомневаюсь.
Так вот, имхо, еще одна проблема C++ в том, что он как-то провоцирует программистов на подобные изобретения. В результате сложные классы и вычисления появляются там, где это вообще не нужно было. Вот как раз эта тенденция, а не сам язык C++, мне и не нравится.
ЮЖ>Не знаю как тебе, а мне это все(метапрограммирование, шаблоны, etc.) чертовски _интересно_, и я бы на месте студентов всеми руками держался за то место где учат этому 'Бздынь'. Если нет у студента стремления к саморазвитию, желания стать эдаким творцом в миниатюре, понимать как все это работает в конце концов, то никаким 'вдалбливанием', не поможешь(Имхо, естественно).
Мне кажется, что в С++ остаются как раз люди, которые хотят быть творцами в миниатюре. Я и сам такой. Да только пора понять, что в 90% случаев программирование заключается не в изобретении чего-то нового, а в решении поставленной перед тобой задачи. Быстро, дешево и качественно. Эффективность даже на первом месте не стоит (об этом сейчас идут серьезные баталии в Об эффективности программ
). А уж новизна или элегантность решения вообще никого не интересует. В таких условиях не творцов готовить нужно (да это и невозможно, человек либо творец, либо нет), а нормальных вменяемых и обучаемых специалистов-разработчиков. И в современных условиях им есть чего изучать кроме метапрограммирования на шаблонах в C++. Тот же самый SQL и РСУБД (на серьезном уровне, а не просто SELECT/INSERT/UPDATE), или WebServices, или XML с XSD и XSLT.
ЮЖ> Кстати, насколько выгодно 'выращивать' программистов для себя ?
Анекдот вспоминается:
-- Молодой человек, извините, не подскажите, в Лондоне кроме дождя другая погода бывает?
-- Не могу вам точно сказать, мне всего 35 лет.
Не могу с уверенностью сказать. Мне кажется, что да. Но здесь время покажет. Обучение -- это очень длительный процесс.
E>>На этом лирическое вступление заканчиваю и перехожу к выводам. А вывод простой: я не хочу писать такой код, который привел ты и Dmi_3. Я не хочу читать такой код. Я хочу держаться подальше от проектов, в которых есть такой код. E>>Потому, что я считаю его неоправдано сложным. Как в написании, так и в отладке, и в сопровождении.
ЮЖ>А как ты относишся к boost и stl ?
К stl нормально. Но в свое время нахлебался с различиями реализации stl в разных компиляторах. Настолько, что пока boost не станет входить в дистрибутив нужных компиляторов (как stl), у меня нет желания с ним связываться. Мне ведь иногда и на экзотических платформах работать приходится. Да и по своей работе мне чаще приходится заниматься файлами и сокетами, чем списками типов. А этого как раз в boost-е то и нет.
ЮЖ>Такой подход сложен только в реализации, а использование... Любой рефлекшн/перехват функций и т.п. ЮЖ>прикрутить не проблема. Я не агитирую за применение такого подхода, всего лишь демонстрирую что ЮЖ>можно сделать не выходя за рамки языка. И это, ИМХО, далеко не идеал...
Посмотри на Ruby. Там вообще на это заморачиваться не приходится
ЮЖ>Вообще, подводя итоги — мне кажется, что сложность в одном месте рождает простоту в другом и этим себя оправдывает.
Здравствуйте, Pavel Chikulaev, Вы писали:
E>>Это все из другой оперы. PC>Эт еще почему? Идея одна и та же абсолютно.
А ты мне расскажи, что общего между трехэтажным кодом вычисления простого числа или синуса в compile-time и использованием STATIC_ASSERT? Что я буду в STATIC_ASSERT проверять, что вычисленный компилятором в compile-time синус равен извесному мне заранее значению?
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Вмешаюсь в Ваш разговор. Для начала, как водится, эпиграф:
"Красиво излагает, сволочь! Учитесь, Киса!" (с) Ильф и Петров
D_>P.S. (offtopic) D_>После всего выше приведенного, совет «…вообще забей на хэширование, если ничего в нем не понимаешь.» я скорее буду относить к Вам а не к себе. Хотя мне трудно представить разработчика компиляторов пусть даже скриптовых языков не использующего hash и слабо разбирающегося в рекурсии. Как Вы ассоциируете атрибуты с именем идентификатора без hash? Ищете в неупорядоченном списке? Как разбираете БНФ или просто выражения со скобками без рекурсии? Ручками стеки заводите?
Эээ... Разве Евгений где-то утверждал, что он разрабатывает компиляторы?
D_> И уж совсем невозможно представить 7x24 приложение отказоустойчивость которого базируется на: E_>> Указал пользователь четное значение -- сам дурак D_>Ваша «вежливость» поражает. Мы с Вами на брудершафт не пили. Я старше Вас, не Ваш студент и не надо мне тыкать и советовать забить на хеширование. Не надо называть и младших коллег stupid. То, что сделал Юрий Жмеренецкий вызывает если не восхищение то глубокое уважение. А Вы (см. «Собачье сердце») позволяете себе давать советы Космического масштаба и Космической же глупости. Вот это уже можете считать моей оценкой. А время необходимое для прочтения главы Кнута того же порядка что и время потраченное на оскорбления коллег и эксперименты по хешированию log-а с сомнительной пользой.
Не нападайте на человека без причины. Быть может, конечно, я чего-то не заметил, но оскорблений (тем более адресных) в этой ветке не было.
D_>Впрочем я сам виноват не надо было связываться с таким человеком: D_>Цитата из Вашей домашней странички: D_> D_>... Иностранными языками не владею, на русском пишу с ошибками. Сам себя могу охарактеризовать как системного программиста-камикадзе и патологического изобретателя велосипедов. Системного -- потому, что систематически умудряюсь встревать в безнадежные проекты (фактически все проекты, в которых я участвовал, можно назвать безнадежными). А изобретатель велосипедов -- потому, что меня хлебом не корми, дай что-нибудь свое придумать. Но это уже на генетическом уровне и не лечится. D_> D_>Конец цитаты. D_>Мне добавить нечего!
Зря Вы так. Евгений не новичок на RSDN и, при всем своем консерватизме, часто высказывается очень толково. Попытайтесь понять человека, соотнесите его условия работы со своими, и Вам во многом станет понятна его точка зрения. Бывает, что человека "прорывает". Похоже, что у Евгения сейчас именно "наболело", вот он и высказывается в том единственном месте, где он встречает какую-то поддержку. Я бы в его ситуации и похуже себя вел — вспыльчивый очень.
А цитату с его homepage вы зря в таком контексте привели — надо все-таки понимать, что человек относится к себе с известной долей самоиронии.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[3]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, eao197, Вы писали: E>Здравствуйте, _Winnie, Вы писали: _W>>А вот операциями над списками типов — пожалуйста. E>Пожалуйста. Если не сложно, конечно.
Это кусочек кода из Winnie Format Library.
Нужно для выражения вроде
Оно ничего не делает, кроме запоминания списка указателей на временные переменные — параметры operator %, которые __ПОТОМ__ надо распечатать в поток(буфер). Поэтому форматировать на ходу нельзя (так как правило no mallocs).
namespace text_print
{
//форвард декларацияtemplate <class Char>
struct format_t;
namespace detail
{
//собственно, элемент списка. Prev - тип предыдыдущего элемента.template <class T, class Prev, class Char>
struct printf_link_t
{
typedef Prev prev_t;
typedef Char char_t;
typedef T type;
Prev *m_prev;
const T *m_param;
printf_link_t(Prev *in_prev, const T *in_param)
:m_prev(in_prev)
,m_param(in_param)
{
}
//создаём следующий элемент списка.template <class Next>
detail::printf_link_t<Next, printf_link_t, Char>
operator %(const Next &x)
{
return detail::printf_link_t<Next, printf_link_t, Char>(this, &x);
}
};
struct printf_param_info_t
{
polymorphic_print_t m_polymorphic_print; //указатель на функцию, которая распечатывает void * аргумент.const void *m_param;
};
//мяу-функция на списком. вычисляет длину и делает функцию, которая заполняет массив.template <class PrintfLink>
struct make_array_from_list_t
{
enum { len = 1 + make_array_from_list_t<typename PrintfLink::prev_t>::len };
static format_t<typename PrintfLink::char_t> *
fill(printf_param_info_t printf_param_info[], PrintfLink *printf_link)
{
--printf_param_info;
printf_param_info->m_polymorphic_print = &polymorphic_print_gen<typename PrintfLink::type>;
printf_param_info->m_param = printf_link->m_param;
return make_array_from_list_t<typename PrintfLink::prev_t>::fill(
printf_param_info, printf_link->m_prev);
}
};
} //detailnamespace detail
{
//специализация для останова.template <class Char>
struct make_array_from_list_t<format_t<Char> >
{
enum { len = 0 };
static format_t<Char> *fill(printf_param_info_t *, format_t<Char> *format)
{
return format;
}
};
}
Еще пример — передача параметра в функцию с неизвестной на этапе компиляции сигнатуры.
Например: pObject->Call("SomeFunction", 1, 2, 3) где динамически определяется, если у объекта неизвестного типа "SomeFunction", а если есть, то можно ли преобразовать параметры из (int, int, int) в (bool, float, long)
Надо проверить в run-time, возможно ли преобразование из типа фактического параметра в тип формального параметра.
Для этого нужна квадратная табличка пребразователей из типа в тип. Её, конечно, лучше сгенерить в compile-time по заданному списку типов. Можно, конечно и в скрипте, но он никогда в жизни не поймёт, что signed и int — это одно и тоже.
Правильно работающая программа — просто частный случай Undefined Behavior
>>Хотя может быть этот пример и не показателен, может hash_pjw из ACE не самая оптимальная hash-функция для моего log-файла (для 8209 строк дает 6802 уникальных значения, а ведь в каждой строке есть уникальный timestamp, т.к. повторяющихся строк в нем практически нет)
Вероятность хотя бы одной коллизии для хорошей 32 битной хеш-функции на уникальных ключах в Вашем случае (8209 записей) составляет около 0.007. Вероятность двух исчезающе мала. 1407 коллизий это перебор. Но именно плохая хэш-функция и привела к таким результатам Вашего эксперимента. Если бы она была хорошей и биты хэш значения независимы, то никакой существенной разницы Вы бы не обнаружили. (я не говорю о Ваших смешных 0.21% которые видимо объясняются просто разными размерами буферов и его величеством Случаем)
Раз уж Вы решили экспериментировать вместо изучения «академической» литературы то позвольте дать несколько советов.
1. Измените оценку результатов с подсчёта количества нулей на среднеквадратическое отклонение разбросов счётчиков. (Чем меньше, тем лучше)
Ну или сумму модулей отклонений от среднего.
2. Попробуйте изменить хэш-функцию на h=A0*ACE::hash_pjw()+A1; где A0 это 3, 23, а лучше 29 и A1 любая (лучше небольшая) константа и попробовать Ваш любимый capacity=2001. Ведь Вы не знаете, может там внутри ACE::hash_pjw другой практик так и сделает потом. (для capacity= 2501 он выберет A0 41 или 61. кстати всего два делителя число почти простое)
3. Попробуйте изменить хэш-функцию на менее плохую (я надеюсь) h=0.618034*ACE::hash_pjw();
4. Поостерегитесь брать размеры hash-буферов как составное число с большИм количеством делителей (особенно разных и\или маленьких делителей например 30030=2*3*5*7*11*13)
5. Почитайте всё-таки что-нибудь (хотя бы Кнута) об универсальном хэшированиии.
6. ОЧЕНЬ ответственно относитесь к выбору хэш-функций, исследуя типичные данные для Вашего случая. Хеширование идентификаторов и путей к файлам – две большие разницы.
7. Не уподобляйтесь моему знакомому преподавателю, учившему студентов, что hash реализован в STL в виде std::map. Или другому знакомому с фразой «Но ведь работает же». (извините — наболело).
8. Если какое-то требование к использованию кода можно выразить явно в программе – выразите. Это будет дополнительной гарантией. Разве все внимательно читают документацию?
Когда я реализовывал hash то там было что-то такое:
Того, кому не понятно, что это массив простых чисел ближайших к последовательным числам Фибоначчи можно безболезненно увольнять. Этот код был в cpp файле и компилировался лишь один раз. В отладчике я его ни разу не видел.
А эту последовательность далеко не каждый сумеет понять. Можете дать своим студентам в качестве упражнения на сообразительность.
59,89,149,233,379,613,991,1597,2591,4201,6779,10949,17713,28657,46381,75029,121403,196429,317827,514229,832063,1346273,2178313,3524603,5702897
Re[2]: Compile-time вычисления: а оно вообще надо?
. E>>Хотелось бы поговорить о наболевшем, о шаблонных наворотах. На примере compile-time вычислений в частности. E>>Можно ли привести примеры, когда compile-time вычисления оправдывают сложность связанных с ними шаблонов. C>Ну, например, у меня в моей велосипедной библиотеке форматирования CT-вычисления используются для оценки размера результирующего буффера — используется самодельное вычисление логарифма. Конечно, можно было бы тупо зарезервировать буффер в 100 символов для обычных чисел, но это некрасиво.
А как же принцип KISS?
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[5]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, eao197, Вы писали:
E>Только эти недостатки легко превратить в достоинства E>А программировать, кроме C++, еще на Python, Ruby или, скажем, Smalltalk -- это не только интересно, но и полезно. (См., например, Re[2]: Compile-time вычисления: а оно вообще надо?
Кому как.
Вообще это или больше платить каждому программисту, или не больше, но тоогда двум
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Compile-time вычисления: а оно вообще надо?
Erop wrote:
> А вообще вот надо мне завести ещё одну размерность. Там, скажем, > очарованность. Вот что мне делать дальше? > Ну ладно, положим очарованность нужна маньякам, они твой код разберут, > перепишут и добавят. Но вот что делать челу, которому как раз люмены с > канделами по фигу, а не пофигу СГСэ и СГСм? Или там, скажем, надо > часто переводить мили в час в футы в секунду. Что ему делать со всей > этой мощью CT-вычислений?
Мили имеют размерность расстояния, furlongs per fornight —
расстояние/время (т.е. скорость). Пишешь трансляторы — и вперед.
Здравствуйте, eao197, Вы писали:
E>Вот мне и интересно, есть ли не академические примеры использования compile-time вычислений?
...Был тут как-то аффтор который, как мне кажется, на это капитально подсел.
Счас, увы, он сюда уже не пишет.
E>И если есть, то что это за примеры, Двоичные константы на C++ — и без макросов
compile-time в чистом виде. конвертация десятичных и восьмеричных чисел в двоичную систему счисления.
Кстати, некто нынче предлагает что-то подобное ввести в буст.
А вот эта штука, как мне кажется, посерьезнее.
Основная ее идея — генерация распознавателя регулярых выражений в compile-time. Короче, что-то вроде flex-а, но в терминах C++.
Имхо — идея — просто блестящая. Expressive и рядом не стоял. Но, реализация, как всегда, оставляет желать.
Автор обещал распознавание к конечным автоматам, но не свел...
__________
16.There is no cause so right that one cannot find a fool following it.
E>Вот мне и интересно, есть ли не академические примеры использования compile-time вычислений? И если есть, то что это за примеры, и оправдали ли себя compile-time вычисления в плане сопровождаемости?
Я сейчас работаю в проекте, где есть очень много всяких данных и структур данных, вычисляемых на этапе компиляции.
При этом практически все они получаются не как, CT-вычисления, а как cpp файлы, полученные в результате специально собранных для этого утилит.
Утилиты в основном на C++
При этом иногда это числа, иногда какие-то нетривильные таблицы, иногда просто код.
CT-вычисления используются в виде
const my_const = my_const1 + my_const2;
или не сильно сложнее. Скажем lengthof.
Ещё используется C_ASSERT
Чем не угодили CT-вычисления?
Ну тем что их
1) Трудно отлаживать. Конечно, если вы хотите посчитать что-то тривиальное, то не вопрос, алгоритм известен до мелочей, но вот если вы хотите посчитать что-то такое, сложное. Скажем решить численно дифур и записать в таблицу траекторию, то уже CT-вычислениея не особо подходят.
2) Трудно проверять, что всё "сраслось". Для результата утилиты можно написать сколь угодно умный проверяльщик, кроме того его можно посмотреть "глазами", в случае CT-вычислений это уже совсем сложно
3) Их трудно поддерживать, комментировать и вообще писать читабельно. C++ в обычном помнимании намного выразительнее всё-таки
4) Из CT-вычислений трудно позвать какие-то сторонние функции (например Win32 API), проверить содержимое каких-то файлов и т. п.
В принципе недостатком системы с утилитами является то, что трудно писать проекты. Поэтому написали некий тул, который умеет удобно это всё дело встраивать в процесс компиляции. Технически это выглядит, как написанный на шеле интерпретатор билдовых файлов особого вида. В целом всё не так уж сложно, и главное, что у билдовых файлов довольно простой синтаксис. Ну и поэтому поддерживать это всё дело намного проще, чем код CT-вычислений.
В целом билд выглядит так:
Этот самый интерпритатор смотрит что там ещё не построенно или нуждается в перестройке или ещё чего и строит утилиты, потом запускает их, потом строит сам проект, или другие утилиты и т. д.
Таким образом вместо того, чтобы заставлять компилятор строить "ненужные" в окончательном коде инстанциации шаблонов, мы заставляем строить "ненужные" утилиты и включаем в окончательный код не их текст, а результат их работы.
Учитывая, что сами утилиты меняются очень редко, а часто меняются как раз параметры их вызова, то при инкриментальном билде утилиты не пересобираются (в отличии от шаблонных монстров), а просто работают, если что-то поменялось.
Вот такой вот реальный опыт есть у меня.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Compile-time вычисления: а оно вообще надо?
Ну, не смотря на узкую область применения, классная машинка. Мало того, прикаольно реализовано, ну и вообще хорошо довольно всё сделано. В конце концов идея приписывать размерность через тип переменной и поиск преобразования (Если оно есть) или детектирование того факта, что преобразования нет вещь в принципе верная
Но вот зачем коэффициент в преобразовании вычислять CT я не понимаю. В конце концов его же можно кэшировать. Что за выгоду ловим-то?: )
Ну и CT-вычисления, как мне кажется, её нифига не красят эту хорошую задумку.
Там всё-таки не такая уж и красивая реализация. Одни комментарии вот в этом месте:
А вообще вот надо мне завести ещё одну размерность. Там, скажем, очарованность. Вот что мне делать дальше?
Ну ладно, положим очарованность нужна маньякам, они твой код разберут, перепишут и добавят. Но вот что делать челу, которому как раз люмены с канделами по фигу, а не пофигу СГСэ и СГСм? Или там, скажем, надо часто переводить мили в час в футы в секунду. Что ему делать со всей этой мощью CT-вычислений?
Таки лучше бы всю мощь шаблонов направить на расширяемость и редактируемость, а не на CT. Ну а вычислять коэффициенты и сдвиги можно и RT всё-таки кажедый коэффициент нужно вычислять один раз, и не так уж их и много вообще.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[14]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, Alxndr, Вы писали:
E>>А в чём проблема-то? A>Проблемы особой нет. Пытаюсь теперь понять, нафига нужна система СИ с ее 8 базовыми вличинами (молль забыл)
Для инженерных расчётов.
В принципе чем больше ты заведшь независимых размерностей, тем лучше будут проверяться твои результаты при помощи проверки размерности (ну типа строго типизированная физика), а чем, наоборот меньше оставишь, тем проще будут твои формулы, и тем глубже ты проникнишь в суть вопроса (типа совсем не типизированная физика должна быть полностью безразмерной
Итого
СИ -- для инженерных применений
СГС -- для теоршизических штудий
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Ну что же. Отвлечёмся на хэш.
D_> … именно плохая хэш-функция и привела к таким результатам Вашего эксперимента. E_> Какая была, такую и использовал. Не всегда есть время изучать Кнута и выбирать оптимальную хэш-функцию, приходится брать то, что есть.
Задержитесь на этом факте. Вернёмся к нему позже.
E_> Кроме-то на этих данных лога выпадает такое распределение. Со временем характер данных в логе может поменяться.
Поэтому я и посоветовал прочесть про универсальное хеширование.
D_> Измените оценку результатов с подсчёта количества нулей на среднеквадратическое отклонение разбросов счётчиков. (Чем меньше, тем лучше) D_>Ну или сумму модулей отклонений от среднего. E_> Если руки дойдут. Но даже эта оценка показывает, что только простого числа в качестве размерности для получения нормального распределения ключей не достаточно.
Вы правы. Если хэш-функция выдаёт мало разных значений, то ничто не поможет. А о том, что же показывает именно эта оценка см. ниже.
Далее. (//комментарии мои) E_> Вот: A0 == 29, A1 == 5
размер буфера : число незадействованных элементов >> 2000: 1875 // ужасно плохо все 8209 записи попали в 125 мест из 2000 >> 2001: 1863 // ужасно плохо все 8209 записи попали в 137 мест из 2001 >> 2003: 737 // плохо для 8209 записей должно быть 30-40 >> 2005: 745 // плохо для 8209 записей должно быть 30-40 >> 2007: 724 // плохо для 8209 записей должно быть 30-40 >> 2009: 759 // плохо для 8209 записей должно быть 30-40
Эти данные убедительно показывают, что предложенная Вами проверка на нечётность размера хэш-буфера почти ничего не даёт. Да ещё и реализована с ошибкой.
Должно быть не STATIC_ASSERT( ( size & 2 ) == 0 );
а STATIC_ASSERT( ( size & 1 ) != 0 );
или STATIC_ASSERT( ( size % 2 ) != 0 );
D_> Попробуйте изменить хэш-функцию на менее плохую (я надеюсь) D_> 0.618034*ACE::hash_pjw();
Обратите внимание A0=0.618034 это «академическое» золотое сечение. И оно слегка исправляет ситуацию, а вот A0=29 вызвало катастрофу с любым capacity кратным 29. Заметьте я почти ничего не знал ни о устройстве ACE::hash_pjw() ни о содержимом Вашего loga когда давал эти советы. Если честно, то надеялся увидеть значения не 700-800 а близкие к 30-40. О причинах такого расхождения будет сказано ниже. >> 2000: 737 >> 2001: 773 >> 2003: 746 >> 2005: 760 >> 2007: 729
Как и предполагалось, с увеличением размера буфера увеличилось и число нулей. Плюс случайные отклонения, обусловленные характером входных данных и разложением размера буфера на простые множители. Но отношение размера буфера к числу нулей осталось прежним «академическим» 2.7182818284590452353602874713527 Пусть появление именно этого числа Вам объяснит кто-то другой. Например, (stupid по Вашему мнению) Юрий Жмеренецкий. Я не математик, но, по моему мнению, это связано с тем, что число введённых ключей равно размеру хэш-буфера а вовсе не 8209 как Вы говорили. Если это так (а это так) то хэш-функция здесь почти ни причём просто Вы таким экстравагантным методом Монте-Карло вычисляли число e. >> 2500: 959 //2500/959=2,6068821689259645464025026068822 >> 2501: 957 //2501/957=2,6133751306165099268547544409613 >> 2502: 942 //2502/942=2,6560509554140127388535031847134 >> 2503: 950 //2503/950=2,6347368421052631578947368421053 >> 2504: 962 //2504/962=2,6029106029106029106029106029106
Повторяю. D_> Измените оценку результатов с подсчёта количества нулей на среднеквадратическое отклонение разбросов счётчиков. (Чем меньше, тем лучше) D_>Ну или сумму модулей отклонений от среднего.
В свете выше приведённого вызывает сомнение Ваше утверждение о том что E_> ... эта оценка показывает, что ...
Эта оценка показывает лишь то, что е=2.7182818284590452353602874713527
О том, что такое число E и как оно определяется тоже можно прочитать в соответствующей литературе.
E_> Не вижу никаких преимуществ от выбора простых чисел для ограничения размерности.
То есть лично Вы всегда можете найти великолепную хэш-функцию?
Поздравляю! Обычно мне и моим коллегам это не удаётся. Но постойте… Как же это соотнести с ранее высказанным Вами: E_> Какая была, такую и использовал. Не всегда есть время изучать Кнута и выбирать оптимальную хэш-функцию, приходится брать то, что есть. E_> Кроме-то на этих данных лога выпадает такое распределение. Со временем характер данных в логе может поменяться.
Неувязочка получается.
E_> Главное -- это качество хэш функции.
Так я же говорил: D_> ОЧЕНЬ ответственно относитесь к выбору хэш-функций, исследуя типичные данные для Вашего случая. Хеширование идентификаторов и путей к файлам – две большие разницы.
D_> Если какое-то требование к использованию кода можно выразить явно в программе – выразите. Это будет дополнительной гарантией. Разве все внимательно читают документацию? E_> Что выразить? Что пользователь твоего кода должен искать сам простые числа?
Если задача этого требует то да (cм. RSA-криптосистема с открытыми ключами).
Но Вы опять не поняли. Я для того и завёл массив capacity, что-бы пользователи могли поменьше заботиться и об этом и о чрезмерном использовании памяти и о идеальной функции хеширования. Ведь у них есть свои проблемы и негоже заставлять изучать всех тонкости организации хэшей. А требованием к коду в данном случае являются размеры буферов возрастающие примерно в «золотой» пропорции(в частности для экономии памяти) и являющиеся простыми числами(для снижения требований к качеству хэш-функции). Если бы я просто задал их числами то во время сопровождения программы мой коллега из добрых побуждений не поняв(как Вы) почему они именно такие изменил бы их например на степени двойки. И при изменении структуры и\или вероятностей распределения ключей его алгоритм превратился бы из O(1) в O(N) а его realtime 24x7 приложение «упало»\«зависло» бы не успев обработать socket. А если вы про пример «тупого» хэша говорите, то прочтите комментарий к нему.
// Не ругайтесь. Это только пример.
Я говорил, что код принадлежит фирме, и я не могу его публиковать. И так процента два уже рассказал.
D_>Того, кому не понятно, что это массив простых чисел ближайших к последовательным числам Фибоначчи можно безболезненно увольнять. E_> Значит меня бы уволили.
Наверно да. Правда в реальности там ещё русский комментарий стоял, на случай если кто плохо знает английский. Но даже комментарий не поможет, если человек не знает таких «академических» понятий как «инкапсуляция» и «абстрагирование», если ему не достаточно интерфейса
и он плохо разбираясь в рекурсии и функциональном программировании лезет в другой файл пытаясь понять «сложную» реализацию.
12 строк кода принадлежащих фирме вырезаны. См. аналоги приведённые выше. И учитесь абстрагироваться.
// is_prime<N>::result - Проверка числа на простоту
...skip...
// Ближайшее к N простое число не меньшее N.template<unsigned int N,bool ready=is_prime<N>::result>
struct near_prime{
enum{result=near_prime<N+1u>::result};
};
template<unsigned int N>
struct near_prime<N,true>{
enum{result=N};
};
// fibonachchi<N,A,B>::result - Вычисление чисел Фибоначчи
// Вычисляется N-ный член ряда F(N)=F(N-1)+F(N-2) где F(0)=А F(1)=Btemplate<unsigned int n,unsigned int a=0u,unsigned int b=1u>
struct fibonachchi{
enum{result=fibonachchi<n-1u,b,a+b>::result};
};
template<unsigned int a,unsigned int b>
struct fibonachchi<0u,a,b>{
enum{result=a};
};
E_> Кроме того, увидеть что-то в последовательности чисел и разрабатывать систему работающую в режиме 24x7 или транслятор скриптового языка -- это разные задачи, тебе не кажется? Помягче нужно быть с оценками.
Вы правы. Это совершенно разные задачи. Но я пока не давал Вам никаких оценок, только советы. Оценки относились лишь к коду или утверждениям.
D_> 59,89,149,233,379,613,991,1597,2591,4201,6779,10949,17713,28657,46381,75029,121403,196429,317827,514229,832063,1346273,2178313,3524603,5702897 E_> мне бы самом понять, что это такое.
Это размеры хэш-буферов которые автоматически выбираются при создании и\или рехешировании. Именно эти числа находятся в массиве capacity и получаются из выражений near_prime<fibonachchi<N>::result>::result
E_>А от своих студентов я больше требую, чтобы они писали простой, аккуратно оформленный и задокументированный код. Этому, поверь, научится гораздо сложнее, чем решению задач на сообразительность. Особенно, когда срок реализации проекта -- вчера.
Простите, но я сомневаюсь, что самое время этому учиться, когда пропущены сроки реализации проекта. Хотя если проект «завален» то есть время и подучиться. Вот только наряду с обучением грамотному использованию синтаксиса C++ хорошо бы учить и базовым принципам преодоления сложности построения программ. А вместо строк документации «не забывайте вызывать AddRef()\Release()» описать в ней ComPtr например.
P.S. (offtopic)
После всего выше приведенного, совет «…вообще забей на хэширование, если ничего в нем не понимаешь.» я скорее буду относить к Вам а не к себе. Хотя мне трудно представить разработчика компиляторов пусть даже скриптовых языков не использующего hash и слабо разбирающегося в рекурсии. Как Вы ассоциируете атрибуты с именем идентификатора без hash? Ищете в неупорядоченном списке? Как разбираете БНФ или просто выражения со скобками без рекурсии? Ручками стеки заводите? И уж совсем невозможно представить 7x24 приложение отказоустойчивость которого базируется на: E_> Указал пользователь четное значение -- сам дурак
Ваша «вежливость» поражает. Мы с Вами на брудершафт не пили. Я старше Вас, не Ваш студент и не надо мне тыкать и советовать забить на хеширование. Не надо называть и младших коллег stupid. То, что сделал Юрий Жмеренецкий вызывает если не восхищение то глубокое уважение. А Вы (см. «Собачье сердце») позволяете себе давать советы Космического масштаба и Космической же глупости. Вот это уже можете считать моей оценкой. А время необходимое для прочтения главы Кнута того же порядка что и время потраченное на оскорбления коллег и эксперименты по хешированию log-а с сомнительной пользой.
Впрочем я сам виноват не надо было связываться с таким человеком:
Цитата из Вашей домашней странички:
... Иностранными языками не владею, на русском пишу с ошибками. Сам себя могу охарактеризовать как системного программиста-камикадзе и патологического изобретателя велосипедов. Системного -- потому, что систематически умудряюсь встревать в безнадежные проекты (фактически все проекты, в которых я участвовал, можно назвать безнадежными). А изобретатель велосипедов -- потому, что меня хлебом не корми, дай что-нибудь свое придумать. Но это уже на генетическом уровне и не лечится.
Конец цитаты.
Мне добавить нечего!
Re[4]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, jazzer, Вы писали:
_W>>>А вот операциями над списками типов — пожалуйста.
E>>Пожалуйста. Если не сложно, конечно.
J>Недавно пробегала это тема уже, типа "кто в реальной работе использует boost::mpl", пошарь по поиску
template<unsigned int n>
struct is_prime{
template<unsigned int k>
struct helper{enum{result=n%k?helper<k-1>::result:0};};
template<>struct helper<1u>{enum{result=1};};
enum{result=helper<n-1>::result};
};
template<>struct is_prime<2u>{enum{result=1};};
//Для сравнения. Очень не эффективный но короткий и ясный код run-time.bool is_prime_fun(unsigned int n){
if(n<2)
return false;
for(unsigned int i(n-1);i!=1;--i)
if(n%i==0)
return false;
return true;
}
Здравствуйте, eao197, Вы писали:
E>Можно ли привести примеры, когда compile-time вычисления оправдывают сложность связанных с ними шаблонов.
... погрызено ... E>Вот мне и интересно, есть ли не академические примеры использования compile-time вычислений? И если есть, то что это за примеры, и оправдали ли себя compile-time вычисления в плане сопровождаемости?
Expression templates — вроде бы хорошая штука
Re[3]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, eao197, Вы писали:
E>Весело, но из области "а можно и так"
Ты хотел примеров, применимых в "реальном мире" (т.е. за пределами реюзабельных библиотек),
я их постарался привести
Что же касается вычислений простых чисел, рядов Фибоначчи и прочих синусов, то имхо это
просто "proof of concept". То есть, демонстрация того, что /можно/ делать в compile-time.
E>Где-то здесь мелькала утилитка по конвертации регулярных выражений в C-шный код. E>Вот это уже интереснее.
Предположим, в программе требуется распознаватель регулярных выражений.
Тогда, есть следующие варианты:
— используем метапрограмму для генерации распознавателя (например expressive или то что выше)
за: (1)не требуется никаких сторонних инструментов (2)не требуется интерпретации выражения в run-time
против: (1)возможна генерация субэффективного распознавателя (2)возможно сильное замедление компиляции (3)в сообщениях об ошибках черт ногу сломает
— используем стороннюю утилиту для генерации распознавателя (flex, re2c, lemon, antlr и проч)
за: (1)не требуется интерпретации выражения в run-time
против: (1)во время билда требуется утилита-генератор и (возможно) сопровождающие ее библиотеки (2)требуется модификация проекта чтобы утилита вовремя вызывалась.
— используем библиотеку-интерпретатор выражений (boost::regex, pcre и проч)
за: можно задавать рег.выражения в run-time
против: нужна скомпилированная статическая библиотека или .dll
Я не хочу сказать, что какой-то из этих вариантов масдай, а какой-то рулез, просто, они есть и это несомненно хорошо.
По крайней мере, я "regex для бедных" достаточно широко использую во всяких мелких утилитах для мелкой обработки текста — просто чтобы время сэкономить. В этом случае, удобство ее подключения и маленький размер — для меня несомненный плюс.
ЗЫ.Вообще-то еще есть несколько широко используемых библиотек-генераторов заточенных именно на end-user-а.
— boost::bind/mem_fn — адаптация callable обьектов к практически произвольным наборам аргументов.
— boost::lambda — генерация произвольных callable обьектов.
Впрочем, тебе ли рассказывать
__________
16.There is no cause so right that one cannot find a fool following it.
Re[3]: Compile-time вычисления: а оно вообще надо?
E><...Научный материал после прочтения поскипан...> E>Юрий, я вообще-то не теоретик, а весьма приземленный практик. Поэтому я постараюсь перевести разговор в более практическое русло.
Мне как практику и теория не чужда. Там я расписал свою точку зрения чтобы ты меня понял.
E>Но многие изыски в области шаблонов и метапрограммирования на шаблонах кажутся мне вопиющим нарушением принципа KISS.
и ниже: E>В общем, уважаемые коллеги по C++ цеху, давайте не будем stupid, и будет пытаться "Keep it simple"
Не знаю почему, но мне эти фразы напоминают ситуацию, которая происходила с stl. Итераторы vs указатели, for vs for_each, и тп.
E>Хочу, чтобы меня поняли правильно. Я фанат C++, я хочу, чтобы C++ процветал, сообщество C++ программистов росло, а количество C++ проектов постоянно увеличивалось. Как мне кажется, для этого необходимо, чтобы программировать на C++ было легко (просто) и удобно.
Имхо, легко и просто не получится, поскольку так устроен язык: практически полный контроль и огромное количество возможностей. Если динамический массив с контролем выхода за границы будет являтся частью языка, то мы потеряем возможность самостоятельного управления памятью, также возникнут потери производитльности в критических точках. Нужен такой массив с С++? если нужен, то его легко реализовать, причем с самым невероятным набором возможностей.
E>Обратимся к самому языку. Понятно, что C++ не самый простой язык, не только в изучении, но и, к сожалению, в использовании. В нем уже сейчас слишком много подводных камней. Но нам этого мало. Складывается впечатление, что мы хотим извести C++ вообще. Превратить его в элитарный инструмент, доступный лишь немногим избранным.
Не спорю, С++ можно считать достаточно сложным (особенно если учитывать backward compatability), но люди хорошо знающие его, умеющие запомнить множество деталей, оринтирующееся где и как применить некую возможность(и отдающие себе отчет почему) будут адекватны в любой работе (это касается не только С++, а любых достаточно сложных вещей).
E>Говорю об этом так уверено, потому что я сейчас смотрю на C++ с двух совершенно разных точек зрения. Во-первых, уже второй год я веду занятия по C++ с группами студентов, из числа которых мы отбирам для себя практикантов, чтобы затем сделать из них наших сотрудников. Я вижу сейчас, как тяжело идет процесс обучения. Как легко люди ошибаются при написании таких элементарных функий, как strcmp или strcpy. Как не понимают, чем различаются вектора и указатели. И как тяжело объяснять, почему сейчас, на двадцать первом году жизни С++ люди пользуются компиляторами, позволяющими применять оператор -- к булевской переменной. Я представляю, сколько нужно дать материала, чтобы объяснить им адресную арифметику, перегрузку операторов, классы и наследования, шаблоны, исключения. Это огромный материал. И даже после этого требуется большой опыт, чтобы не допускать ошибок выхода за пределы массива или возврата из функции ссылки на автоматический объект. В результате срок допуска среднего студента-практиканта к производству production кода растягивается на долгие месяцы, если не годы. А тут мы еще и шаблонное метапрограммирование сверху. Бздынь!
Не знаю как тебе, а мне это все(метапрограммирование, шаблоны, etc.) чертовски _интересно_, и я бы на месте студентов всеми руками держался за то место где учат этому 'Бздынь'. Если нет у студента стремления к саморазвитию, желания стать эдаким творцом в миниатюре, понимать как все это работает в конце концов, то никаким 'вдалбливанием', не поможешь(Имхо, естественно). Кстати, насколько выгодно 'выращивать' программистов для себя ?
E>Во-вторых, повезло мне познакомиться с языком Ruby. В частности с некоторыми его возможностями. Тут уж точно срабатывает поговорка: "К хорошему быстро привыкаешь". В частности, посмотрев, как выглядит метапрограммирование на Ruby ... я пришел к однозначному выводу: можно жить и по другому.
Можно, не спорю. А вдруг и на С++ можно все сделать красиво и лаконично, но пока неизвестно как... ("в тихом омуте черти водятся").
E>На этом лирическое вступление заканчиваю и перехожу к выводам. А вывод простой: я не хочу писать такой код, который привел ты и Dmi_3. Я не хочу читать такой код. Я хочу держаться подальше от проектов, в которых есть такой код. E>Потому, что я считаю его неоправдано сложным. Как в написании, так и в отладке, и в сопровождении.
А как ты относишся к boost и stl ? Ведь в рассматриваемом контекте концептуально они не отличаются от "моего кода" и кода Dmi_3. Да и boost::mpl по большей части калька с stl + функциональный подход.
E>Шаблоны -- хорошая вещь, но чувство меры и зравый смысл должен все же брать верх. Как замечательно кто-то сказал: E>Я люблю математику, но не в лошадиных дозах.
Будешь смеяться, но по образованию я математик, и местами люблю математику именно в лошадинных дозах
E>Ну здесь дело вкуса. Мне, например, нравится идея кодогенерации на сриптовых языках ... E>Понятно, что это моя личная идея фикс, но все же. Давай задумаемся, что проще -- научиться программировать на Python/Perl/Ruby или освоить метапрограммирование на C++ных шаблонах? Имхо, задачи практически одной сложности, может даже освоение Python/Ruby попроще будет.
Освоение метапрограммирования влечет за собой существенный профессиональный рост программиста как программиста на С++.
E>А вот что полезнее? Мне кажется, что знание еще одного динамического языка
А по мне, функционального , хотя это ортогонально.
E>Ну, например, за последний месяц мне потребовалось создать пять или шесть классов, которые были предназначены только для хранения конфигурационных параметров. Т.е. штук пять-семь атрибутов, конструктор по-умолчанию, setter-/getter-ы для каждого атрибута. Писать все это вручную -- муторно. Прятать за макросами -- не читабельно. Да и с инициализацией атрибутов в конструкторе по умолчанию не все просто. А я представил себе, как бы было интересно, если бы я в hpp-файле просто написал такой фрагмент:
.... E>Вот это я понимаю, вот это метапрограммирование! E>На шаблонах еще попробовать это сделать нужно
Вот, откопал у себя(устаревший вариант):
using namespace cttl_old;
struct MyPointMeta
{
struct attribyte
{
struct PosX : integer<int, 0> {}; // int - тип переменной, 0-значение по умолчаниюstruct PosY : integer<int, 0> {};
struct PosZ : integer<int, 0> {};
typedef typelist<PosX, PosY, PosZ> alist; // увы, обязательно
};
// еще можно использовать функции
// функции реализованы как функторы, принимающие два параметра
// - контейнер аргументов + сам объект(контейнер аттрибутов)struct function
{
// функция не несет никакого смысла, только пример
// Пусть Show принимает три параматра ;)
// void - возвращаемый типstruct Show : signature<void, typelist<int, int, int> >
{
// args - входные параметры
// object - сам объект (все по ссылкам)
BODY(args, object)
{
using attribyte::PosY;
std::cout << "PosX: " << object.get<attribyte::PosX>() << //можно так
<< "PosY: " << object.get<PosY>() << // или так. см. using выше
<< "PosZ: " << object.get<attribyte::PosZ>() <<
std::endl;
// доступ к входным параметрам
object.get<attribyte::PosX>() = args.get<0>();
object.get<attribyte::PosZ>() = args.get<2>();
object.get<PosY>() = args.get<1>();
}
};
// список всех функций, в принципе необязательно, необходим для некоторых возможностейtypedef typelist<Show> fnlist;
};
};
int main()
{
using namespace std;
typedef make_class<MyPointMeta> MyPoint;
MyPoint pt; // будет вызван конструктор с указанными параметрами по умолчанию
// get/set выражены одной функцией get, возвращающей ссылку
pt.get<MyPoint::PosX>() = 100;
pt.get<MyPoint::PosY>() = 4306;
// x имеет тип int ;)
MyPoint::PosX::type x = pt.get<MyPoint::PosX>();
cout << x << endl;
// вызов функций
MyPoint::function::Show::args a;
a << 1 << 2 << 3; // Типы, естественно проверяются
pt.call<MyPoint::function::Show>(a);
// было еще такое ;)
// куда трассируем (в указанном порядке)typedef typelist<trace::file, trace::output_window, trace::console> my_destination;
// трассировать всеtypedef tracer<my_destination, trace::full> my_tracer;
// заодно измерим время выполнения...typedef typelist<my_tracer, timed> call_mode;
call_mode cm;
// установим дополнительные параметры
cm.get<trace::file_name>() = "c:\\temp\\log.txt";
system::ret_val res;
// собственно вызов функции. + замер времени выполнения, + трассировка в файл,
// output_window и на консоль, и это _без_ модификации исходной функции
// Это вызов одной функции, а можно одной строкой привязать call_mode ко всем функциям в классе.
res = pt.call<MyPoint::function::Show>(a, cm);
// время выполнения
cout << res.get<function::exec_time>() << endl;
}
Такой подход сложен только в реализации, а использование... Любой рефлекшн/перехват функций и т.п.
прикрутить не проблема. Я не агитирую за применение такого подхода, всего лишь демонстрирую что
можно сделать не выходя за рамки языка. И это, ИМХО, далеко не идеал...
Вообще, подводя итоги — мне кажется, что сложность в одном месте рождает простоту в другом и этим себя оправдывает.
Здравствуйте, Dmi_3, Вы писали:
>>>Хотя может быть этот пример и не показателен, может hash_pjw из ACE не самая оптимальная hash-функция для моего log-файла (для 8209 строк дает 6802 уникальных значения, а ведь в каждой строке есть уникальный timestamp, т.к. повторяющихся строк в нем практически нет)
D_>Вероятность хотя бы одной коллизии для хорошей 32 битной хеш-функции на уникальных ключах в Вашем случае (8209 записей) составляет около 0.007. Вероятность двух исчезающе мала. 1407 коллизий это перебор. Но именно плохая хэш-функция и привела к таким результатам Вашего эксперимента.
Какая была, такую и использовал. Не всегда есть время изучать Кнута и выбирать оптимальную хэш-функцию, приходится брать то, что есть.
Кроме-то на этих данных лога выпадает такое распределение. Со временем характер данных в логе может поменяться.
D_>Раз уж Вы решили экспериментировать вместо изучения «академической» литературы то позвольте дать несколько советов. D_>1. Измените оценку результатов с подсчёта количества нулей на среднеквадратическое отклонение разбросов счётчиков. (Чем меньше, тем лучше) D_>Ну или сумму модулей отклонений от среднего.
Если руки дойдут. Но даже эта оценка показывает, что только простого числа в качестве размерности для получения нормального распределения ключей не достаточно.
D_>2. Попробуйте изменить хэш-функцию на h=A0*ACE::hash_pjw()+A1; где A0 это 3, 23, а лучше 29 и A1 любая (лучше небольшая) константа и попробовать Ваш любимый capacity=2001. Ведь Вы не знаете, может там внутри ACE::hash_pjw другой практик так и сделает потом. (для capacity= 2501 он выберет A0 41 или 61. кстати всего два делителя число почти простое)
Вот: A0 == 29, A1 == 5
(я чуть изменил программу, чтобы можно было емкость задавать в командной строке).
Не вижу никаких преимуществ от выбора простых чисел для ограничения размерности. Главное -- это качество хэш функции. Поэтому навороты с поиском простых чисел в compile-time все равно, по моему мнению, излишество.
D_>6. ОЧЕНЬ ответственно относитесь к выбору хэш-функций, исследуя типичные данные для Вашего случая. Хеширование идентификаторов и путей к файлам – две большие разницы.
Либо вообще забей на хэширование, если ничего в нем не понимаешь.
D_>7. Не уподобляйтесь моему знакомому преподавателю, учившему студентов, что hash реализован в STL в виде std::map. Или другому знакомому с фразой «Но ведь работает же». (извините — наболело).
В STL нет hash.
D_>8. Если какое-то требование к использованию кода можно выразить явно в программе – выразите. Это будет дополнительной гарантией. Разве все внимательно читают документацию?
Что выразить? Что пользователь твоего кода должен искать сам простые числа? Имхо, я бы быстрее нашел другую библиотеку.
D_>Того, кому не понятно, что это массив простых чисел ближайших к последовательным числам Фибоначчи можно безболезненно увольнять.
Значит меня бы уволили.
Кроме того, увидеть что-то в последовательности чисел и разрабатывать систему работающую в режиме 24x7 или транслятор скриптового языка -- это разные задачи, тебе не кажется? Помягче нужно быть с оценками.
D_>А эту последовательность далеко не каждый сумеет понять. Можете дать своим студентам в качестве упражнения на сообразительность. D_>59,89,149,233,379,613,991,1597,2591,4201,6779,10949,17713,28657,46381,75029,121403,196429,317827,514229,832063,1346273,2178313,3524603,5702897
Ага, мне бы самом понять, что это такое.
А от своих студентов я больше требую, чтобы они писали простой, аккуратно оформленный и задокументированный код. Этому, поверь, научится гораздо сложнее, чем решению задач на сообразительность. Особенно, когда срок реализации проекта -- вчера.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
D_>Того, кому не понятно, что это массив простых чисел ближайших к последовательным числам Фибоначчи можно безболезненно увольнять. Этот код был в cpp файле и компилировался лишь один раз. В отладчике я его ни разу не видел.
Ну вот в этом-то и проблема. Как ты хотел бы увидать его в отладчике? Он же CT
D_>А эту последовательность далеко не каждый сумеет понять. Можете дать своим студентам в качестве упражнения на сообразительность. D_>59,89,149,233,379,613,991,1597,2591,4201,6779,10949,17713,28657,46381,75029,121403,196429,317827,514229,832063,1346273,2178313,3524603,5702897
Хорошая последоательность. Видно, например, сколь велико самое большое из чисел. Про near_prime<fibonachchi<46>::result>::result такого не скажешь
А вообще скрипт, генерящий эту последовательность или c++ утилита и чтабельнее и поддерживаемее и компилятор меньше напрягает не по делу
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Dmi_3, Вы писали:
D_>Вероятность хотя бы одной коллизии для хорошей 32 битной хеш-функции на уникальных ключах в Вашем случае (8209 записей) составляет около 0.007. Вероятность двух исчезающе мала. 1407 коллизий это перебор. Но именно плохая хэш-функция и привела к таким результатам Вашего эксперимента. Если бы она была хорошей и биты хэш значения независимы, то никакой существенной разницы Вы бы не обнаружили. (я не говорю о Ваших смешных 0.21% которые видимо объясняются просто разными размерами буферов и его величеством Случаем)
Продолжаем эксперимент в духе brute force. Я модифицировал программу. Теперь она использует не только ACE::hash_pjw, но и три метода из исходного кода Ruby 1.8.1, а также несколько hash-функций из исходного кода Berkeley DB. Я думаю вряд ли стоит ожидать, что в Ruby и в Berkeley DB попали корявые реализации hash-функций.
Вот полученные результаты работы. Первое значение -- это количество оставшихся свободными ячеек в хеш-таблице. Второе значение -- это максимальное количество коллизий в одной ячейке. Третье значение показывает, сколько уникальных 32-х битовых хэшей было получено.
Так что я по прежнему нахожусь при мнении, что важно выбрать правильную хеш-функцию. А уж будет размер хэш-таблицы простым числом, или нет -- это уже дело десятое. И все навороты по вычислению простых чисел в compile-time -- это из области удовлетворения собственного любопытства, а не реальной необходимости.
Вот код программы. Приношу извинения всем, кому тяжело будет выкачивать сообщение столь большого размера.
Так же нужно отметить, что в программу вошли фрагменты кода, произведенные из кода Ruby и Berkeley DB, т.о. эти фрагменты находятся под действием Ruby-лицензии и лицензии Sleepycat Software (приношу ей свои изменения, что из-за экономии места не привожу текст их лицензии, как они это требуют ).
#include <memory>
#include <iostream>
#include <vector>
#include <list>
#include <set>
#include <string>
#include <iterator>
#include <algorithm>
#include <functional>
#include <cstdlib>
#include <ace/ACE.h>
typedef std::list< int > capacities_t;
typedef std::list< std::string > lines_t;
typedef unsigned long (*pfn_hash_t)(
const char * data,
std::size_t data_size );
struct distribution_t
{
//! Количество свободных элементов в хеш таблице.int m_free;
//! Максимальное количество коллизий в одном элементе.
u_long m_max;
//! Количество уникальных 32-х битовых хешей.int m_uniq;
distribution_t( int free, u_long max, int uniq )
: m_free( free )
, m_max( max )
, m_uniq( uniq )
{}
};
std::ostream &
operator<<( std::ostream & o, const distribution_t & d )
{
char sz[ 48 ];
std::sprintf( sz, "%d/%lu/%d", d.m_free, d.m_max, d.m_uniq );
return o << sz;
}
capacities_t
all_capacities( char ** b, char ** e )
{
capacities_t r;
std::transform( b, e,
std::back_inserter( r ),
std::ptr_fun( std::atoi ) );
return r;
}
std::auto_ptr< lines_t >
load_data( int max_capacity )
{
std::auto_ptr< lines_t > data( new lines_t() );
for( int i = 0; std::cin && i != max_capacity; )
{
std::string v;
std::getline( std::cin, v );
if( !v.empty() )
{
data->push_back( v );
++i;
}
}
return data;
}
distribution_t
calc_distribution(
const lines_t & lines,
int capacity,
pfn_hash_t hash )
{
typedef std::vector< u_long > vector_t;
typedef std::set< u_long > uniques_t;
vector_t hash_table( capacity );
uniques_t uniq;
int i = 0;
for( lines_t::const_iterator it = lines.begin();
i != capacity;
++i, ++it )
{
unsigned long h = (*hash)( it->data(), it->size() );
uniq.insert( h );
++hash_table[ h % capacity ];
}
return distribution_t(
std::count( hash_table.begin(), hash_table.end(), 0 ),
*std::max_element( hash_table.begin(), hash_table.end() ),
uniq.size() );
}
const int method_name_width = 13;
const int value_width = 13;
void
show_table_header(
const capacities_t & capacities )
{
std::cout.width( method_name_width );
std::cout << "";
for( capacities_t::const_iterator it = capacities.begin(),
it_end = capacities.end();
it != it_end;
++it )
{
std::cout.width( value_width );
std::cout << *it << std::flush;
}
std::cout << std::endl;
}
void
try_hash_method(
const std::string & method_name,
pfn_hash_t hash,
const lines_t & lines,
const capacities_t & capacities )
{
std::cout.width( method_name_width );
std::cout << method_name;
for( capacities_t::const_iterator it = capacities.begin(),
it_end = capacities.end();
it != it_end;
++it )
{
std::cout.width( value_width );
std::cout << calc_distribution( lines, *it, hash ) << std::flush;
}
std::cout << std::endl;
}
// Примечание: следующий код находится под Ruby лицензией.unsigned long
ruby_elf( const char * p, std::size_t len )
{
unsigned long key = 0;
unsigned long g;
while (len--) {
key = (key << 4) + *p++;
if (g = key & 0xF0000000)
key ^= g >> 24;
key &= ~g;
}
return key;
}
unsigned long
ruby_perl( const char * p, std::size_t len )
{
unsigned long key = 0;
while (len--) {
key += *p++;
key += (key << 10);
key ^= (key >> 6);
}
key += (key << 3);
key ^= (key >> 11);
key += (key << 15);
return key;
}
unsigned long
ruby_default( const char * p, std::size_t len )
{
unsigned long key = 0;
while (len--) {
key = key*65599 + *p;
p++;
}
key = key + (key>>5);
return key;
}
// Примечание: следующий код находится под действием лицензии Berkeley DB.
/*
* __ham_func2 --
* Phong Vo's linear congruential hash.
*
* PUBLIC: u_int32_t __ham_func2 __P((DB *, const void *, u_int32_t));
*/#define DCHARHASH(h, c) ((h) = 0x63c63cd9*(h) + 0x9c39c33d + (c))
unsigned long
__ham_func2( const char * key, unsigned int len)
{
const unsigned char *e, *k;
unsigned int h;
unsigned char c;
k = reinterpret_cast< const unsigned char * >( key );
e = k + len;
for (h = 0; k != e;) {
c = *k++;
if (!c && k > e)
break;
DCHARHASH(h, c);
}
return (h);
}
/*
* __ham_func3 --
* Ozan Yigit's original sdbm hash.
*
* Ugly, but fast. Break the string up into 8 byte units. On the first time
* through the loop get the "leftover bytes" (strlen % 8). On every other
* iteration, perform 8 HASHC's so we handle all 8 bytes. Essentially, this
* saves us 7 cmp & branch instructions.
*
* PUBLIC: u_int32_t __ham_func3 __P((DB *, const void *, u_int32_t));
*/unsigned long
__ham_func3(const char * key, unsigned int len)
{
const unsigned char *k;
unsigned int n, loop;
if (len == 0)
return (0);
#define HASHC n = *k++ + 65599 * n
n = 0;
k = reinterpret_cast< const unsigned char * >( key );
loop = (len + 8 - 1) >> 3;
switch (len & (8 - 1)) {
case 0:
do {
HASHC;
case 7:
HASHC;
case 6:
HASHC;
case 5:
HASHC;
case 4:
HASHC;
case 3:
HASHC;
case 2:
HASHC;
case 1:
HASHC;
} while (--loop);
}
return (n);
}
/*
* __ham_func4 --
* Chris Torek's hash function. Although this function performs only
* slightly worse than __ham_func5 on strings, it performs horribly on
* numbers.
*
* PUBLIC: u_int32_t __ham_func4 __P((DB *, const void *, u_int32_t));
*/unsigned long
__ham_func4(const char * key, unsigned int len)
{
const unsigned char *k;
unsigned int h, loop;
if (len == 0)
return (0);
#define HASH4a h = (h << 5) - h + *k++;
#define HASH4b h = (h << 5) + h + *k++;
#define HASH4 HASH4b
h = 0;
k = reinterpret_cast< const unsigned char * >( key );
loop = (len + 8 - 1) >> 3;
switch (len & (8 - 1)) {
case 0:
do {
HASH4;
case 7:
HASH4;
case 6:
HASH4;
case 5:
HASH4;
case 4:
HASH4;
case 3:
HASH4;
case 2:
HASH4;
case 1:
HASH4;
} while (--loop);
}
return (h);
}
/*
* Fowler/Noll/Vo hash
*
* The basis of the hash algorithm was taken from an idea sent by email to the
* IEEE Posix P1003.2 mailing list from Phong Vo (kpv@research.att.com) and
* Glenn Fowler (gsf@research.att.com). Landon Curt Noll (chongo@toad.com)
* later improved on their algorithm.
*
* The magic is in the interesting relationship between the special prime
* 16777619 (2^24 + 403) and 2^32 and 2^8.
*
* This hash produces the fewest collisions of any function that we've seen so
* far, and works well on both numbers and strings.
*
* PUBLIC: u_int32_t __ham_func5 __P((DB *, const void *, u_int32_t));
*/unsigned long
__ham_func5(const char * key, unsigned int len)
{
const unsigned char *k, *e;
unsigned int h;
k = reinterpret_cast< const unsigned char * >( key );
e = k + len;
for (h = 0; k < e; ++k) {
h *= 16777619;
h ^= *k;
}
return (h);
}
// ---int
main( int argc, char ** argv )
{
if( 1 < argc )
{
capacities_t capacities = all_capacities( argv + 1, argv + argc );
int max_capacity = *std::max_element(
capacities.begin(), capacities.end() );
std::auto_ptr< lines_t > data = load_data( max_capacity );
show_table_header( capacities );
try_hash_method( "ACE::hash_pjw", &ACE::hash_pjw,
*data, capacities );
try_hash_method( "Ruby ELFHASH", &ruby_elf,
*data, capacities );
try_hash_method( "Ruby PERL", &ruby_perl,
*data, capacities );
try_hash_method( "Ruby default", &ruby_default,
*data, capacities );
try_hash_method( "BDB HAM_FUNC2", &__ham_func2,
*data, capacities );
try_hash_method( "BDB HAM_FUNC3", &__ham_func3,
*data, capacities );
try_hash_method( "BDB HAM_FUNC4", &__ham_func4,
*data, capacities );
try_hash_method( "BDB HAM_FUNC5", &__ham_func5,
*data, capacities );
return 0;
}
else
{
std::cout << "hash_test2 <capacity1> [<capacity2> ...]"
<< std::endl;
return -1;
}
}
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
D_>>А эту последовательность далеко не каждый сумеет понять. D_>>Можете дать своим студентам в качестве упражнения на сообразительность. D_>>59,89,149,233,379,613,991,1597,2591,
E>Если приведенный выше фрагмент в конце-концов сводится к указанной последовательности чисел, E>то почему нельзя было записать так: E>
Конечно, написать было можно. Но это только часть последовательности.
near_prime<fibbonachchi<46>::result>::result == 1836311951
near_prime<fibbonachchi<47>::result>::result == 2971215073
И, допустим, что я в 20-том числе допустил ошибку. Это легко, памятуя о двух "опечатках"
в исчезнувшем STATIC_ASSERT((size&2)==0);
Контр-вопрос: Сколько времени Вы проведёте в отладчике, прежде чем найдёте несоответствие комментария
и действительности учитывая, что на маленьких тестовых примерах всё OK да и на больших всё работает
но сильно тормозит? Е_>ИМХО. Я быстрее найду другую библиотеку.
Ну и наконец: E_>Было бы круто, если бы .... реализация сама бы подобрала бы ближайшее «БЫ» сверху простое число.
Я тоже человек. Мне не интереееесно всё это вычислять!
Предвидя Ваши возражения про кодогенератор скажу следующее.
1. Выражение типа {@"%$ near_prime_fibonachchi @#16} ничем не лучше моего.
2. Я немогу совсем абстрагироваться от реализации т.к. должен помнить по крайней мере эти "интерфейсные" @"%$ @#.
Это и к документатору относится !\note
В моём случае программа самодокументирована, вероятность ошибки набора минимальна,
сама ошибка легко визуально обнаружима и моя бедная голова свободна от @"%$ @#.
А в другой фирме от @#$%#$%^&^
Что такие последовательности символов означают, Вы знаете.
Расплатой за все прелести является "навороченный" код в пол экрана.
Написание (и разбор с пониманием) которого способствует моему росту как программиста C++,
лучшему пониманию рекурсии и т.д.
А если кому-то он кажется сложным, то можно и абстрагироваться. (это не "наезд").
E>И что будет с вашим кодом на 64-х битовой платформе, где емкость контейнера в 6 миллионов экземляров -- это мелочь (да и на 32-х битовой платформе это не будет проблемой)?
Кажется я уже нечаянно ответил.
Но если Вы имеете ввиду, что is_prime<N64>::result не может быть вычислена
т.к. придётся перебрать в CT слишком много делителей, то скажу
что там алгоритм вообще не ищет делителей.
Есть очень эффективные методы определения простоты числа именно без получения его делителей.
Они и с 256 битным по идее в CT должны справиться.
Как там это сделано прошу не спрашивать, но см. тест Миллера-Рабина.
С его помощью в CT можно искать почти простые числа.
Извинения принимаются. Проехали?
E>А вот вас я попрошу либо привести точную цитату того, что по моему мнению к Юрию относится термин stupid. Либо публично забрать свои слова обратно.
После загадочного исчезновения Вашей ошибки со STATIC_ASSERT((size&2)==0);
Я считаю странной эту просьбу.
1. Эти слова могли оказаться там же где и ASSERT
2. Вы сами можете их убрать а заодно добавить мои "восхищённые" восклицания по поводу модерирования.
3. Предлагаю ввести электронные подписи сообщений во избежание подобных инцидентов.
Тем не менее:
class Dmi_3
WORD (*phrase)[];
public://Вы просили публично.
get_to_back(){delete phrase; phrase=0;}
};
Dmi_3 the_Dmi_3;
int main(){
the_Dmi_3.get_to_back();
}
Я рад, что ошибся в Вашем отношении к коллегам вообще и к Юрию в частности.
НЕ БОЛЕЕ ТОГО.
Далее без дипломати.
E_>>> Что выразить? Что пользователь твоего кода должен искать сам простые числа? D_>>Если задача этого требует то да (cм. RSA-криптосистема с открытыми ключами).
E>По-вашему, простые числа (для 2048-битовых или 4096-битовых ключей) можно искать в compile-time?
Нет. Но я этого и не говорил.
E>А с чего бы ему это потребовалось менять числа если приложение работает нормально?
Иногда может попасться хэш-функция
unsigned long
hash_fun( const char * p, std::size_t len ){
unsigned long key = 0;
while (len--) {
enum{mul=89};
STATIC_ASSERT(is_prime<mul>::result);//Это иногда делает hash_fun хорошей.
key = key*mul + *p;
p++;
}
key = key + (key>>5);
return key;
}
где mul совпадёт с текущим размером hash. Последствия могут быть плачевны.
Пользователь, обнаружив это, решит переиначить «магические» числа размеров буферов.
E>Вам же могу посоветовать больше внимания оформлению своего кода. Его очень тяжело читать.
С этого места поподробней please.
E>Ой, а откуда следовало, что я плохо разбираюсь в рекурсии?
Приведённые мною template ну очень похожи на рекурсивные функции runtime.
Если их легко понять то и template легко.
int fibo(int n,int a=0,int b=1){//template<N,A=0,B=1>struct FIBOif(n==0) return a; // Аналог частичной специализации для N=0 enum{result=A};return fibo(n-1,b,a+b);// enum{result=FIBO<N-1,B,A+B>::result};
}
Здравствуйте, _Winnie, Вы писали:
_W>Здравствуйте, Dmi_3, Вы писали:
_W>Ничего не понимаю. Если hash-функция подобрана нормально, то ей пофиг по модулю чего ее брать. Если на каких-то она модулях сбоит, значит писавшему её надо кое-что оторвать.
И, кстати, деление на простое число — это в 12 раз медленней, чем побитовая операция &.
Ф топку такую "оптимизацию", лучше заставить пользователя выбрать нормальную хеш-функцию.
Правильно работающая программа — просто частный случай Undefined Behavior
Re[4]: Compile-time вычисления: а оно вообще надо?
Вообще-то, что-то в словах Erop есть...
Я бы так сказал по поводу твоего кода, Дмитрий: программировать на C++ было бы куда приятнее, если бы для реализации этой задачи достаточно было бы написать в два раза меньше кода.
Но, к сожалению, процесс развития C++ идет не так быстро как хотелось бы. Поэтому сейчас и кажется, что подобные решения вполне удовлетворительны. А если бы нам дали в руки более удобный инструмент для метапрограммирования, то мы бы сами ужаснулись, насколько сложно все было в прошлом. Только вот что это за инструмент должен быть -- я не знаю.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[5]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, eao197, Вы писали:
CX>>А уж я то насколько ленив! Веришь — все эти шаблонные навороты, они как раз из-за лени. Ну лень мне педалить почти один и тот же код много раз, натыкаясь на одни и те же ошибки.
E>Так ведь все велосипеды от лени появляются Мне когда-то было лень запоминать обозначения в make-правилах (всякие $@, $<, $> ), теперь у меня свой инструмент для управления компиляцией .
За это тебе огромный респект.
E>А настоящая лень наступает, когда от использования велосипеда уже кайфа нет, когда это использование становиться рутиной, а сопровождать нужно...
А вот тут помогает отдых на природе, в кругу хороших друзей, в осеннем лесу, пропахшем дымком, с шашлычком да хорошей водочкой (или вином — это уже по вкусам). Гитара еще неплохо сюда вписывается. Опять же — рыбалочка под тихий шум дождя да по грибочки на следующий день. Лепота!
Три-четыре дня такого отдыха — и опять рвешься грудью на амбразуру, никто не в силах удержать.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[10]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, CrystaX, Вы писали:
CX>А вот тут помогает отдых на природе, в кругу хороших друзей, в осеннем лесу, пропахшем дымком, с шашлычком да хорошей водочкой (или вином — это уже по вкусам). Гитара еще неплохо сюда вписывается. Опять же — рыбалочка под тихий шум дождя да по грибочки на следующий день. Лепота! CX>Три-четыре дня такого отдыха — и опять рвешься грудью на амбразуру, никто не в силах удержать.
А неделя болезни маленького ребенка отбивает охоту работать не несколько месяцев вперед
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[11]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, eao197, Вы писали:
E>Вот мне и интересно, есть ли не академические примеры использования compile-time вычислений? И если есть, то что это за примеры, и оправдали ли себя compile-time вычисления в плане сопровождаемости?
Ну, на практике с compile-time вычислениями ЧИСЕЛ не сталкивался.
Ну разве что проверка, равно ли число степени двойки. Это можно проверить двумя способами — либо compile-time цикл по битам числа. Это был первый вариант. Но оказалось, что всё очень просто —
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, _Winnie, Вы писали:
_W>>А вот операциями над списками типов — пожалуйста.
E>Пожалуйста. Если не сложно, конечно.
Недавно пробегала это тема уже, типа "кто в реальной работе использует boost::mpl", пошарь по поиску
Здравствуйте, eao197, Вы писали:
_W>>А вот операциями над списками типов — пожалуйста.
E>Пожалуйста. Если не сложно, конечно.
В том же бусте примеров масса (он у нас к академическим игрушкам относится или нет ?). Например, Boost.Variant — внутреннее представление класса и интерфейс вычисляются из списка типов.
Prefer compile- and link-time errors to run-time errors из C++ Coding Standards: 101 Rules, Guidelines, and Best Practices
E>Вот мне и интересно, есть ли не академические примеры использования compile-time вычислений? И если есть, то что это за примеры, и оправдали ли себя compile-time вычисления в плане сопровождаемости?
сравни BOOST_STATIC_ASSERT(...) и if (...) throw smth_wrong(); итд
Re[4]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, Глеб Алексеев, Вы писали:
E>>Пожалуйста. Если не сложно, конечно.
ГА>В том же бусте примеров масса (он у нас к академическим игрушкам относится или нет ?). Например, Boost.Variant — внутреннее представление класса и интерфейс вычисляются из списка типов.
Для меня пока к академическим
Недавно здесь обсуждали boost::filesystem. Красивая, вроде вещь, а на практике удобнее обертки над POSIX-овыми функциями из ACE использовать. Для того же удаления файлов, например. В Variant-ах мне как-то вообще нуждаться не приходилось, повезло, видимо.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[2]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, Pavel Chikulaev, Вы писали:
PC>Prefer compile- and link-time errors to run-time errors из C++ Coding Standards: 101 Rules, Guidelines, and Best Practices PC>
E>>Вот мне и интересно, есть ли не академические примеры использования compile-time вычислений? И если есть, то что это за примеры, и оправдали ли себя compile-time вычисления в плане сопровождаемости? PC>сравни BOOST_STATIC_ASSERT(...) и if (...) throw smth_wrong(); итд
Это все из другой оперы.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[2]: 14. Prefer compile- and link-time errors to run-time
Позволю себе написать выдержку из C++ Coding Standards: 101 Rules, Guidelines, and Best Practices
14. Prefer compile- and link-time errors to run-time errors
Summary
Don't put off 'til run time what you can do at build time: Prefer to write code that uses the compiler to check for invariants during compilation, instead of checking them at run time. Run-time checks are control- and data-dependent, which means you'll seldom know whether they are exhaustive. In contrast, compile-time checking is not control- or data-dependent and typically offers higher degrees of confidence.
Discussion
The C++ language offers many opportunities to "accelerate" error detection by pushing it to compilation time. Exploiting these static checking capabilities offers you many advantages, including the following:
Static checks are data- and flow-independent: Static checking offers guarantees that are independent of the program inputs or execution flow. In contrast, to make sure that your run-time checking is strong enough, you need to test it for a representative sample of all inputs. This is a daunting task for all but the most trivial systems.
Statically expressed models are stronger: Oftentimes, a program that relies less on run-time checks and more on compile-time checks reflects a better design because the model the program creates is properly expressed using C++'s type system. This way, you and the compiler are partners having a consistent view of the program's invariants; run-time checks are often a fallback to do checking that could be done statically but cannot be expressed precisely in the language. (See Item 68.)
Static checks don't incur run-time overhead: With static checks replacing dynamic checks, the resulting executable will be faster without sacrificing correctness.
One of C++'s most powerful static checking tools is its static type checking. The debate on whether types should be checked statically (C++, Java, ML, Haskell) or dynamically (Smalltalk, Ruby, Python, Lisp) is open and lively. There is no clear winner in the general case, and there are languages and development styles that favor either kind of checking with reportedly good results. The static checking crowd argues that a large category of run-time error handling can be thus easily eliminated, resulting in stronger programs. On the other hand, the dynamic checking camp says that compilers can only check a fraction of potential bugs, so if you need to write unit tests anyway you might as well not bother with static checking at all and get a less restrictive programming environment.
One thing is clear: Within the context of the statically typed language C++, which provides strong static checking and little automatic run-time checking, programmers should definitely use the type system to their advantage wherever possible (see also Items 90 through 100). At the same time, run-time checks are sensible for data- and flow-dependent checking (e.g., array bounds checking or input data validation) (see Items 70 and 71).
Examples
There are several instances in which you can replace run-time checks with compile-time checks.
Example 1: Compile-time Boolean conditions. If you are testing for compile-time Boolean conditions such as sizeof(int) >= 8, use static assertions instead of run-time tests. (But see also Item 91.)
Example 2: Compile-time polymorphism. Consider replacing run-time polymorphism (virtual functions) with compile-time polymorphism (templates) when defining generic functions or types. The latter yields code that is better checked statically. (See also Item 64.)
Example 3: Enums. Consider defining enums (or, better yet, full-fledged types) when you need to express symbolic constants or restricted integral values.
Example 4: Downcasting. If you frequently use dynamic_cast (or, worse, an unchecked static_cast) to perform downcasting, it can be a sign that your base classes offer too little functionality. Consider redesigning your interfaces so that your program can express computation in terms of the base class.
Exceptions
Some conditions cannot be checked at compile time and require run-time checks. For these, prefer to use assertions to detect internal programming errors (see Item 68) and follow the advice in the rest of the error handling section for other run-time errors such as data-dependent errors (see Items 69 through 75).
Re[3]: Compile-time вычисления: а оно вообще надо?
.
E>>Хотелось бы поговорить о наболевшем, о шаблонных наворотах. На примере compile-time вычислений в частности.
S>А вычисление размера TypeList — Вы считаете compile-time вычислением ?
Нет.
Хотя, если ты приведешь реальный пример, где тебе потребовался TypeList, то я буду признателен.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[3]: Compile-time вычисления: а оно вообще надо?
. E>Хотелось бы поговорить о наболевшем, о шаблонных наворотах. На примере compile-time вычислений в частности. E>Можно ли привести примеры, когда compile-time вычисления оправдывают сложность связанных с ними шаблонов.
Ну, например, у меня в моей велосипедной библиотеке форматирования CT-вычисления используются для оценки размера результирующего буффера — используется самодельное вычисление логарифма. Конечно, можно было бы тупо зарезервировать буффер в 100 символов для обычных чисел, но это некрасиво.
Еще в моей библиотеке контейнеров используется CT-вычисления, но простые.
Математическим compile time вычислениям я тоже не нахожу применения, но вот касательно вычислений, основанных на списках типов...
1. В моем парсере LL(k) используется синтаксическая категория one_of, построенная на той же идее, что и boost::variant.
2. В проекте используется система семантически разных типов, которые являются (по совместительству ) различными также и синтаксически. С автоматическим преобразованием из одной системы в другую при необходимости. Сделано на основе boost::mpl. Штука весьма полезная.
Если покопаться поглубже, наверняка еще кой-что вспомнится.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[4]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, _Winnie, Вы писали:
_W>Здравствуйте, eao197, Вы писали: E>>Здравствуйте, _Winnie, Вы писали: _W>>>А вот операциями над списками типов — пожалуйста. E>>Пожалуйста. Если не сложно, конечно.
_W>Это кусочек кода из Winnie Format Library. _W>Нужно для выражения вроде
_W>format("hello, %s %d %f %(1) %(2) %(0) %(0)") % "world" % 10 % 10.0
_W>Оно ничего не делает, кроме запоминания списка указателей на временные переменные — параметры operator %, которые __ПОТОМ__ надо распечатать в поток(буфер). Поэтому форматировать на ходу нельзя (так как правило no mallocs).
Это как раз тот случай, когда навороты на шаблонах вполне оправданы.
Да и пользователь твоего формата вполне защищен от них.
_W>Еще пример — передача параметра в функцию с неизвестной на этапе компиляции сигнатуры. _W>Например: pObject->Call("SomeFunction", 1, 2, 3) где динамически определяется, если у объекта неизвестного типа "SomeFunction", а если есть, то можно ли преобразовать параметры из (int, int, int) в (bool, float, long) _W>Надо проверить в run-time, возможно ли преобразование из типа фактического параметра в тип формального параметра. _W>Для этого нужна квадратная табличка пребразователей из типа в тип. Её, конечно, лучше сгенерить в compile-time по заданному списку типов.
А вот это уже от лукавого. Динамические языки с такими вещами справляются гораздо лучше. ИМХО, конечно.
_W> Можно, конечно и в скрипте, но он никогда в жизни не поймёт, что signed и int — это одно и тоже.
А это уже как скрипт напишешь
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[5]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, eao197, Вы писали:
E>Что я буду в STATIC_ASSERT проверять, что вычисленный компилятором в compile-time синус равен извесному мне заранее значению?
Незнаю как синус, а проверка на то, что размер буфера(hash,random,...) есть простое число иногда бывает нужна.
Re[4]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, Dmi_3, Вы писали:
E>>Что я буду в STATIC_ASSERT проверять, что вычисленный компилятором в compile-time синус равен извесному мне заранее значению?
D_>Незнаю как синус, а проверка на то, что размер буфера(hash,random,...) есть простое число иногда бывает нужна.
А можно подробнее? Для каких hash, random алгоритмов нужно, чтобы размер буфера был простым числом?
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[5]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, eao197, Вы писали:
E>Недавно здесь обсуждали boost::filesystem. Красивая, вроде вещь, а на практике удобнее обертки над POSIX-овыми функциями из ACE использовать. Для того же удаления файлов, например.
Для удаления файлов надо boost::filesystem расширить, это без вариантов, тут у них конкретная дыра
Здравствуйте, eao197, Вы писали:
D_>>И это не трёхэтажный код!!! E>Нет. Всего лишь двухэтажный. Особенно, если отформатировать нормально:
...skip...
Тогда и run-time код тоже форматируй и return-ы из середины убирай. А то так не очень то объективно получается. А объективно код compile-time примерно вдвое сложнее, но это синтаксису template надо говорить "спасибо". А если программировать более сложные алгоритмы то разница в сложности уменьшается. См. например, тест Миллера-Рабина. А священные войны форматирования оставим в покое.
Re[6]: Compile-time вычисления: а оно вообще надо?
jazzer wrote:
> E>Недавно здесь обсуждали boost::filesystem. Красивая, вроде вещь, а > на практике удобнее обертки над POSIX-овыми функциями из ACE > использовать. Для того же удаления файлов, например. > Для удаления файлов надо boost::filesystem расширить, это без > вариантов, тут у них конкретная дыра
Ага, и еще добавить нормальный i18n, а то у них до сих пор используются
ANSI-функции в версии для Windows. Вроде бы в следующем Бусте (в 1.34,
не в 1.33.1) обещают наконец-то нормально сделать.
--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 2.0 beta
Sapienti sat!
Re[8]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, Dmi_3, Вы писали:
D_>Здравствуйте, eao197, Вы писали:
E>>А можно подробнее? Для каких hash, random алгоритмов нужно, чтобы размер буфера был простым числом?
D_>Немогу привести полноценных примеров (они большие и принадлежат не мне а фирмам) поэтому ограничусь "тупым" генератором псевдослучайных чисел и "тупым" хэшем.
Хорошие примеры. Особенно с генератором псевдослучайных чисел. Смущает только то, что это программисту нужно самому искать простые числа. А STATIC_ASSERT его затем просто проверяет.
А вот пример с хэш-таблицей убедительным не выглядит. Хотя бы потому, что она не может динамически размер увеличивать.
Кстати, а в чем смысл идентификатора COND1T10N (с цифрами внутри)?
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[9]: Compile-time вычисления: а оно вообще надо?
От:
Аноним
Дата:
26.10.05 21:37
Оценка:
Здравствуйте, eao197, Вы писали:
E>Смущает только то, что это программисту нужно самому искать простые числа. А STATIC_ASSERT его затем просто проверяет.
//Можно и N-ное простое число вычислить но тут уже лимиты компилятора играют.
//Нет формулы а чисел больно много N/ln(N).template<int N>
struct prime{
enum{result=берём прошлое число и прибавляем двойку пока не получим простое};
};
E>А вот пример с хэш-таблицей убедительным не выглядит. Хотя бы потому, что она не может динамически размер увеличивать.
А частенько это и не нужно. А если нужно тогда только run-time провекки.
E>Кстати, а в чем смысл идентификатора COND1T10N (с цифрами внутри)?
Просто "прикол".
Re[10]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, <Аноним>, Вы писали:
E>>А вот пример с хэш-таблицей убедительным не выглядит. Хотя бы потому, что она не может динамически размер увеличивать.
А>А частенько это и не нужно. А если нужно тогда только run-time провекки.
Интересно, кстати. Никогда самому не приходилось хэш таблицы делать, решил проверить, как простые числа помогают в распределении ключей. Написал вот такой тестик:
Прогонял его на одном и том же log-файле с разными значениями capacity. Оказалось, что capacity, который является степенью двойки, дает наихудший результат (причем намного худший):
2049: 750
2053: 741 # Простое число.
2048: 1920
А на вчетверо больших значениях еще страшнее:
8192: 7680
8209: 3610 # Простое число.
8193: 3612
Хотя может быть этот пример и не показателен, может hash_pjw из ACE не самая оптимальная hash-функция для моего log-файла (для 8209 строк дает 6802 уникальных значения, а ведь в каждой строке есть уникальный timestamp, т.к. повторяющихся строк в нем практически нет)
Было бы круто, если бы при объявлении размерности hash_table я указал необходимую мне размерность, а реализация hash_table сама бы подобрала ближайшее сверху простое число.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
E>Интересно, кстати. Никогда самому не приходилось хэш таблицы делать, решил проверить, как простые числа помогают в распределении ключей. Написал вот такой тестик:
...>
E>Прогонял его на одном и том же log-файле с разными значениями capacity. Оказалось, что capacity, который является степенью двойки, дает наихудший результат (причем намного худший): E>
Предлагаю вернуться к приведенным результатам и обратить внимание вот на что. Простые числа показывают наилучший результат, но случайное, не простое число (2049 или 8193) так же показывают ну очень не плохие результаты (проигрыш 1.2% и 0.05% соответственно). Забавно, не правда ли?
Идем дальше. Допустим, что мне нужно работать с ~2000 значениями и мне нужен hash_table соответствующей размерности. Первое, что мне хочется сделать, это указать в качестве размерности 2000. И я буду не прав:
2000: 1875
2001: 743
2003: 729 # Простое число.
Но мне достаточно просто указать 2001 вместо 2000 и я получаю значительно более лучший результат. Даже простое число 2003 дает выигрыш 1.92% по сравнению с взятым с потолка значением 2001.
Еще интереснее картина получается, если мне нужен hash_table на 2500 значений:
2500: 1890
2501: 944
2503: 951 # Простое число.
Т.е. 2501 (не простое число) дает распределение лучше, чем простое число 2503! И значение 2501 совсем не нужно проверять на простоту.
Я это все к тому, что если мне попадает в руки hash_table, который требует указывать в качестве размерности простое число, то я должен это простое число откуда-то взять. Например, написать скрипт для его вычисления. Usabillity такого hash_table не высока
Либо, мне могут просто указать в документации -- нельзя использовать четные числа, а предпочтительнее всего -- простые числа (но это и не гарантирует наилучшего результата).
И все. Никакого навязчивого сервиса. Никаких сложных CT-вычислений. Указал пользователь четное значение -- сам дурак, еще не факт что простое число бы он правильно вычислил. И просто, и в общем случае эффективно, и usabillity не страдает.
А уж если захочется, то в STATIC_ASSERT можно элементарную проверку на четность размерности задать
Получается, что и здесь принцип KISS продолжает действовать
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[2]: Compile-time вычисления: а оно вообще надо?
DEA>А вот эта штука, как мне кажется, посерьезнее. DEA>Основная ее идея — генерация распознавателя регулярых выражений в compile-time. Короче, что-то вроде flex-а, но в терминах C++. DEA>Имхо — идея — просто блестящая. Expressive и рядом не стоял. Но, реализация, как всегда, оставляет желать. DEA>Автор обещал распознавание к конечным автоматам, но не свел...
А по мне, так и идея...
Где-то здесь мелькала утилитка по конвертации регулярных выражений в C-шный код. Вот это уже интереснее.
Да ты же сам на нее ссылку и давал: Re: regexp -> C++ function
eao197 wrote:
> А по мне, так и идея... > Где-то здесь мелькала утилитка по конвертации регулярных выражений в > C-шный код. Вот это уже интереснее. > Да ты же сам на нее ссылку и давал: Re: regexp -> C++ function > <http://rsdn.ru/forum/Message.aspx?mid=1353501&only=1>
Это не так удобно, особенно для простых парсеров. Тут рулит Spirit.
Например, мне нужно было распарсить файл вида:
Name: value
Name2: another value
Имена должны начинаться с буквы, символа '$' или '_', потом еще возможны
цифры. Значения могут содержать пробелы и всегда заканчиваются концом
строки. Вдобавок, файл записан в Unicode.
Вот код, который это делает:
typedef std::map<std::wstring,std::wstring> props; //Карта, в
которую будут складываться свойства
std::wstring name,value; //Текущие имя и значение
rule<wide_phrase_scanner_t> identifier_rule=lexeme_d[(alpha_p | L'_'
| L'$') >> *(alnum_p | L'_' | L'$')];
rule<wide_phrase_scanner_t>
value_rule=lexeme_d[*(anychar_p-L'\n'-L'\r')];
rule<wide_phrase_scanner_t> record_rule=
identifier_rule[assign_a(name)] >> ":" >>
value_rule[assign_a(value)];
rule<wide_phrase_scanner_t>
manifest_rule=+(record_rule[insert_at_a(props,cref(name),cref(value))]);
//Вызов парсера
parse_info<const wchar_t*> info=::parse(_manifest,
_manifest+_size,manifest_rule,space_p);
if (!info.hit || !info.full) //Проверка ошибокthrow
std::runtime_error(narrow_string_to_utf8(load_string(IDS_ERROR_MANIFEST)));
--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 2.0 beta
Sapienti sat!
Re[3]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, 0xDEADBEEF, Вы писали:
E>>Весело, но из области "а можно и так" DEA>А еще в комитете по стандартизации в 2003-м пробегала вот такая вот полусумасшедшая бумажка: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1471.pdf (читать про metacode)
Да, она здесь уже как-то обсуждалась.
DEA>Судя по тому, что больше ничего подобного не предлагается, ее похоронили. А жаль
Действительно жаль. Причем, даже на сайте самого Вандервуда о metacode с 2003 (или 2004) больше ничего не появлялось. Видимо, он и сам эту идею похоронил.
Тем не менее, все перечисленные в его презентации недостатки шаблонов остаются. И задалбывают по тихоньку.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[2]: Compile-time вычисления: а оно вообще надо?
Согласен с тем, что ты сказал выше.
E>В принципе недостатком системы с утилитами является то, что трудно писать проекты.
Ну, это сильно зависит от того, какой утилитой управления компиляцией пользуешься
Вот когда у вас появился подходящий инструмент, все оказалось не так уж и сложно.
E>Таким образом вместо того, чтобы заставлять компилятор строить "ненужные" в окончательном коде инстанциации шаблонов, мы заставляем строить "ненужные" утилиты и включаем в окончательный код не их текст, а результат их работы.
+1
Только вот если вместо утилит на C++ использовать скриптовые языки (Perl, Python, Ruby), да еще с возможностью интеграции в систему управления компиляцией, то все еще больше упрощается.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[3]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, eao197, Вы писали:
E>Только вот если вместо утилит на C++ использовать скриптовые языки (Perl, Python, Ruby), да еще с возможностью интеграции в систему управления компиляцией, то все еще больше упрощается.
Скорее всего оба подхода возможны, но у подхода со скриптовыми языками есть два недостатка (на мой взгляд)
1) Надо уметьпрограммировать на обоих языках. При этом некоторые утилиты решают очень даже сложные вычислительные задачи. То есть надо ещё и оптимизироровать уметь.
2)Если всё на C++, то таки можно разделятьи переиспользовать код
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, Erop, Вы писали:
E>>Только вот если вместо утилит на C++ использовать скриптовые языки (Perl, Python, Ruby), да еще с возможностью интеграции в систему управления компиляцией, то все еще больше упрощается.
E>Скорее всего оба подхода возможны, но у подхода со скриптовыми языками есть два недостатка (на мой взгляд)
E>1) Надо уметьпрограммировать на обоих языках. При этом некоторые утилиты решают очень даже сложные вычислительные задачи. То есть надо ещё и оптимизироровать уметь. E>2)Если всё на C++, то таки можно разделятьи переиспользовать код
+1
Только эти недостатки легко превратить в достоинства
А программировать, кроме C++, еще на Python, Ruby или, скажем, Smalltalk -- это не только интересно, но и полезно. (См., например, Re[2]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, Erop, Вы писали:
E>В принципе недостатком системы с утилитами является то, что трудно писать проекты. Поэтому написали некий тул, который умеет удобно это всё дело встраивать в процесс компиляции. Технически это выглядит, как написанный на шеле интерпретатор билдовых файлов особого вида. В целом всё не так уж сложно, и главное, что у билдовых файлов довольно простой синтаксис. Ну и поэтому поддерживать это всё дело намного проще, чем код CT-вычислений.
E>В целом билд выглядит так: E>Этот самый интерпритатор смотрит что там ещё не построенно или нуждается в перестройке или ещё чего и строит утилиты, потом запускает их, потом строит сам проект, или другие утилиты и т. д.
E>Таким образом вместо того, чтобы заставлять компилятор строить "ненужные" в окончательном коде инстанциации шаблонов, мы заставляем строить "ненужные" утилиты и включаем в окончательный код не их текст, а результат их работы.
У меня используется похожий механизм. Вот, например, в ObjESSty
Но фокус в том, что для построения из ddl-файла C++ кода должна быть запущена утилита oess_cpp_serializer, которую предварительно нужно скомпилировать. Но заботится об это не нужно. Строка:
автоматически добавляет к текущему проекту несколько зависимостей. Среди этих зависимостей есть и утилита-генератор. В результате, когда моя систему компиляции проектов Mxx_ru начинает компиляцию проекта some_project.rb, она проверяет наличие всех зависимостей, в том числе и утилиты oess_cpp_serializer. Если утилита oess_cpp_serializer отсутствует или устарела, то она компилируется. После чего она может использоваться для генерации C++ кода из some_file.ddl. Причем, если сама oess_cpp_serializer нуждается в каких-то библиотеках, то эти библиотеки так же неявно становятся зависимостями some_project.rb и их состояние так же контролируется Mxx_ru при построении some_project.rb. При этом программисту нужно всего лишь указать, что он хочет обработать файл some_file.ddl каким-то инструментом, прячущимся за классом Oess_1::Util_cpp_serializer::Gen.
— используем стороннюю утилиту для генерации распознавателя (flex, re2c, lemon, antlr и проч)
за: (1)не требуется интерпретации выражения в run-time против: (1)во время билда требуется утилита-генератор и (возможно) сопровождающие ее библиотеки (2)требуется модификация проекта чтобы утилита вовремя вызывалась.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>>Было бы круто, если бы при объявлении размерности hash_table я указал необходимую мне размерность, а реализация hash_table сама бы подобрала ближайшее сверху простое число.
Ответ:
//Вычислим ближайщее к N простое число не меньшее N.template<unsigned int N>
class get_near_prime_number{
template<unsigned int K>
struct ask{
enum{
tmp=is_prime<K>::result,
answer=tmp?K:ask<(K+2u)*!tmp>::answer
};
};
template<>struct ask<0u>{enum{answer=0u};};
public:
enum{result=ask<N|1u>::answer};
};
Простота — 13 строк написанные за 2 минуты.
эффективность — абсолютная (это же CT)
usabillity — get_near_prime_number<12345>::result
И это при том, что взятое с потолка нечетное число дает эффективность, лишь на один-два процента уступающую простым числам. А иногда на такую же величину большую эффективность.
А если нет разницы, зачем же платить больше?
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Приношу свои извинения, если мое обращение на "ты" (которое является вполне легальным на данном форуме) оскорбило вас. Я здесь со всеми на ты, и даже если ко мне обращаются на "вы", то сразу предлагаю перейти на "ты", т.к. это гораздо более удобно.
D_>Вы правы. Если хэш-функция выдаёт мало разных значений, то ничто не поможет. А о том, что же показывает именно эта оценка см. ниже. D_>Далее. (//комментарии мои)
Прогонял его на одном и том же log-файле с разными значениями capacity. Оказалось, что capacity, который является степенью двойки, дает наихудший результат (причем намного худший):
2049: 750
2053: 741 # Простое число.
2048: 1920
А на вчетверо больших значениях еще страшнее:
8192: 7680
8209: 3610 # Простое число.
8193: 3612
а так же на код программы, которую я приводил в том же письме. Я считываю из входного потока capacity элементов. Поэтому в первой последовательности я считывал 2049, 2053 и 2048 не пустых строк. Затем решил проверить ситуацию на вчетверо больших объемах. Отсюда и вторая последовательность: 8192, 8209 и 8193 строки соответственно. Видя такое плохое распределение для capacity, которое является степенью двойки, я решил проверить, насколько хорошие хэши генерирует функция hash_pjw из ACE. Чуть модифицировал программу и получил результат 6802 для 8209 строк. Но далее вы продолжаете считать, что в моих тестах всегда присутствуют 8209 строк. Это не так. Посмотрите еще раз на тексты моих программ здесь
и вы увидете, что capacity как раз и есть количество прочитанных строк.
Поэтому я и считаю, что если хэш функция выбрана удачно и у capacity хорошее значение, то количество пустых элементов в таблице должно стремиться к нулю. Т.к. размер таблицы достаточен для сохранения всех прочитанных значений. Но, если для наиболее равномерного заполнения хэш-таблицы требуется вчетверо больше данных, чем размер таблицы, то может быть об этом можно было просто сказать? Раз уж для вас настолько очевидна моя некомпетентность в данном вопросе. Я ведь здесь не один такой, несведующий. Вместо упражнений в острословии устроили бы здесь маленький ликбез -- глядишь, некомпетенции бы вокруг поубавилось.
D_>Эти данные убедительно показывают, что предложенная Вами проверка на нечётность размера хэш-буфера почти ничего не даёт. Да ещё и реализована с ошибкой.
Напомню, что я предлагал делать такой STATIC_ASSERT только если очень захочется.
D_>Должно быть не STATIC_ASSERT( ( size & 2 ) == 0 ); D_>а STATIC_ASSERT( ( size & 1 ) != 0 ); D_>или STATIC_ASSERT( ( size % 2 ) != 0 );
Да, здесь я ошибся -- вот, что значит приводить код, который никогда не компилировался и не тестировался.
D_>Например, (stupid по Вашему мнению) Юрий Жмеренецкий.
В общем, уважаемые коллеги по C++ цеху, давайте не будем stupid, и будет пытаться "Keep it simple"
Прошу так же принять во внимание, что я говорил во множественном числе, обращась ко всем коллегам по C++ (имея при этом в виду и себя). А так же наличие смайлика и знака
Попросту говоря, здесь ничего не было обращено персонально к Юрию. А все сказанное, к тому же, имело очень сильный юмористический оттенок.
А вот вас я попрошу либо привести точную цитату того, что по моему мнению к Юрию относится термин stupid. Либо публично забрать свои слова обратно.
E_>> Не вижу никаких преимуществ от выбора простых чисел для ограничения размерности. D_>То есть лично Вы всегда можете найти великолепную хэш-функцию? D_>Поздравляю! Обычно мне и моим коллегам это не удаётся. Но постойте… Как же это соотнести с ранее высказанным Вами: E_>> Какая была, такую и использовал. Не всегда есть время изучать Кнута и выбирать оптимальную хэш-функцию, приходится брать то, что есть. E_>> Кроме-то на этих данных лога выпадает такое распределение. Со временем характер данных в логе может поменяться. D_>Неувязочка получается.
Никакой неувязочки. Я не специалист в хэшировании, поэтому если мне по каким-то причинам потребуется воспользоваться хэш-функция, то я вряд ли буду осваивать Кнута или другую научную литературу. А воспользуюсь какой-либо готовой реализаций. Из ACE, Ruby или Berkeley DB, т.к. надеюсь, что их разработчики понимают в этом деле больше меня. Что я и попробовал сделать. И, как ни странно, получил результаты, которые ожидал.
E_>> Главное -- это качество хэш функции. D_>Так я же говорил: D_>> ОЧЕНЬ ответственно относитесь к выбору хэш-функций, исследуя типичные данные для Вашего случая. Хеширование идентификаторов и путей к файлам – две большие разницы.
Ну в этом мы не противоречим друг другу. Расхождения начинаются в том, что я считают навороты вокруг простых чисел в этом случае уже излишними. А вы -- нет. Что по-моему и является излишним переусложнением.
D_>> Если какое-то требование к использованию кода можно выразить явно в программе – выразите. Это будет дополнительной гарантией. Разве все внимательно читают документацию? E_>> Что выразить? Что пользователь твоего кода должен искать сам простые числа? D_>Если задача этого требует то да (cм. RSA-криптосистема с открытыми ключами).
По-вашему, простые числа (для 2048-битовых или 4096-битовых ключей) можно искать в compile-time?
D_>Но Вы опять не поняли. Я для того и завёл массив capacity, что-бы пользователи могли поменьше заботиться и об этом и о чрезмерном использовании памяти и о идеальной функции хеширования. Ведь у них есть свои проблемы и негоже заставлять изучать всех тонкости организации хэшей. А требованием к коду в данном случае являются размеры буферов возрастающие примерно в «золотой» пропорции(в частности для экономии памяти) и являющиеся простыми числами(для снижения требований к качеству хэш-функции). Если бы я просто задал их числами то во время сопровождения программы мой коллега из добрых побуждений не поняв(как Вы) почему они именно такие изменил бы их например на степени двойки.
А с чего бы ему это потребовалось бы делать? Если приложение работает нормально, то зачем его менять? А если работает не правильно, то зачем эти навороты с числами Фибоначчи и ближайшими к ним значениями?
D_> И при изменении структуры и\или вероятностей распределения ключей его алгоритм превратился бы из O(1) в O(N) а его realtime 24x7 приложение «упало»\«зависло» бы не успев обработать socket. А если вы про пример «тупого» хэша говорите, то прочтите комментарий к нему. D_>// Не ругайтесь. Это только пример.
Ok. Пример, так пример.
D_>>Того, кому не понятно, что это массив простых чисел ближайших к последовательным числам Фибоначчи можно безболезненно увольнять. E_>> Значит меня бы уволили. D_>Наверно да. Правда в реальности там ещё русский комментарий стоял, на случай если кто плохо знает английский. Но даже комментарий не поможет, если человек не знает таких «академических» понятий как «инкапсуляция» и «абстрагирование», если ему не достаточно интерфейса
Отличный пример иронии, не достигшей своей цели. В баталиях с таким одиозным персонажем RSDN, как VladD2, я уже столько услышал в свой адрес, что меня на форумах RSDN сложно вывести из себя или хотя бы уколоть подобными выпадами.
Так вот, я прекрасно понял, что это последовательность ближайших к числам Фибоначчи простых чисел. Только меня бы уволили за то, что я не понимаю, зачем все это нужно.
D_>И учитесь абстрагироваться.
Ok. Форумы RSDN как раз очень хороши тем, что здесь есто чему научиться. И я, тот год, что участвую на RSDN многому научился.
Вам же могу посоветовать больше внимания оформлению своего кода. Его очень тяжело читать.
D_>> 59,89,149,233,379,613,991,1597,2591,4201,6779,10949,17713,28657,46381,75029,121403,196429,317827,514229,832063,1346273,2178313,3524603,5702897 E_>> мне бы самом понять, что это такое. D_>Это размеры хэш-буферов которые автоматически выбираются при создании и\или рехешировании. Именно эти числа находятся в массиве capacity и получаются из выражений near_prime<fibonachchi<N>::result>::result
Да, одним из моих предположений являлось то, что это результат работы вашего кода. Но вы не говорили, что студентам нужно показывать и предшествующий код. Речь шла о предоставлении студентам последовательности чисел. Я думаю, что студента, который взглянув на последовательность сказал бы, что это ближайшие к числам Фибоначчи простые числа, мне бы вряд ли было чему научить.
E_>>А от своих студентов я больше требую, чтобы они писали простой, аккуратно оформленный и задокументированный код. Этому, поверь, научится гораздо сложнее, чем решению задач на сообразительность. Особенно, когда срок реализации проекта -- вчера. D_>Простите, но я сомневаюсь, что самое время этому учиться, когда пропущены сроки реализации проекта. Хотя если проект «завален» то есть время и подучиться.
А кто сказал про пропущенность сроков или завал проекта? Имхо, выражение "срок сдачи -- вчера" является вполне устоявшимся выражением, которое означает, что на реализацию проекта отведен слишком малый срок. В Москве такие проекты сплошь и рядом, если вообще не 100%.
D_> Вот только наряду с обучением грамотному использованию синтаксиса C++ хорошо бы учить и базовым принципам преодоления сложности построения программ.
Например, отказ от использования в коде неоправдано сложных конструкций.
D_>P.S. (offtopic) D_>После всего выше приведенного, совет «…вообще забей на хэширование, если ничего в нем не понимаешь.» я скорее буду относить к Вам а не к себе.
А этот совет ко мне и относился.
D_> Хотя мне трудно представить разработчика компиляторов пусть даже скриптовых языков не использующего hash и слабо разбирающегося в рекурсии. Как Вы ассоциируете атрибуты с именем идентификатора без hash? Ищете в неупорядоченном списке? Как разбираете БНФ или просто выражения со скобками без рекурсии? Ручками стеки заводите?
Ой, а откуда следовало, что я плохо разбираюсь в рекурсии?
БНФ я не разбирал сам. Это вместо меня yacc делал. А еще я реализовал (4fun, как говорил Юрий Жмеренецкий) собственный аналог yacc, но в виде LR(1) парсера на основании "правил подстановки Флойда", которые нам отчитали в свое время во время обучения.
А идентификаторы я храню в обычном map-е. Может не так эффективно, как в hash, но и проблем с производительностью не было.
D_> И уж совсем невозможно представить 7x24 приложение отказоустойчивость которого базируется на: E_>> Указал пользователь четное значение -- сам дурак
Очень, кстати, удобно. Делать систему, которая эффективно ведет себя при правильном использовании. А при неправильном -- сразу падает, но не пытается самостоятельно "выровнять" ситуацию.
D_>То, что сделал Юрий Жмеренецкий вызывает если не восхищение то глубокое уважение. А Вы (см. «Собачье сердце») позволяете себе давать советы Космического масштаба и Космической же глупости. Вот это уже можете считать моей оценкой.
. Я и завел отдельную тему чтобы определить границы полезности использования сложных шаблонных конструкций в реальных проектах (которые будут развиваться не год, не два, и которые будут сопровождаться программистами с разным опытом, квалификацией, энтузиазмом и мотивацией), чтобы не бросать тень или как-то порочить работу Юрия. В крайнем случае модераторы просто вынесут эту тему в Священные воины, а топик Юрия все равно останется здесь.
D_>Впрочем я сам виноват не надо было связываться с таким человеком: D_>Цитата из Вашей домашней странички: D_> D_>... Иностранными языками не владею, на русском пишу с ошибками. Сам себя могу охарактеризовать как системного программиста-камикадзе и патологического изобретателя велосипедов. Системного -- потому, что систематически умудряюсь встревать в безнадежные проекты (фактически все проекты, в которых я участвовал, можно назвать безнадежными). А изобретатель велосипедов -- потому, что меня хлебом не корми, дай что-нибудь свое придумать. Но это уже на генетическом уровне и не лечится. D_> D_>Конец цитаты. D_>Мне добавить нечего!
Кстати спасибо, что так хорошо меня прорекламировали. Жаль только, что ссылку на мою страничку about не привели
Замечательно сказано в Законах Паркинсона:
Если же подумать, увидишь, что идеальное объявление привлечет одного
человека, и того именно, кто нужен. Начнем с предельного случая:
"Требуется акробат, который может пройти по проволоке на высоте 200 м
над бушующим пламенем. Ходить придется дважды в день, по субботам —
трижды. Плата — 25 фунтов в неделю. Ни пенсии, ни компенсации за увечье не
будет. Явиться лично в цирк "Дикий Кот" от 9 до 10".
Может как раз кто-то такого патологического изобретателя велосипедов и разыскивает
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
D_>А эту последовательность далеко не каждый сумеет понять. Можете дать своим студентам в качестве упражнения на сообразительность. D_>59,89,149,233,379,613,991,1597,2591,4201,6779,10949,17713,28657,46381,75029,121403,196429,317827,514229,832063,1346273,2178313,3524603,5702897
Если приведенный выше фрагмент в конце-концов сводится к указанной последовательности чисел, то почему нельзя было записать так:
И что будет с вашим кодом на 64-х битовой платформе, где емкость контейнера в 6 миллионов экземляров -- это мелочь (да и на 32-х битовой платформе это не будет проблемой)?
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Dmi_3, Вы писали:
D_>Конечно, написать было можно. Но это только часть последовательности. D_>near_prime<fibbonachchi<46>::result>::result == 1836311951 D_>near_prime<fibbonachchi<47>::result>::result == 2971215073 D_>И, допустим, что я в 20-том числе допустил ошибку. Это легко, памятуя о двух "опечатках" D_>в исчезнувшем STATIC_ASSERT((size&2)==0); D_>Контр-вопрос: Сколько времени Вы проведёте в отладчике, прежде чем найдёте несоответствие комментария D_>и действительности учитывая, что на маленьких тестовых примерах всё OK да и на больших всё работает D_>но сильно тормозит?
Не согласен. Если вы последовательность значений для чисел Фибоначчи вводили вручную, то могли написать так:
А для вставки числовой последовательности в код совсем не нужно делать кодогенератор. Достаточно один раз сделать скрипт или простую программу на С++ для генерации последовательности и:
— либо скопипастить результат ее работы в текст программы;
— либо подключить результат ее работы через #include.
Все.
E>>И что будет с вашим кодом на 64-х битовой платформе, где емкость контейнера в 6 миллионов экземляров -- это мелочь (да и на 32-х битовой платформе это не будет проблемой)? D_>Кажется я уже нечаянно ответил.
Нет, я имею в виду, что ваш код придется явно портировать на 64-х битовую платформу, т.к. придется расширять исходную последовательность новыми значениями. А если бы в хеш-контейне применялось простое удвоение объема буфера без предварительно вычисленных размеров, то код легко бы портировался с 16-ти битовой на 32-х битовую, на 64-х битовую и на любую другую платформу.
Немного в оффтопик: если вам интересно какое-то решение потому, что оно повысило ваш уровень знания C++, то это еще не повод использовать данное решение в промышленном коде. Занятие самообразованием за счет заказчика -- это довольно опасная затея, хотя и заманчивая.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
E>Занятие самообразованием за счет заказчика -- это довольно опасная затея, хотя и заманчивая.
Занятия самообразованием за счёт заказчика в данном конкретном случае — действительно очень-очень опасная затея.
Здравствуйте, Dmi_3, Вы писали:
D_>Извинения принимаются. Проехали?
Проехали. Если желаете, будем общаться на вы. Только не обижайтесь, если по прошествии некоторого времени на какой-либо другой ваш пост я отвечу на "ты", т.к. могу забыть об этой условности.
E>>А вот вас я попрошу либо привести точную цитату того, что по моему мнению к Юрию относится термин stupid. Либо публично забрать свои слова обратно. D_>После загадочного исчезновения Вашей ошибки со STATIC_ASSERT((size&2)==0); D_>Я считаю странной эту просьбу. D_>1. Эти слова могли оказаться там же где и ASSERT D_>2. Вы сами можете их убрать а заодно добавить мои "восхищённые" восклицания по поводу модерирования. D_>3. Предлагаю ввести электронные подписи сообщений во избежание подобных инцидентов.
В данной ветке пока следов модерирования я не заметил, все сообщения остались на своих местах. В частности, ошибка со STATIC_ASSERT находится здесь: Re[13]: Простота, эффективность и usabillity
. Поэтому упрекая меня в негативном отношении к коллегам, вы делаете тоже самое по отношению к модераторам. Не красиво, однако.
E>>По-вашему, простые числа (для 2048-битовых или 4096-битовых ключей) можно искать в compile-time? D_>Нет. Но я этого и не говорил.
Тем более, ведь для генерации RSA ключей пользователи не ищут сами необходимые для этого простые числа. Я думаю, что многие, кто генерирует для себя запросы на подпись SSL-сертификата (получая таким образом открытый и закрытый ключи) или даже самоподписанный SSL-сертификат, даже не представляют себе деталей RSA-алгоритма и сколько и каких простых чисел в этот момент генерируется. Поэтому привлечение RSA в качестве примера того, где пользователю нужно самому искать простые числа, мне кажется не удачным.
E>>А с чего бы ему это потребовалось менять числа если приложение работает нормально? D_>Иногда может попасться хэш-функция D_>
D_>unsigned long
D_>hash_fun( const char * p, std::size_t len ){
D_> unsigned long key = 0;
D_> while (len--) {
D_> enum{mul=89};
D_> STATIC_ASSERT(is_prime<mul>::result);//Это иногда делает hash_fun хорошей.
D_> key = key*mul + *p;
D_> p++;
D_> }
D_> key = key + (key>>5);
D_> return key;
D_>}
D_>
D_>где mul совпадёт с текущим размером hash. Последствия могут быть плачевны. D_>Пользователь, обнаружив это, решит переиначить «магические» числа размеров буферов.
Знаете, Dmi_3, у меня сложилось впечатление, что слаборазбирающийся в вопросах хеширования человек (вроде меня), никогда не поймет, что эпизодические падения производительности будут связаны с тем, что текущий размер хеш-таблицы совпадает со значением mul в hash_fun. К тому же, насколько я могу судить, простого совпадения все равно не достаточно. Для этого еще нужно специальное значение в *p. Так что, человек, который сможет продиагностировать подобные проблемы, сможет подобрать подходящее значение для mul. И не факт, что это значение должно будет быть простым.
E>>Ой, а откуда следовало, что я плохо разбираюсь в рекурсии? D_>Приведённые мною template ну очень похожи на рекурсивные функции runtime. D_>Если их легко понять то и template легко.
Ну не скажите, обычная рекурсия в run-time и рекурсия определения шаблонов -- это две довольно большие разницы.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Dmi_3, Вы писали:
E>>Вам же могу посоветовать больше внимания оформлению своего кода. Его очень тяжело читать. D_>С этого места поподробней please.
Ничего не понимаю. Если hash-функция подобрана нормально, то ей пофиг по модулю чего ее брать. Если на каких-то она модулях сбоит, значит писавшему её надо кое-что оторвать.
Правильно работающая программа — просто частный случай Undefined Behavior
Re[3]: Compile-time вычисления: а оно вообще надо?
E>Вот это я понимаю, вот это метапрограммирование! E>На шаблонах еще попробовать это сделать нужно
E>А вот на Ruby, как мне представляется, реализация будет не столь сложной....
.
У меня наконец дошли руки причесать эти исходники и выложить на всеобщее обозрение. Именно об этих исходниках также шла речь в небезызвестной тебе ветке Что толку в Ада если Ариан 5 все равно упал
. С Арианом-то дело уже прошлое, но я смею надеяться, что использование моего кода (с compile time вычислениями) не позволит упасть многим другим программам.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[2]: Compile-time вычисления: а оно вообще надо?
Интересно, Дмитрий. Вот за что мне нравится C++, так это за возможность сотворить что-нибудь такое-эдакое:
// Сила
si::force f1(10); // 10 Н
cgs::force f2 = f1*2; // 10 Н * 2 = 2000000 дин
si::force f3 = m1*l2/(t1*t1); // 1 г * 1 м / (1 с * 1 с) = 0.001 Н
Я в свое время так и не смог на Java программировать из-за того, что там этого хоть убейся, а не сделаешь.
C++ forever!
Тем не менее, я думаю, что как раз compile-time там не так уж и много. Имхо, это практически обобщенное и метапрограммирование в чистом виде. Хотя строгую классификацию я бы не стал делать.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[3]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, eao197, Вы писали:
E>Я в свое время так и не смог на Java программировать из-за того, что там этого хоть убейся, а не сделаешь.
Аналогично.
E>C++ forever!
+1
E>Тем не менее, я думаю, что как раз compile-time там не так уж и много. Имхо, это практически обобщенное и метапрограммирование в чистом виде. Хотя строгую классификацию я бы не стал делать.
Как раз compile-time там довольно много, просто не торчит наружу. Вся система выведения коэффициентов, новых типов и т.д. основана на boost::mpl, а уж boost::mpl — это просто квинтэссенция compile time вычислений. А вот если туда еще и CT итерирование прикрутить...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, Erop, Вы писали:
E>Ну, не смотря на узкую область применения, классная машинка. Мало того, прикаольно реализовано, ну и вообще хорошо довольно всё сделано. В конце концов идея приписывать размерность через тип переменной и поиск преобразования (Если оно есть) или детектирование того факта, что преобразования нет вещь в принципе верная
E>Но вот зачем коэффициент в преобразовании вычислять CT я не понимаю. В конце концов его же можно кэшировать. Что за выгоду ловим-то?: )
Самая главная причина — посмотреть, а вот можно ли? Оказалось, можно. Мелочь, а приятно.
[skip]
E>Таки лучше бы всю мощь шаблонов направить на расширяемость и редактируемость, а не на CT. Ну а вычислять коэффициенты и сдвиги можно и RT всё-таки кажедый коэффициент нужно вычислять один раз, и не так уж их и много вообще.
), то увидишь, что я над этим как раз сейчас думаю. Ничего страшного нет, сделаю CT итерирование — можно будет наворачивать любые базовые единицы. В том числе очарованность.
Просто подожди немного.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[4]: Compile-time вычисления: а оно вообще надо?
), то увидишь, что я над этим как раз сейчас думаю. Ничего страшного нет, сделаю CT итерирование — можно будет наворачивать любые базовые единицы. В том числе очарованность. CX>Просто подожди немного.
Я уже прочитал.
Я не про то пишу, что совсем совсем не удастся реализовать это всё. Я про то, что трудно будет воспользоваться, если запрос немного нестандартный. Не в последнюю очередь и из-за CT
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Compile-time вычисления: а оно вообще надо?
), то увидишь, что я над этим как раз сейчас думаю. Ничего страшного нет, сделаю CT итерирование — можно будет наворачивать любые базовые единицы. В том числе очарованность. CX>>Просто подожди немного.
E>Я уже прочитал. E>Я не про то пишу, что совсем совсем не удастся реализовать это всё. Я про то, что трудно будет воспользоваться, если запрос немного нестандартный. Не в последнюю очередь и из-за CT
Ну значит, прочитав, все-таки не понял. Конечная цель — чтобы воспользоваться было легко. Именно к этому я и стремлюсь. Поэтому подожди следующей версии, там уже многое будет проще. Выложил же эту версию я для того только чтоб отзывы собрать и, возможно, баги отыскать (если они есть ).
Я хочу сделать некую универсальную библиотеку для работы с любыми размерностями. Физические величины — это просто самый наглядный пример, не более того.
Удобство использования — один из важнейших критериев. Если есть что по этому поводу сказать — жду с нетерпением.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[5]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, eao197, Вы писали:
E>Вообще-то, что-то в словах Erop есть... E>Я бы так сказал по поводу твоего кода, Дмитрий: программировать на C++ было бы куда приятнее, если бы для реализации этой задачи достаточно было бы написать в два раза меньше кода. E>Но, к сожалению, процесс развития C++ идет не так быстро как хотелось бы. Поэтому сейчас и кажется, что подобные решения вполне удовлетворительны. А если бы нам дали в руки более удобный инструмент для метапрограммирования, то мы бы сами ужаснулись, насколько сложно все было в прошлом. Только вот что это за инструмент должен быть -- я не знаю.
Ну помечтать-то я и сам люблю. Вот только мой код позволяет в чем-то к этим мечтам приблизиться. Это ли не плюс?
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[6]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, CrystaX, Вы писали:
CX>Ну помечтать-то я и сам люблю. Вот только мой код позволяет в чем-то к этим мечтам приблизиться. Это ли не плюс?
Я тебе сейчас ересь скажу (для форума по C++). Лично меня с возрастом лень одолевает. Так уж оказалось, что я написал много библиотечного кода, большая часть из которого до сих пор в эксплуатации находится. Поэтому приходится его сопровождать. А для этого, время от времени, в собственный код заглядывать приходится. И оказывается, что проще всего сопровождению поддается максимально тупой и простой код (чуть ли не в индуском стиле). А вот всякие элегантные и красивые решения со временем, почему-то, свою красоту утрачивают. Иногда смотришь в свой код и думаешь, а зачем здесь вообще этот параметр шаблона потребовался? Или зачем я еще вот это исключение придумал.
Здесь-то и оказывается, что разобраться с кодом, который выполняется в compile-time (это не обязательно шаблоны, то же самое и со сложными макросами происходит) не просто. Нужно настроится на "ту же волну", что была в момент написания. И если для своего кода это еще возможно, то вот для чужого -- совсем не просто. И вот если от этой сложности избавиться еще на этапе написания кода, то это вообще здорово. Но это так, ворчание...
Что же касается конкретно твоего решения, то несомненный его плюс в том, что оно позволяет достичь "семантической корректности". Причем без run-time overhead, что для предполагаемой области применения (научные числодробилки) опросто офигительный плюс. Ну а дальше все будет зависеть от вектора развития C++. Если Boost.MPL станет в C++ мейнстримом и большинство C++ программистов будут им без проблем владеть, то и с сопровождением и развитием твоего кода мало у кого возникнут проблемы. Только не хотелось бы, чтобы Boost.MPL стал мейнстримом из-за оттока из C++ тех, кому лень со сложностью C++ разбираться (все же, чем больше C++ программистов, тем больше инструментов/библиотек/книг/документации, да и просто новых идей).
Я вот как раз эту тему затеял, чтобы как-то определить круг задач, где CT-вычисления -- явное добро, а где, напротив, явное зло. Чтобы черезмерные CT-навороты не отпугивали людей (в том числе и меня) от C++. А разумные примеры использования CT-вычислений как раз способствовали привлечению внимания к C++. Твой пример, имхо, -- это положительный пример (хотя сопровождать его я бы не взялся ? математической подготовки не хватит ).
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[7]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, eao197, Вы писали:
CX>>Ну помечтать-то я и сам люблю. Вот только мой код позволяет в чем-то к этим мечтам приблизиться. Это ли не плюс?
E>Я тебе сейчас ересь скажу (для форума по C++). Лично меня с возрастом лень одолевает. Так уж оказалось, что я написал много библиотечного кода, большая часть из которого до сих пор в эксплуатации находится. Поэтому приходится его сопровождать. А для этого, время от времени, в собственный код заглядывать приходится. И оказывается, что проще всего сопровождению поддается максимально тупой и простой код (чуть ли не в индуском стиле). А вот всякие элегантные и красивые решения со временем, почему-то, свою красоту утрачивают. Иногда смотришь в свой код и думаешь, а зачем здесь вообще этот параметр шаблона потребовался? Или зачем я еще вот это исключение придумал.
E>Здесь-то и оказывается, что разобраться с кодом, который выполняется в compile-time (это не обязательно шаблоны, то же самое и со сложными макросами происходит) не просто. Нужно настроится на "ту же волну", что была в момент написания. И если для своего кода это еще возможно, то вот для чужого -- совсем не просто. И вот если от этой сложности избавиться еще на этапе написания кода, то это вообще здорово. Но это так, ворчание...
А уж я то насколько ленив! Веришь — все эти шаблонные навороты, они как раз из-за лени. Ну лень мне педалить почти один и тот же код много раз, натыкаясь на одни и те же ошибки.
E>Что же касается конкретно твоего решения, то несомненный его плюс в том, что оно позволяет достичь "семантической корректности". Причем без run-time overhead, что для предполагаемой области применения (научные числодробилки) опросто офигительный плюс. Ну а дальше все будет зависеть от вектора развития C++. Если Boost.MPL станет в C++ мейнстримом и большинство C++ программистов будут им без проблем владеть, то и с сопровождением и развитием твоего кода мало у кого возникнут проблемы. Только не хотелось бы, чтобы Boost.MPL стал мейнстримом из-за оттока из C++ тех, кому лень со сложностью C++ разбираться (все же, чем больше C++ программистов, тем больше инструментов/библиотек/книг/документации, да и просто новых идей).
Время покажет.
E>Я вот как раз эту тему затеял, чтобы как-то определить круг задач, где CT-вычисления -- явное добро, а где, напротив, явное зло. Чтобы черезмерные CT-навороты не отпугивали людей (в том числе и меня) от C++. А разумные примеры использования CT-вычислений как раз способствовали привлечению внимания к C++. Твой пример, имхо, -- это положительный пример (хотя сопровождать его я бы не взялся ? математической подготовки не хватит ).
Да ладно, брось. Разобрался бы немного и прекрасно сопровождал бы. Но я тебя не обязываю, так что не пугайся.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[8]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, CrystaX, Вы писали:
CX>А уж я то насколько ленив! Веришь — все эти шаблонные навороты, они как раз из-за лени. Ну лень мне педалить почти один и тот же код много раз, натыкаясь на одни и те же ошибки.
Так ведь все велосипеды от лени появляются Мне когда-то было лень запоминать обозначения в make-правилах (всякие $@, $<, $> ), теперь у меня свой инструмент для управления компиляцией .
А настоящая лень наступает, когда от использования велосипеда уже кайфа нет, когда это использование становиться рутиной, а сопровождать нужно...
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[6]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, CrystaX, Вы писали:
CX>Ну значит, прочитав, все-таки не понял. Конечная цель — чтобы воспользоваться было легко. Именно к этому я и стремлюсь. Поэтому подожди следующей версии, там уже многое будет проще. Выложил же эту версию я для того только чтоб отзывы собрать и, возможно, баги отыскать (если они есть ).
CX>Я хочу сделать некую универсальную библиотеку для работы с любыми размерностями. Физические величины — это просто самый наглядный пример, не более того. CX>Удобство использования — один из важнейших критериев. Если есть что по этому поводу сказать — жду с нетерпением.
Ну не все размерности связанны так уж удобно. В конце концов вот вырази в своей машинке переход от СГСэ к секундам граммам и сантиметрам.
Потом совершенно неправильно тип размерности задавать позицией в некотором векторе. Так как тогда я заведу в двух местах в программе два новые типа размерностей и привет, всё запутается
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: Compile-time вычисления: а оно вообще надо?
E>Так ведь все велосипеды от лени появляются Мне когда-то было лень запоминать обозначения в make-правилах (всякие $@, $<, $> ), теперь у меня свой инструмент для управления компиляцией .
О-о-о-о-о-о Auto2lz — это Ваша разработка
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[10]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, srggal, Вы писали:
E>>Так ведь все велосипеды от лени появляются Мне когда-то было лень запоминать обозначения в make-правилах (всякие $@, $<, $> ), теперь у меня свой инструмент для управления компиляцией .
S>О-о-о-о-о-о Auto2lz — это Ваша разработка
Нет, ты меня с кем-то путаешь. Моя разработка -- это Mxx_ru. Лично мне нравиться.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[7]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, Erop, Вы писали:
CX>>Я хочу сделать некую универсальную библиотеку для работы с любыми размерностями. Физические величины — это просто самый наглядный пример, не более того. CX>>Удобство использования — один из важнейших критериев. Если есть что по этому поводу сказать — жду с нетерпением.
E>Ну не все размерности связанны так уж удобно. В конце концов вот вырази в своей машинке переход от СГСэ к секундам граммам и сантиметрам.
Электрические величины не могут быть выражены только в секундах, граммах и сантиметрах по определению. Они выражаются через длину, массу, время и силу тока, что у меня есть.
Посмотри на cgs::charge, cgs::voltage, cgs::resistance и т.д.
E>Потом совершенно неправильно тип размерности задавать позицией в некотором векторе. Так как тогда я заведу в двух местах в программе два новые типа размерностей и привет, всё запутается
Я уже об этом думал. Сразу как додумаю — представлю решение.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[8]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, CrystaX, Вы писали:
CX>Электрические величины не могут быть выражены только в секундах, граммах и сантиметрах по определению. Они выражаются через длину, массу, время и силу тока, что у меня есть. CX>Посмотри на cgs::charge, cgs::voltage, cgs::resistance и т.д.
Ну я не знаю, как оно там "по определению", я знаю как в физике
Так вот в СГС есть только три основные размерности. Остальные выражаются через эти
Но с электричеством есть косяк один небольшой. есть два разных способа выразить. Поэтому есть СГСэ и СГСм.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, Erop, Вы писали:
CX>>Электрические величины не могут быть выражены только в секундах, граммах и сантиметрах по определению. Они выражаются через длину, массу, время и силу тока, что у меня есть. CX>>Посмотри на cgs::charge, cgs::voltage, cgs::resistance и т.д.
E>Ну я не знаю, как оно там "по определению", я знаю как в физике E>Так вот в СГС есть только три основные размерности. Остальные выражаются через эти
Кроме электрических и магнитных величин.
E>Но с электричеством есть косяк один небольшой. есть два разных способа выразить. Поэтому есть СГСэ и СГСм.
Моя cgs это и есть совмещенная СГС и СГСэ. СГСм не прикрутил, но для демонстрации и не нужно.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[10]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, CrystaX, Вы писали:
E>>Так вот в СГС есть только три основные размерности. Остальные выражаются через эти CX>Кроме электрических и магнитных величин.
Не, они там тоже выражаются, только степени полуцелые выходят
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[11]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, Erop, Вы писали:
E>>>Так вот в СГС есть только три основные размерности. Остальные выражаются через эти CX>>Кроме электрических и магнитных величин.
E>Не, они там тоже выражаются, только степени полуцелые выходят
Я уже начинаю сомневаться в своих знаниях. А ведь когда-то в олимпиадах участвовал и в институте по физике всегда отлично было. Вот сейчас сверился на всякий случай с учебником, завалявшимся еще с институтских времен.
Так вот, электрические и магнитные величины в СГС не выражаются отдельными единицами вообще. Об этом даже прямо написано в разделе, связанном с СГСэ:
Так как в системе СГС большинство единиц не имеет наименований, то единицу какой-либо физической величины мы будем обозначать символом этой системы с соответствующим индексом. Так, например, единицу силы тока — символом СГСi, единицу емкости — СГСc, напряжение — СГСu и т.д.
Собственно, сколько помню, так всегда и обозначались электрические величины в СГС — 1 А = 3 * 10^9 СГСi и т.д.
И никак они (электрические и магнитные величины) через сантиметры, граммы и секунды не выражаются.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[12]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, CrystaX, Вы писали:
CX>Я уже начинаю сомневаться в своих знаниях. А ведь когда-то в олимпиадах участвовал и в институте по физике всегда отлично было. Вот сейчас сверился на всякий случай с учебником, завалявшимся еще с институтских времен.
Ну примерно такая же фигня. ТОка инмтитут ещё конкретно физический А что за учебник?
CX>Так вот, электрические и магнитные величины в СГС не выражаются отдельными единицами вообще. Об этом даже прямо написано в разделе, связанном с СГСэ: CX>
CX>Так как в системе СГС большинство единиц не имеет наименований, то единицу какой-либо физической величины мы будем обозначать символом этой системы с соответствующим индексом. Так, например, единицу силы тока — символом СГСi, единицу емкости — СГСc, напряжение — СГСu и т.д.
CX>Собственно, сколько помню, так всегда и обозначались электрические величины в СГС — 1 А = 3 * 10^9 СГСi и т.д. CX>И никак они (электрические и магнитные величины) через сантиметры, граммы и секунды не выражаются.
Ну и почему тогда есть СГСэ и СГСм?
Просто писать что-то типа "корень квадратьный из сантиметров-граммов в секунду за секунду" неудобно, вот и пишут СГСм i напрмер. Это просто сокращённая запись да и только
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[13]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, Erop, Вы писали:
CX>>Я уже начинаю сомневаться в своих знаниях. А ведь когда-то в олимпиадах участвовал и в институте по физике всегда отлично было. Вот сейчас сверился на всякий случай с учебником, завалявшимся еще с институтских времен. E>Ну примерно такая же фигня. ТОка инмтитут ещё конкретно физический А что за учебник?
Не скажу сейчас — учебник дома остался. Советских еще времен, хороший учебник.
Домой приду — напишу.
CX>>Так вот, электрические и магнитные величины в СГС не выражаются отдельными единицами вообще. Об этом даже прямо написано в разделе, связанном с СГСэ: CX>>
CX>>Так как в системе СГС большинство единиц не имеет наименований, то единицу какой-либо физической величины мы будем обозначать символом этой системы с соответствующим индексом. Так, например, единицу силы тока — символом СГСi, единицу емкости — СГСc, напряжение — СГСu и т.д.
CX>>Собственно, сколько помню, так всегда и обозначались электрические величины в СГС — 1 А = 3 * 10^9 СГСi и т.д. CX>>И никак они (электрические и магнитные величины) через сантиметры, граммы и секунды не выражаются.
E>Ну и почему тогда есть СГСэ и СГСм? E>Просто писать что-то типа "корень квадратьный из сантиметров-граммов в секунду за секунду" неудобно, вот и пишут СГСм i напрмер. Это просто сокращённая запись да и только
Ок, если это сокращенная запись, дай определение силе тока в системе СГС. Через сантиметры, граммы и секунды.
CX>Ок, если это сокращенная запись, дай определение силе тока в системе СГС. Через сантиметры, граммы и секунды.
Ну, например, в СГСэ размерность заряда выбирается так, чтобы в законе Кулона не было размерного множителя.
Соответсвенно заряд в СГСэ будет: "корень квадратный их грамма на кубический сантиметр в секунду за секунду"
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[11]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, CrystaX, Вы писали:
E>>>Так вот в СГС есть только три основные размерности. Остальные выражаются через эти CX>>Кроме электрических и магнитных величин.
E>Не, они там тоже выражаются, только степени полуцелые выходят
Вырази, пожалуйста, через эти три величины
— силу тока
— интенсивность освещения
— плоский угол
— темперутуру
Здравствуйте, Erop, Вы писали:
E>Ну, например, в СГСэ размерность заряда выбирается так, чтобы в законе Кулона не было размерного множителя.
E>Соответсвенно заряд в СГСэ будет: "корень квадратный их грамма на кубический сантиметр в секунду за секунду"
Хмм... Да, верно. Вечером еще раз гляну в учебник.
В любом случае, если вернуться к обсуждению моей системы размерностей, это проблем не создает. Просто выбирается наиболее мощная система единиц, и все орты выражаются в ней.
Здравствуйте, CrystaX, Вы писали:
E>>Соответсвенно заряд в СГСэ будет: "корень квадратный их грамма на кубический сантиметр в секунду за секунду"
CX>В любом случае, если вернуться к обсуждению моей системы размерностей, это проблем не создает. Просто выбирается наиболее мощная система единиц, и все орты выражаются в ней.
Не совсем. В СГСэ заряд умноженный на корень из грамм-кубосантиметра -- это обратные скунды. Как это выразить в твоей системе?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[12]: Compile-time вычисления: а оно вообще надо?
Здравствуйте, Alxndr, Вы писали:
A>Вырази, пожалуйста, через эти три величины A>- силу тока A>- интенсивность освещения A>- плоский угол A>- темперутуру
Ну сила тока, это расход заряда в минуту. Там СГСэ и СГСм бывает. В одной в законе кулона нет размерного множетеля, в другой в законе ампера (Он же Био-Савары-Лапласа, кажется)
Интенсивность освещения вводится через энергии, плоский угол вообще безразмерен, так как есть отношение длин, ну а температура как вводится я не помню, но думаю, что тоже через энергии. Надо в справочник поглядеть.
А в чём проблема-то?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[13]: Compile-time вычисления: а оно вообще надо?