О BOOST, тебя хвалить устали
Твои заслуги возносив.
С "велосипедами" из stall-и
Ты борешься, нас не спросив.
PR пронёсся над умами
В фаворе ты, но вот беда
Теперь, когда ты рядом с нами
Ты сам "велосипедом" stall
Я вру? Бессовестно тревожу
Покой зомбированных тел?
Ну что же объясню попозже,
Что этим я сказать хотел.
Возьму, последуя примеру
Тех, кто хулит велосипед,
Банальный код. Но заная меру
Не буду bind-ить стих и вред.
Да ВРЕД иначе и не скажешь
О том ветвистом копипэйст.
Под компиляторы однажды
Настроенном в ущерб себе.
Както мне понадобился генератор псевдослучайных чисел. И следуя модному течению я решил использовать boost::random::linear_feedback_shift. По своему прежнему опыту я знал каким хорошим алгоритмом является LFSR. Мой велосипед, основанный на нём, служил мне верой и правдой уже не один год.
Справедливости ради хочу сказать, что использовал старую версию boost_1_33_0. Ну не могу я скачивать все версии BOOST подряд. Но вряд ли сейчас ситуация изменилась.
И вот начались мои мучения. Удовлетворив всем (даже закомментированным) STATIC_ASSERT-ам (спасибо, что хоть они есть) я подобрал template параметры и... Моя программа вошла в бесконечный цикл. Вернее это я теперь знаю, что он бесконечный. А сперва я очень радовался быстрой работе и якобы огромному периоду boost::random:: linear_feedback_shift генератора. Но чудес не бывает, и когда этот якобы огромный период превысил число возможных состояний генератора, я забеспокоился. Но как можно обвинить ВЕЛИКИЙ BOOST!? Естественно, я стал искать свою ошибку. Потратив пару дней я находился в свирепом настроении. Заказчик (физик-ядерщик) требовал продукт, а программа работать не хотела. Но вот, наконец, я провёл полное доказательство правильности своего алгоритма (Те кто этим занимался знает, что это адская работа). Оставался лишь хвалёный (читай PR-еный) BOOST-ом linear_feedback_shift. И я отправился в чтение кода BOOST. К счастью оказалось, что boost::random не слишком завязан на остальные дебри BOOST. Раскрыв всего десяток макросов, пройдя всего пару десятков include, мне удалось частично понять немного странную логику разработчиков.
И не надо обвинять меня в лишней работе. Я искал ошибку в незнакомом коде и по любому должен был пройти по этим #define #ifdef и #include. К слову сказать, если бы они меньше внимания уделяли тому чтобы их велосипеды ездили везде, всё могло бы быть гораздо проще и понятнее. Как известно, программы пишут не для компиляторов, а для людей. Но плюньте в глаза тому, кто скажет, что этот принцип распространяется на BOOST.
Но вернёмся к пресловутому linear_feedback_shift. Сперва я обнаружил, что он почти не в состоянии выдать своё заявленное минимальное значение. Мой плохой английский не позволил мне выяснить в документации это точная нижняя граница или просто некое число меньшее\равное этой границе. Пришлось изменить мой алгоритм (от чего он стал труднее для понимания) и использовать метод linear_feedback_shift::max. Вы думаете это спасло отца русской демократии? Как бы не так! Доказать что linear_feedback_shift::operator() никогда не выдаёт значение возвращаемое linear_feedback_shift::max я не смог, но исчерпывающий поиск для нескольких разных инстанциаций linear_feedback_shift показал, что таки не выдаёт. В процессе этого поиска дополнительно выяснилось, что обычный период генератора даже меньше чем у ::rand(). И ни в одном случае не превосходит половины возможного числа состояний генератора. То есть генератор не выдаёт как минимум половину чисел, в которую обычно и входят min и max. Причём Вам будет довольно таки трудно найти именно те template параметры, при которых он всё-таки выдаёт хотя-бы половину. А если Вы хотите чтобы порядок этих чисел ещё и напоминал случайный, (не слишком ли много Вы хотите?) то Вы должны быть специалистом по генераторам случайных чисел, или потратить кучу времени на подбор чудесной комбинации правильных параметров ибо в документации (не говоря уже о assert-ах) такой информации нет.
Впрочем, в утверждении, что генератор не выдаёт min я погрешил против истины. Иногда ВЫДАЁТ!!! И при этом его период равен единице!!! То есть он или не выдаёт min совсем или выдаёт его всегда! Замечательный генератор. Вы не находите? Примерно такая же ситуация имеет место для чисел близких к минимуму или максимуму.
А сейчас ВНИМАНИЕ. На арене фокусник.
МНЕ УДАЛОСЬ менее чем за 100 часов(а у меня старый, медленный комп) получить ВСЕ псевдослучайные числа в том порядке, в котором их выдают ВСЕ 32-битные (и менее) инстанциации этого генератора удовлетворяющие STATIC_ASSERT-ам и инициализированные default значением.
И это говорит не столько о высокой скорости работы генератора, сколько о смехотворности его среднего периода. В общем, могу рекомендовать несколько инстанциаций этого генератора только для локального внутри метода использования, если Вам абсолютно неважно качество получаемых чисел и крайне важна сверхвысокая скорость работы (всё в регистрах, память не задействована).
В документации сказано (насколько позволяет понять мой отвратительный английский) что качество linear_feedback_shift генератора среднее (quality: medium).
cycle length is limited to the maximum value representable in one machine word, fails some statistical tests, can be improved with the xor_combine compound engine.
Формально к этому не придраться. Но мы и без того знаем, что период любого генератора не может быть больше числа его состояний, а "some" в свете вышеизложенного лучше перевести как "большинство". Что касается xor_combine compound engine, то он может сделать хорошими 90% наших отвратительных велосипедных генераторов. Но случайная инстанциация boost::random::linear_feedback_shift обычно не входит даже в эти 90%.
После этого исследовать другие характеристики генератора мне не захотелось и, покатавшись (получая синяки и шишки при падениях) на этом BOOST велосипеде я хотел вернулся к своему старенькому велосипеду (тоже LFSR), который выдаёт любой (хоть 64-битный) интегральный тип во всём его диапазоне, гарантирует период=(1<<47)-1; (Если кому мало можно легко добавить), работает правда почти на 80% медленнее, но позволяет делать прямое позиционирование в любую часть генерируемой последовательности, и давно успешно прошел все известные мне методы проверки генераторов псевдослучайных чисел. Увы, я их не так много знаю. Кроме того (в коммерческой версии) он гарантирует, что это качество останется одинаковым для любых его инстанциаций. Завистники, правда, говорят, что его sizeof в десятки раз больше бустовского, но мне редко приходилось видеть программы использующие сотни \ тысячи генераторов одновременно и\или передающих их параметром по значению (как в BOOST) так, что это не должно быть большой проблемой. В 1989 году на 16 разрядном ДВК-2 с 56 килобайтами памяти это не стало проблемой. Но на свою беду я решил сделать вторую попытку и использовал boost::lagged_fibonacci. Большой sizeof этого генератора вселял надежду, а (даже указанная в документации) скорость работы была на пару процентов выше чем у моего велосипеда. Увы, меня ждало горькое разочарование. В документации я опять же этого не нашел, но оказалось что несколько генераторов с разным состоянием могут выдавать абсолютно одинаковые последовательности и это не удивительно если посмотреть как написаны operator== и seed(it&,it). Кроме того большинство бустовских генераторов нельзя использовать в программах высокой надёжности от которых, например, зависят жизни людей. ВСЁ! Я поставил крест на использовании boost::random::AnyEngine, но пока ещё хотел использовать boost::random::AnyDistribution. Поэтому адаптировал свой велосипед к бустовскиму интерфейсу и стал использовать его как boost::random::Engine. Кстати до адаптации его интерфейс был прост как грабли. Вы знаете что такое STL итератор? Так вот этот велосипед – STL совместимый random_access итератор кольцевой неизменяемой последовательности равномерно распределённых беззнаковых псевдослучайных чисел. Он так и назван. Вопросы остались? Нужно долго изучать Random Number Generator Library Concepts, копаться в документации и коде изучая некие engine, distribution, seed, validate, min, max, reset? Нужно объяснять что означает равенство генераторов? Нужно выяснять имеет ли генератор эффект девятки? Поздравляю, базируясь лишь на своих знаниях C++ (а STL его часть) Вы за несколько секунд (или минут в зависимости от сообразительности) узнали почти всё о новом незнакомом генераторе псевдослучайных чисел даже не заглядывая в документацию. Нет, Вам возможно придётся таки залезть туда когда Вы захотите использовать разность итераторов или специфический конструктор (BOOST такой функциональности, кажется, даже не предоставляет), но начать работу вы сможете сразу. А теперь дайте документацию и исходники BOOST незнакомому с ним человеку и включите секундомер…
Что? Вы хотите распределение вероятностей отличное от равномерного? Желаете генерировать не unsigned int а std::vector<double> или Ваш some_other_type? В чём проблема? STL итератор легко параметризуется типом итерируемых значений. Хотя у меня этого и не сделано.
Для меня до сих пор является загадкой, почему boost::random::Engine_конструктор по умолчанию не проводит первичную рандомизацию и создаёт объект в одном и том же состоянии. Неужели я сам каждый раз должен каким-то чудом создать буфер случайных чисел и передать его в конструктор или функцию seed? Если мне вдруг понадобиться такая функциональность (например для снятия рандомизации при отладке) то можно создать глобальный константный объект и присваивать его текущему генератору. С моей точки зрения это даже проще чем reset, а обычный случай должен подразумевать начальную рандомизацию. Коммерсанты требуют от меня знаний BOOST и отказывают в приёме на работу. Что же пусть платят деньги, чтобы их программисты забивали себе головы новыми ни для чего не нужными концепциями и тратили время на подбор template параметров, генерацию случайных затравок (часть из которых просто нельзя генерировать) и поиски ошибок в BOOST генераторах.
Но продолжим. Как Вы помните я решил не отказываться от написанных в BOOST распределений и вот что я обнаружил. boost::normal_distribution вызывает Engine разное количество раз и выдаёт коррелирущие соседние значения. По видимому, это является следствием неграмотной и неполной оптимизации. Кроме того моему учёному заказчику было мало обычного double, а работать с big_precision_real_number буст не захотел. Приведу исходный бустовский и аналогичный мой код с комментариями. В буст коде расскажу почему он плохо написан. В своём, почему значения будут коррелировать.
// deterministic polar method, uses trigonometric functionstemplate<class RealType = double>
class normal_distribution
{
public:
typedef RealType input_type;
typedef RealType result_type;
#if !defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) && !(defined(BOOST_MSVC) && BOOST_MSVC <= 1300)
BOOST_STATIC_ASSERT(!std::numeric_limits<RealType>::is_integer);
#endif// Почему используются целые константы?
// result_type – вещественный тип
// и может не уметь так создаватьсяexplicit normal_distribution(const result_type& mean = result_type(0),
const result_type& sigma = result_type(1))
: _mean(mean), _sigma(sigma), _valid(false)
{
// Мой коллега писавший class big_precision_real_number
// поленился написать operator>=
// в template всегда лучше использовать operator<
assert(sigma >= result_type(0));
}
// compiler-generated copy constructor is NOT fine, need to purge cache
// Я так и не смог понять, почему необходимо сбрасывать кеш.
// и почему его ненужно сбрасывать при присваивании.
// Мне кажется, это лучше делать явно через reset
normal_distribution(const normal_distribution& other)
: _mean(other._mean), _sigma(other._sigma), _valid(false)
{
}
// Комментарий вводит в заблуждение.
// compiler-generated copy ctor and assignment operator are fine
// Обращение к членам класса в template опасно проводить без this->
// даже если Вы используете префиксное подчёркивание.
RealType mean() const { return _mean; }
RealType sigma() const { return _sigma; }
// Информация о валидности вполне может содержаться в самом кеше.void reset() { _valid = false; }
// Кажется, operator() должен быть константным?template<class Engine>
result_type operator()(Engine& eng)
{
#ifndef BOOST_NO_STDC_NAMESPACE
// allow for Koenig lookupusing std::sqrt; using std::log; using std::sin; using std::cos;
#endif
if(!_valid) {
// 1) Почему _r1 _r2 входят в состояние объекта?
// Достаточно стековых переменных.
// 2) В общем случае опасно читать\менять состояние объекта не атомарно,
// а прямая работа с членами-данных оптимизируется
// компиляторами заметно хуже, чем с auto переменными.
// 3) Пользователь может "заложиться" на фиксированное число
// вызовов eng() при генерации. Нужно хотя бы предупредить!
_r1 = eng();
_r2 = eng();
// Зачем постоянно использовать лишние операции?
// Будет яснее и быстрее, если однократно вычислить константы,
// а не делать это на каждом втором вызове.
_cached_rho = sqrt(-result_type(2) * log(result_type(1)-_r2));
_valid = true;
} else {
_valid = false;
}
// Can we have a boost::mathconst please?
// Раз всё равно требуется конструироваться от double
// зачем выше использовали целые константы?const result_type pi = result_type(3.14159265358979323846);
// Часто sin_cos это одна инструкция процессора или один
// кеширующий result_type::метод и лучше вычислять их парой
// а не в разных вызовах.return _cached_rho * (_valid ?
cos(result_type(2)*pi*_r1) :
sin(result_type(2)*pi*_r1))
* _sigma + _mean;
// Правильность самой формулы вычисления вызывает сомнения.
}
#if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
// Почему количество пробелов при вводе и выводе не совпадает?template<class CharT, class Traits>
friend std::basic_ostream<CharT,Traits>&
operator<<(std::basic_ostream<CharT,Traits>& os, const normal_distribution& nd)
{
os << nd._mean << " " << nd._sigma << " "
<< nd._valid << " " << nd._cached_rho << " " << nd._r1;
return os;
}
// Странно, что ctor сбрасывает кеш, а ввод из потока нет.
// И чем так отличается _r2 что не участвует во вводе\выводе?template<class CharT, class Traits>
friend std::basic_istream<CharT,Traits>&
operator>>(std::basic_istream<CharT,Traits>& is, normal_distribution& nd)
{
is >> std::ws >> nd._mean >> std::ws >> nd._sigma
>> std::ws >> nd._valid >> std::ws >> nd._cached_rho
>> std::ws >> nd._r1;
return is;
}
#endif
private:
// Слишком избыточное состояние генератора провоцирует к ошибкам
// Хватило бы result_type _cached, _mean, _sigma;
result_type _mean, _sigma;
result_type _r1, _r2, _cached_rho;
bool _valid;
};
А теперь о boost::uniform_on_sphere… Там тоже ошибка (к счастью крайне маловероятная) деления на ноль. А о скорости его работы даже говорить не хочется. Как ни учён был мой заказчик, но сфера у него была обычная 3D и задержки связанные с генерацией произвольного N-мерного вектора свели бы на нет все мои прошлые усилия. Для 1D и 2D случаев это ещё заметнее. ASSERT или исключение на случаи меньше единицы отсутствуют.
Вот сижу теперь и думаю зачем я корячился переводя документацию(мне это сложно я программист а не переводчик) если в итоге пришлось всё самому делать?
Не знаю как Вы, а я больше в BOOST ни ногой. Я ЕМУ НЕ ВЕРЮ. И его разработчики сделали всё, чтобы было труднее ему поверить. Разбираться в правильности (в данном случае ошибочности) его кода почти невозможно. А я копался в одной из самых понятных (имхо) частей BOOST.
Есть ещё желающие говорить что BOOST это не пропиареный велосипед? Вы скажете в любом коде могут быть ошибки. Наверно да. Но еслибы на мой код в течении хотябы месяца пялились бы тысячи программистов в нём не осталось бы ни одной ошибки. А сколько лет бусту? Действительно, наши велосипеды часто имеют ошибки. Но имеет ли право такая библиотека содержать такие ошибки? И чем тогда она отличается от наших велосипедов? Кстати, хоть это ничего и не меняет, поправьте меня если в новой версии этих ошибок нет. Может быть тогда мне удасться поверить в буст. Он хоть и велосипед но не хуже 90% наших велосипедов.
Часть вторая (очень очень спорная. наверно зря пишу)
Кроме того у меня возникли большие сомнения в переносимости. Нет, не самого BOOST.
Об этом разработчики позаботились (это PR), а программ написанных с его использованием. Неужели мы все должны писать так как в BOOST? Обрамляя в угоду недоделанным компиляторам большие куски кода #ifdef-ами и фактически дублируя его с небольшими изменениями для нескольких разных случаев? А как потом его синхронно изменить во всех этих местах?
Проводя аналогию с велосипедами можно сказать, что их велосипеды могут ездить везде но увы по-разному. А мне нужно чтобы пусть не везде, но одинаково.
Приведу (далеко не лучший) пример. Вот наследуюсь я от пресловутого linear_feedback_shift
class my_bicycle : linear_feedback_shift< .... >
{
public:
// Я могу написать и потом обнаружить что это не переносимоbool operator == ( my_bicycle const & x ) const throw ()
{ return this->linear_feedback_shift::operator==(x); }
// Вероятно, я должен писать так
// Но лично я не хочу тратить свои мозги на запоминание этого факта.
// И лично для меня это выглядит менее понятно.
// Не говоря уже о том, что в бОльшем количестве кода легче совершить ошибку.bool operator == ( my_bicycle const & x ) const throw ()
{
return
static_cast<linear_feedback_shift const&>(this)
==
static_cast<linear_feedback_shift const&>(x);
}
// Но и это исчо не всё.
// Мне вообще предлагают лечь под компилятор и получать удовольствие.#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
friend bool operator == ( my_bicycle const& x, my_bicycle const& y ) throw ()
{
return
static_cast<linear_feedback_shift const&>(x)
==
static_cast<linear_feedback_shift const&>(y);
}
#else
bool operator == ( my_bicycle const & x ) const throw ()
{
return
static_cast<linear_feedback_shift const&>(*this)
==
static_cast<linear_feedback_shift const&>(x);
}
#endif
};
Хотите продолжать? Тогда вспомните что некоторые компиляторы ругаются на throw (). Этого мало? Замените #ifndef X на #if !defined(X) для некоторых компиляторов. Верьте! Это можно продолжать! И Ваша жена будет образцом непритязательности и смирения по сравнению с капризным своенравным и взбалмошным компилятором.
Итак пара понятных строк кода выросла до размеров нескольких экранов только потому, что кто-то себя пиарит(?). Скажите, Вы не знаете какие секретные технологии используют разработчики BOOST чтобы сопровождать это безобразие? Я бы за такую задачу не взялся.
Лично я не вижу проблемы в том чтобы отказываться от поддержки плохих компиляторов. Но... Это опять чёртов PR которому последнее время уделяется всё внимание. Вы можете быть откровенно слабым программистом, но если Вы в костюме и галстуке то Ваш код будет называться ПРОДУКТОМ. А мой код назовут "велосипедом" только за то, что я не пользуюсь мобильным телефоном, берегу окружающую среду отказавшись от использования дымящего автомобиля и предпочитаю ходить в джинсах и свитере.
P.S.
PR акция:
1) Поборники и защитники BOOST могут затребовать free-версию вышеозначенного велосипеда в виде MSVC71.hpp и MSVC71.obj файлов и яро её покритиковать.
2) Имеющие хороший пакет для проверки рандомов и желающие его протестировать приветствуются. (Бустовский даже глядеть не хочу)
3) Испытывающие нужду в хорошем генераторе псевдослучайных чисел тоже могут связываться.
P.P.S.
А вообще вся эта PR возня очень напоминает следующее объявление:
Продаю старые файлы windows95.
Файл win386.swp стоит 1386 у.е. (раритет)
Владельцам новых компов предлагаю апгрейд
файлы:
win486.swp за 486 у.е.
Для FAT32 и NTFS
win_pentium1.swp за 1000 у.е.
win_pentium2.swp за 2000 у.е.
win_pentium3.swp за 3000 у.е.
И эксклюзивное предложение!
Только у нас!
Только для Вас!
Последняя модификация!
Легальная авторская копия!
Полная програмная и аппаратная совместимость с 4х-ядерными процессорами!
Поддерживает 256-битные приложения!
Поддерживает длинные имёна!
Русифицирован!
Дружественен к пользователю!
Абсолютно вирусобезопасен!
Содержит электронную подпись!
Обладает возможностью к расширению!
Протестирован InteLL!
Сертифицирован 1BM!
Поддержка Macrohard Mouse, Macrohard Dog и Macrohard Cat!
Файл:
ЭЭЭЭ !!! КУДА ВЫ? СТОЙТЕ !!!
ДВА ПО ЦЕНЕ ОДНОГО !!! ТРЕТИЙ БЕСПЛАТНО !!!
Свежие! Создаются в присутствии покупателя!
Ламерам по предъявлению этого объявления скидки!
Обычное явление, я бы на вашем месте хорошо подумал много ли людей использует генератор случайных чисел и многим ли он действительно нужен хороший. Подумали? Вот и прикиньте насколько код будет оттестирован. Зачем вам вообще он из буста нужен был если был готовый, рабочий, в котором вы все грабли знаете? Острых ощущений захотелось ?
Здравствуйте, Dmi_3, Вы писали:
D_>Кроме того большинство бустовских генераторов нельзя использовать в программах высокой надёжности от которых, например, зависят жизни людей.
Можно ли этот тезис раскрыть подробнее? А то я очень далек от генераторов случайных чисел, а из вашего текста не понял откуда такой категоричный вывод появился.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Значит с математикой в буст не всё хорошо. Я также наблюдаю некоторые неаккуратности, типа пачки warning-ов, которые достаточно лёгкие но из-за своей темплейтности разворачиваются в сотни строк лога, но чтобы неаккуратности до такой степени . Я, кстати, пытался им писать про их warning-и — проигнорировали.
Буст есть библиотека из библиотек. Библиотеки пишутся совершенно разными людьми, и в общем они проходят review и regression test что конечно в основном выявляет "бустофицируемость" и портируемость библиотеки. Поэтому лучше буст воспринимать именно как набор библиотек а не как цельный продукт. Такие, очень часто используемые библиотеки как bind думаю вылизаны хорошо и им можно доверять . К остальным — с линейкой.
С другой стороны их авторов можно понять, написать портируемый код с поддержкой старых компиляторов тяжело. Тут не до математики . Сам вот раздумывал додолбить свой класс Property да предложить бусту, но понял что трудоёмкость такого труда просто огромная.
А по поводу поддержки портируемости вами — не понятно. Если вы собираетесь писать сильно портируемый код то вам в любом случае придётся бороться с компиляторами и буст вам только в помощь с его workaround-ами и обёртками. Если нет — то зачем вам заботиться о том что в других компиляторах нет поддержки throw()? Если вам нужно "везде, но одинаково" используйте базовый функционал буста (без advanced конструкций). В хелпе многих библиотек указываются tradeoff-ы и портируемые/непортируемые конструкции.
Здравствуйте, rm822, Вы писали:
R>Обычное явление, я бы на вашем месте хорошо подумал много ли людей использует генератор случайных чисел и многим ли он действительно нужен хороший. Подумали?
Вот это, имхо, очень правильная постановка вопроса.
Вот тут, например, не так давно ругали stl-алгоритмы и контейнеры, что типа там просто какой-то лажовый sort(), а не супер_пупер_sort_через_правое_плечо_левое_ухо_с_групповыми_перестановками_inplace_про_который_я_недавно_прочитал_в_умной_книжке().
Я, лично, постоянно использую обычный sort() и мне всё равно как конкретно он работает, я просто знаю, что он работает "нормально". И я думаю, таких людей достаточно много.
А если кому нужен супер_пупер_sort_и_т_д(), то ему все равно наврядли угодишь, потомучто есть супер_пупер_sort_через_правое_плечо_левое_ухо_с_групповыми_перестановками_inplace_про_который_я_недавно_прочитал_в_умной_книжке(), а есть
модифицированный_Ивановым_с_улучшенным_среднем_временем_в_худшем_случае_супер_пупер_sort_через_правое_плечо_левое_ухо_с_групповыми_перестановками_inplace_про_который_я_недавно_прочитал_в_умной_книжке().
Всё равно всегда есть к чему придраться, и всё равно всё не реализуешь.
Поэтому я 90% случаев я просто испольую готовое и радуюсь, что мне не надо в это вникать. А когда мне надо что-то особенное, с особыми требования по какому-либо параметру или это просто mission-critical часть, то тут уж ничего не остаётся, как, засучив рукава, вникать в это и реализовывать.
Вот тогда я и получил один из главных уроков в области программной архитектуры: для наиболее ответственных, критических задач вы должны использовать инструмент одним уровнем абстракции ниже, чем это было бы в идеале. Например, если вы пишете крутую трехмерную стрелялку (такую, как Quake, который вышел примерно тогда же) и вы планируете оставить конкурентов далеко позади с помощью крутейшей трехмерной графики, не используйте первую попавшуюся графическую библиотеку. Пишите свою собственную, потому что это фундамент вашей работы. Те, кто использует 3D библиотеки, такие как DirectX, делают это, потому что они пытаются выиграть на чем-то другом, отличном от качественной графики (может быть, на сюжете игры).
Основная идея этих статей следующая. Не возможно сделать высокоуровневую, удобную абстракию, что бы она в тоже время была полностью гибкой, функциональной, и без drawback'ов. Например, tcp — очень удобно, понятно, не надо знать детали потокового соединения. Но когда начинаются проблемы со скоростью работы или ещё с чем-то Вы ничего не сможете сделать! Совсем ничего! Потомучто кроме send() и recv() у Вас больше ничего нет.
Так же и с boost... и с stl, direct3D, openGL, ODBC, XML... короче со всем.
Здравствуйте, remark, Вы писали:
R>Основная идея этих статей следующая. Не возможно сделать высокоуровневую, удобную абстракию, что бы она в тоже время была полностью гибкой, функциональной, и без drawback'ов.
Это все правильно, но все равно библиотека должна быть без багов, а Dmi_3 нашел именно баги.
На самом деле, багов в random действительно порядком, достаточно посмотреть на переписку в мейл-листе буста, они там постоянно чего-то исправляют.
Здорово было бы, если бы Dmi_3 перевел свой пост на английский и послал в мейл-лист буста — глядишь и поправили бы, или вообще взяли бы его реализацию, если она патентно чиста, конечно же.
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, remark, Вы писали:
R>>Основная идея этих статей следующая. Не возможно сделать высокоуровневую, удобную абстракию, что бы она в тоже время была полностью гибкой, функциональной, и без drawback'ов.
J>Это все правильно, но все равно библиотека должна быть без багов, а Dmi_3 нашел именно баги.
Ну да, это я понял. Я имел в виду, что даже, если бы она была без багов, то она бы не подошла Dmi_3, судя по его требованиям. А если бы и подошла сразу, то это было бы ещё хуже, т.к. чем позже он бы понял, что она всё так не подходит, тем хуже
Т.е. в принципе он мог бы и не смотреть в сторону boost.random.
Для mission-critical частей можно использовать только те библиотеки, которые как минимум проверены годами, и про которые известно, что они "работают". Т.е., например, все знают, что Win API можно использовать и что оно просто работает, можно делать ядро ИС на Oracle, т.к. все знают, что она просто работает, можно делать сетевой сервер на ACE и т.д. Но на первом попавшемся проекте с sourceforge я бы делать не решился...
R>Для mission-critical частей можно использовать только те библиотеки, которые как минимум проверены годами, и про которые известно, что они "работают". Т.е., например, все знают, что Win API можно использовать и что оно просто работает, можно делать ядро ИС на Oracle, т.к. все знают, что она просто работает, можно делать сетевой сервер на ACE и т.д. Но на первом попавшемся проекте с sourceforge я бы делать не решился...
R>
Ну а вы сами то в какой ряд поставите boost, к ИС на Oracle, ACE или к первому попавшемуся проекту на sourceforge?
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, Dmi_3, Вы писали:
D_>>Кроме того большинство бустовских генераторов нельзя использовать в программах высокой надёжности от которых, например, зависят жизни людей.
E>Можно ли этот тезис раскрыть подробнее? А то я очень далек от генераторов случайных чисел, а из вашего текста не понял откуда такой категоричный вывод появился.
Я тоже не являюсь специалистом в этой области. И знаком лишь с 50% литературы приведённой в boost документации, а самостоятельно читал и того меньше. Тем не менее вывод обоснован. Несмотря на то, что каждый алгоритм используемый в boost::random генераторах имеет под собой достаточно солидную теоритическую базу и в этом смысле они не являются "велосипедами", исполнение подкачало. Вы помните как раньше нельзя было использовать библиотеки без const? Сейчас есть такиеже проблемы с библиотеками без throw(). Кроме того, наивное использование ЛЮБЫХ генераторов случайных чисел плохая идея при написании программ высокой надёжности. Увы, ограниченность наших знаний о мире и недетерминированный характер некоторых процессов не позволяют нам обойтись без них. В boost документации в разделе мотивации об этом немного написано.
В программно-аппаратных комплексах высокой надёжности (и реального времени) практически всегда происходит не меннее чем трёхкратное дублирование вычислений и аппаратное сравнение результатов с автоматическим отключением сбойной ветки и подачей сигнала тревоги. Но это часто считается недостаточным и тогда требуется формальное доказательство правильности(и финитности) всех используемых алгоритмов. Классическим примером также является отказ от использования вырождающихся в O(N*N) вариантов сортировки Хоара.
Надёжность реализации boost-генераторов проверялась(?) лишь тестированием. Я не думаю, что авторы сознательно удалили assert-ы являющиеся продуктом доказательства правильности. А общеизвестно, что тестирование лишь позволяет обнаружить некоторые ошибки, а вовсе не гарантирует их отсутствие. Наличие возможности деления на ноль в boost::uniform_on_sphere::operator() и возможности генерации одинаковых последовательностей разными boost::lagged_fibonacci яркое тому подтверждение. Практически невозможно не зная заранее об этих ошибках написать тестирующую программу, которая их обнаружит. А выявить ошибку путём попытки доказательства правильности, возможно. Я же выявил. Кроме того, программы написаны довольно небрежно, о чём свидетельствует разное число пробелов при вводе выводе. Есть ещё несколько не рассмотренных здесь причин. Другие поучительные примеры к вышеизложенному находятся http://citforum.ru/programming/digest/scofdebug/t_cont.shtml (Изучение знаменитых (и не очень знаменитых) ошибок_ Глава из книги Наука отладки). Хотя к некоторым утверждениями оттуда (например, к совету комментировать старый код) нужно относиться с осторожностью.
P.S.
Надеюсь, я достаточно подробно раскрыл тезис, но в дальнейшем делать этого вероятно не буду. Сейчас я это сделал потому, что чувствую себя слегка виноватым перед Вами за недоразумение возникшее в ветке compile-time вычислений.
Здравствуйте, Dmi_3, Вы писали:
D_>Надёжность реализации boost-генераторов проверялась(?) лишь тестированием. Я не думаю, что авторы сознательно удалили assert-ы являющиеся продуктом доказательства правильности. А общеизвестно, что тестирование лишь позволяет обнаружить некоторые ошибки, а вовсе не гарантирует их отсутствие. Наличие возможности деления на ноль в boost::uniform_on_sphere::operator() и возможности генерации одинаковых последовательностей разными boost::lagged_fibonacci яркое тому подтверждение. Практически невозможно не зная заранее об этих ошибках написать тестирующую программу, которая их обнаружит. А выявить ошибку путём попытки доказательства правильности, возможно. Я же выявил. Кроме того, программы написаны довольно небрежно, о чём свидетельствует разное число пробелов при вводе выводе.
Это прямое следствие самой природы Boost-а -- пропиаренного собрания самодельных велосипедов. В духе лучших традиций OpenSource -- подхода, когда баги выявляются миллионами глаз пользователей. В том числе и вашей парой
Что уж тут поделать. Потенциальные разработчики библиотек делятся на четыре категории:
* те, кто хотели бы делать библиотеки (но не обязательно умеют это делать)
* те, кто умеют это делать (но не обязательно хотят или берутся)
* те, кто заявляет о разработке (но не обязательно реально делают)
* те, кто реально делают (но не обязательно хотят или умеют)
К сожалению, наилучший результат получается на пересечении всех этих категорий. Что, как вы понимаете, происходит крайне редко
Лично я бы предпочел, чтобы библиотеки разрабатывались так, как Вирт и Кнут пишут свои программы -- когда они имеют возможность предлагать деньги за каждую найденную в уже вышедшей программе ошибку. Но приходится считаться с реальностью, в которой мы имеем то, что кто-то счел возможным поместить в Boost.
Пусть это сделано плохо, но это сделано и лицензия позволяет всем, кто имеет достаточные знания и умения, улучшить существующую реализацию. Это основополагающий принцип OpenSource. Поэтому ваш пост, с одной стороны, очень важен и полезен. Т.к. вы показали явные проблемы существующей реализации. И, может быть, подвигли кого-нибудь к ее исправлению. Но, с другой стороны, слишком уж вы кровожадны. И ваша эмоциональность, имхо, деструктивна. Так уж получается, что будущее C++ зависит от таких библиотек, как Boost. И как раз вы бы могли этому будущему поспособствовать, предложив Boost-у свою реализацию. Это было бы конструктивно. Хотя я понимаю, что скорее всего это невозможно из-за прав на интеллектуальную собственность.
D_>Надеюсь, я достаточно подробно раскрыл тезис, но в дальнейшем делать этого вероятно не буду.
Зря вы так
Ценность RSDN именно в том, что люди здесь считают возможным и нужным делится своими знаниями. И, в свою очередь, пополнять свои знания знаниями других участников.
D_> Сейчас я это сделал потому, что чувствую себя слегка виноватым перед Вами за недоразумение возникшее в ветке compile-time вычислений.
Дело давнее, уже забытое
Надеюсь, теперь вы лучше понимаете мое негативное отношение к черезчур сложным реализациям чего бы то ни было.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, johny5, Вы писали:
J> ... Такие, очень часто используемые библиотеки как bind думаю вылизаны хорошо и им можно доверять . К остальным — с линейкой.
Тогда почему я немогу сбиндить следующее?
class bind_test1
{
public:
int fun() { return 1; }
int fun_c() const { return 2; }
int fun_v() volatile { return 3; }
int fun_cv() const volatile { return 4; }
};
int main()
{
bind_test1 object;
bind_test1* ptr = &object;
bind_test1 const* ptr_c = ptr;
bind_test1 volatile* ptr_v = ptr;
bind_test1 const volatile* ptr_cv = ptr;
// Помогите сделать каждый из этих вызовов через boost::bind
// boost::bind (&bind_test1::fun_v,ptr)(); не работает MSVC71 BOOST_1_33_0
ptr->fun_v ();
ptr->fun_cv ();
ptr_v->fun_v ();
ptr_v->fun_cv ();
ptr_cv->fun_cv ();
ptr_c->fun_cv ();
}
Вы скАжете, пример надуман и volatile никто не использует? Разработчики сложных драйверов с Вами могут не согласиться.
Вы скАжете это легко исправить? Да. Но почему это до сих пор не исправлено если на составление примера ушло 40 человеко*минут, а библиотекой годами пользуются тысячи программистов? Не означает ли это что код не только не пытались доказать но и не пытались тестировать?
И ещё… Всё это bind хозяйство объявлено как бросающее любые исключения... Это мешает, но представляете что начнётся если они захотят это исправить? УУУ!!! Полностью разобраться во всём коде bind чтобы найти другие ошибки я не могу и не хочу. Боюсь, что этого почти(или совсем?) никто не может. Вы всё ещё считаете что boost::bind можно доверять?
Здравствуйте, eao197, Вы писали:
E>… слишком уж вы кровожадны. И ваша эмоциональность, имхо, деструктивна. Так уж получается, что будущее C++ зависит от таких библиотек, как Boost. И как раз вы бы могли этому будущему поспособствовать, предложив Boost-у свою реализацию. Это было бы конструктивно.
Я боялся, что это будет так воспринято…
Не надо делать из меня злого барабашку!
Я считаю, что сама концепция Engine\Distribution вредна и не заслуживает развития. Так уж повелось со времён примера Страуструпа, что все делают random-ы используя функторы. Мне кажется, что стоило бы использовать итераторы. Неужели я неубедительно объяснил почему это будет экономить мышление тысяч пользователей? Покажите что я не прав и (через несколько месяцев) я выложу boost совместимую реализацию (естественно без английской документации но с русскими комментариями и ссылками на РЕАЛЬНО используемую литературу).
Если, конечно, не помру с голоду или не пойду работать на свежий воздух дворником. Наши физики бедны и не могут много платить. Зато способны внятно объяснить что же им нужно. А не говорить "сделай трумбапуп используя бираксум". Вот тебе 20 страниц английского текста – переводи. Покривился, покорячился, перевел. Там написано: "Мэйкай кульный трумбапуп. Юзай рульный бираксум". НЕ НАДО СМЕЯТЬСЯ! ЭТО ГРУСТНО! Ну простите меня за мою эмоциональнось. И объясните почему коммерсанты считают, что когда программисту нужно сделать что-то из предметной области икс то он должен САМОСТОЯТЕЛЬНО становиться или даже уже быть специалистом в этой области, САМОСТОЯТЕЛЬНО искать того кто сможет внятно поставить задачу и "клещами" вытаскивать эту постановку? Программист и так довольно много знает о компьютерах, C++, алгоритмах, интерфейсах, структурах данных, методах программирования и ещё много о чём они даже понятия не имеют. Правда коммерсанты терпят молодых да ранних, что "грузят" этих самых коммерсантов memory_leek-ами и требуют повышения зарплат и покупки продвинутых компов ибо программы "текут", медленно работают и в конце концов падают по переполнению ВИНДОУЗ.СВАП! Это не шутка это правда! Эти же "программисты", играя на рабочем месте, имеют наглость посылать меня на … если им указать на ошибку мешающую мне работать (#define string "bla-bla-bla") но не "разжевать" её во всех подробностях. Я бы "разжевал" подробнее но на тот момент не мог понять что же из моих объяснений не ясно "программисту". Они же объявляют выговор потому что после моих изменений пол-конторы не смогла скомпилировать проект. Забывая, что ещё древние знали: "после того" вовсе не означает "в следствии того". И что если бы они последовали тем советам что я давал ранее такого просто не могло бы случиться. (они цепляли давно не входящие в проект заголовки) Хочется ещё о многом сказать но воздержусь.
Кроме того ни один коммерсант не согласиться ждать пока кто-то напишет этот несчастный хороший код, а возьмёт пару студентов и получит желаемое(?) гораздо(!) быстрее. Есть правда микроскопическая(?) вероятность, что потом он будет набирать дополнительную команду, платить им и закупать продвинутые средства отладки, многократно отодвигая изначально нереальныные сроки сдачи проекта. А вот физик согласен ждать. Тоже правда не хочет, но куда ему бедолаге деваться?! Молодые да ранние 1С стриптизёры за 5000у.е. в месяц такого понапишут что его ТОКАМАК однажды превратиься в симпатичный ядерный грибок. И это тоже не смешно.
D_>>Надеюсь, я достаточно подробно раскрыл тезис, но в дальнейшем делать этого вероятно не буду. E> Зря вы так. Ценность RSDN именно в том, что люди здесь считают возможным и нужным делится своими знаниями. И, в свою очередь, пополнять свои знания знаниями других участников.
Так я вовсе не против делиться, а тем более получать знания. Просто если долго делиться\получать то успеваешь сильно проголодаться... А чтобы хоть сколько-нибудь обоснованно и подробно ответить на вопрос времени уходит немало. Да и интернет у меня не казённый.
P.S.
Да простят меня мои знакомые коллеги. К некоторым из них(хоть и молодым и высокооплачиваемым) всё вышесказанное не относиться. В общем я согласен что я старый ворчун, но разве я не прав? Увы я не могу воздержаться от ворчания когда вижу как идеи лучших преставителей моей любимой профессии ежедневно приносятся в жертву алчным, безграмотным, ищущим сиюминутной выгоды коммерсантам и стриптизёрам. Ещё раз простите за деструктивную(?) эмоциональность.
Здравствуйте, Dmi_3, Вы писали:
D_>Вы скАжете, пример надуман и volatile никто не использует? Разработчики сложных драйверов с Вами могут не согласиться.
Так они в первую очередь не станут сложными библиотеками пользоваться, тем более бустом.
Где я сейчас работаю, пишется система (около 140а COM-dlls на C++) для встроенных WinCE-устройств, жирный слой над ОС. Используемые библиотеки: доработанная COM-часть ATL (без C++ exceptions, работает от embedded VC3 до VC8) и STL (используется в исключительном порядке в двух модулях) старенькая какая-то от HP. STL нашу VC8 компилировать наотрез отказался и пришлость пересесть на STLPort (имеющий свои подводные камни). Так вот в остальном все стандартные классы типа array и string у нас свои велосипедные, но опробованные временем (лет 10 назад всё начиналось) и клиентами (около 200000 устройств в год сбываем), на разных архитектурах (MIPS, ARM, x86) и ОСях (на данный момент от Windows CE 3.0 до XP). Свой велосипед ближе к ж0пе, свой скорее можно понять и починить (ATL пришлось нехило для VC8 править, даже для STLPortа чуть-чуть).
Попробовал на днях в COM-"Hello World" проекте ATL от VC8 использовать — так она хочет статически libы свои использовать — с С++ ИСКЛЮЧЕНИЯМИ . Что, конечно, линковаться для платформы без них не стало. Взял велосипедную ATL -- всё пошлó.
Так что, выпьем за велосипеды!
Re: BOOST vs BICYCLE
От:
Аноним
Дата:
10.12.06 03:09
Оценка:
Здравствуйте, Dmi_3, Вы писали:
[rant muted]
Дмитрий, ты совершил потрясающее количество ошибок общего характера, которые не только поставили под угрозу твой проект, но и привели к дестабилизации твоей психики. На месте boost'а могла быть любая другая сравнимая по сложности библиотека (в использовании которой у тебя минимум опыта), и у тебя были бы абсолютно такие же проблемы. Надеюсь, этот случай будет тебе хорошим уроком. В следующий раз будь поумней и научись оценивать риск своих решений перед тем, как бросаться в омут с головой.
В ваших словах, к сожалению, слишком много горькой правды. Но, как мне кажется, нужно выделить две составляющие.
1. Техническая. Не думаю, что нужно считать Boost образцом для подражания. Если у вас есть реализация генератора случайных чисел, которой вы хотите поделиться, то сделайте это. В том виде, в котором вам кажется это наиболее удобным. В виде итераторов. С документацией и примерами на русском языке. С минимальными затратами для себя. Не обязательно подстраиваться под Boost или отправлять вашу реализацию в Boost. Опубликуйте ее здесь. Имхо, здесь могут найтись люди, которые смогут перевести все что нужно на английский язык и отправить в Boost или просто помогут вам в развитии вашей реализации. С одим из моих проектов именно так и случилось, то же самое может случиться и с вашим. И, если ваша реализация окажется удобной и востребованой, то и она со временем может войти в Boost как еще один вариант (причем это смогут сделать ваши пользователи, не нагружая вас лишней работой).
2. Эмоциональная. Похоже, что ваши приключения с Boost-ом наложились еще на очень неблагоприятный эмоциональный фон. К сожалению, такое случается. Но падать духом не стоит.
Желаю удачи!
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
D_>Вы скАжете, пример надуман и volatile никто не использует? Разработчики сложных драйверов с Вами могут не согласиться. D_>Вы скАжете это легко исправить? Да. Но почему это до сих пор не исправлено если на составление примера ушло 40 человеко*минут, а библиотекой годами пользуются тысячи программистов? Не означает ли это что код не только не пытались доказать но и не пытались тестировать?
Ну с volatile тут довольно просто, STL не поддерживает volatile напрямую — вы не сможете создать volatile std::vector<..> и т.д.. Т.к. Boost является продолжением STL, их решение по крайней мере является последовательным.
D_>И ещё… Всё это bind хозяйство объявлено как бросающее любые исключения... Это мешает, но представляете что начнётся если они захотят это исправить? УУУ!!! D_>Полностью разобраться во всём коде bind чтобы найти другие ошибки я не могу и не хочу. Боюсь, что этого почти(или совсем?) никто не может.
bind сам по себе ничего не бросает, он может прокинуть только исключение из пользовательских классов. Это либа, которая формирует особый результирующий тип в зависимости от предоставляемых аргументов, т.е. по сути ничего не делает.
D_> Вы всё ещё считаете что boost::bind можно доверять?
Ну чему то в этой жизни всё таки нужно доверять
Свои велосипеды нужно сначала написать, потом тестировать. Готовый велосипед — только тестировать. Или вообще, просто ВЕРИТЬ. Изучайте документацию, читайте форумы, слушайте мнения людей, составляйте своё мнение о библиотеке. С готовым велосипедом вы всегда рискуете сэкономить время. Конечно, если ваш собственный вариант уже написан "как надо" — нет смысла искать что то ещё.
В конце концов, тот язык, с которым вы работаете, C++, точнее его компиляторы тоже имеют Большое количество багов, и багов кодогенерации в том числе.
Здравствуйте, Dmi_3, Вы писали:
D_>И ещё… Всё это bind хозяйство объявлено как бросающее любые исключения...
Это уже не по адресу, тут надо Страуструпа пинать
Спецификации исключений (СИ) разработаны таким образом, что использовать их по-человечески нереально просто.
Во-первых (и в-главных), они не являются частью типа функции.
Поэтому когда ты пишешь шаблон и в него попадает функция, то она оказывается без СИ, стало быть, ты ничего не можешь сделать, чтобы автоматически протащить СИ из вызываемой функции в вызывающую.
Т.е. написать bind так, чтобы он автоматически принимал СИ вызываемой функции, невозможно в принципе.
И вообще, если ты пишешь шаблоны — забудь про СИ.
Простой пример — какой должна быть СИ у std::for_each? Очевидно, комбинацией всех СИ, участвующих в реализации (т.е. создание промежуточного итератора, сама итерация, СИ функтора, СИ возможного копирования функтора и т.д.) Язык такое поддерживает? нет.
Во-вторых, то же самое с указателями на функции — СИ тоже теряются (ну это следствие первого пункта). Ближайший пример — qsort.
Ну а в-третьих, даже и без шаблонов и указателей они СИ не поддерживаются как надо (как в Джаве, скажем), т.е. компилятор вообще ничего не скажет на такой код:
(более того, про этом прямо сказано в стандарте, 15.4/10:
An implementation shall not reject an expression merely because when executed it throws or might throw an exception that the containing function does not allow.
)
Хотя проверить его и ругнуться — нефиг делать (только для полной поддержи этого надо, чтобы СИ были частью типа функции).
По-человечески это в С++ сделано только для взаимоотношений меджу СИ конструкторов/деструкторов базовых и производных классов.
Но, поскольку ты не можешь конвертировать функцию в конструктор класса, ты этим механизмом для реализации bind тоже воспользоваться не можешь.
Dmi_3 wrote: > > Я боялся, что это будет так воспринято… > Не надо делать из меня злого барабашку!
Не в обиду. Но ты начал за здравие, а кончил за упокой.
Видишь, как поменять реализацию в бусте и есть желание, вперед, это
открытые исходники, как никак, и автор — это всего-лишь автор.
З.Ы.
Лекцию по возрастной психологии читать не буду.
Dmi_3 wrote: > > > Вы скАжете, пример надуман и volatile никто не использует? Разработчики > *сложных* драйверов с Вами могут не согласиться. > Вы скАжете это легко исправить? Да. Но почему это до сих пор не > исправлено если на составление примера ушло 40 человеко*минут, а > библиотекой годами пользуются тысячи программистов?
Да потому что, тем кто этот bind использует данное не надо было. Тебе
понадобилось, нашел проблему и ее исправлени, исправь в бусте (или там
такое не возможно?)
> Не означает ли это > что код не только не пытались доказать но и не пытались тестировать?
Нет, не означает. (Логику пока еще никто не отменил)
> И ещё… Всё это bind хозяйство объявлено как бросающее любые > исключения... Это мешает, но представляете что начнётся если они захотят > это исправить? УУУ!!! > *Полностью* разобраться во всём коде bind чтобы найти другие ошибки я не > могу и не хочу. Боюсь, что этого почти(или совсем?) никто не может. Вы > всё ещё считаете что boost::bind можно доверять?
В тех рамках, что я использовал, все было отлично.
З.Ы. А доверядь, лично я не знаю ни одной библиотеки сейчас, которой
можно доверять абсолютно.
Аноним wrote: > > Дмитрий, ты совершил потрясающее количество ошибок общего характера, > которые не только поставили под угрозу твой проект, но и привели к > дестабилизации твоей психики. На месте boost'а могла быть любая другая > сравнимая по сложности библиотека (в использовании которой у тебя > минимум опыта), и у тебя были бы абсолютно такие же проблемы. Надеюсь, > этот случай будет тебе хорошим уроком. В следующий раз будь поумней и > научись оценивать риск своих решений перед тем, как бросаться в омут с > головой.
Киньте в меня камень, кто не делает ошибок. Не всегда (и чаще почти
никогда не возможно оченить риск). В частности, проект, что я сейчас
делаю, с целью уменьшения временных затрат, а максимально использовал
буст вместо собственных велосипедов. Использование велосипедов от буста
сэкономило мне около 3 человеко-недель рабочего времени (эти велосипеды
не идеальны, кое где надо учитывать баго-фичи, или мои ручки, странности
при сборке буста 2005-й студией). Так же будет и с любой другой
библиотекой. Просто надо учитывать, что все библиотеки пушутся людьми, а
людям свойственно делать ошибки.
Свои 5 копеек вставлю, можи кому пригодиться
boost 1_33_1
MSVC8
using namespace boost;
using namespace std;
typedef int32_t IntType;// аналогичное поведение для int8_t int16_t int64_t
uniform_int<IntType> ui(numeric_limits<IntType>::min(), numeric_limits<IntType>::max());
rand48 rng;
variate_generator<rand48, uniform_int<int32_t> > gen(rng, ui);
IntType x = gen(); //и вот тут мы влетаем в бесконечный цикл
В документации — ни слова. В рантайме — ни ассерта, ни ексепшена.
Если уменьшить диапазон хотя бы на 1 в любую сторону — работает.
Если заменить
typedef intXX_t IntType;
на
typedef uintXX_t IntType;
снова все работает !!!
Полез вовнутрь.
uniform_int.hpp
template<class IntType = int>
class uniform_int
{
public:
....
typedef IntType result_type;
....
explicit uniform_int(IntType min = 0, IntType max = 9)
: _min(min), _max(max)
{
......
assert(min <= max); //хха, типа "проверились". Как бы не так
init();
}
private:
result_type _min, _max, _range;
void init()
{
_range = _max - _min;// для знаковых типов с максимально возможными диапазонами тут получим.... конечно же -1 !!!!!!
}
......
};
дальше этот _range используется в расчетах, одним глазом посмотрел но не вникал особо.
Фикс простой, либо range сделать беззнаковым, либо ассерт заменить на range>=0
День угрохал, на свой код грешил !!!