Thursday, August 18, 2011

map::iterator: избавляемся от ->first и ->second

Решил тут в процессе изучения С++ старый свой код порефакторить. Попался такой вот кусочек:
typedef unordered_map<int,double> ColumnMap;
typedef ColumnMap::const_iterator ColumnMapIter;
...
for(ColumnMapIter it = row->begin(); it != row->end(); ++it) {
    ColumnMap *tmp = other -> rlist[it -> first];
    ColumnMapIter it_col = tmp -> find(col);
    if (it_col != tmp->end()) {
        val += (it -> second ) * (it_col -> second);
    }
}
Согласитесь, что в этих first и second чёрт ногу сломит. Однако в плюсах имеется такая редкоиспользуемая фича, как указатели на члены класса. Почитать про них можно, например, здесь: http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=142
С их-то помощью и можно заменить first и second на что-нибудь более понятное.

Смотрите:
typedef unordered_map<int,double> ColumnMap;
typedef ColumnMap::const_iterator ColumnMapIter;
...
typedef ColumnMap::value_type ColumnMapPair;
const ColumnMapPair::first_type ColumnMapPair::* column = &ColumnMapPair::first;
ColumnMapPair::second_type ColumnMapPair::* value = &ColumnMapPair::second;
...
for(ColumnMapIter it = row->begin(); it != row->end(); ++it) {
    ColumnMap *tmp = other -> rlist[*it.*column];
    ColumnMapIter it_col = tmp -> find(col);
    if (it_col != tmp->end()) {
        val += (*it.*value) * (*it_col.*value);
    }
}

Sunday, August 14, 2011

занятненький подкаст

Рыская по Википедии, случайно наткнулся на skepticality.com. На данный момент это официальный подкаст журнала "Skeptic", выпускаемого организацией "The Skeptics Society".

Сейчас на сайте выложено 160+ выпусков на самые разнообразные темы. Между прочим, каждый из них снабжён пачкой ссылок для заинтересовавшихся затронутыми в нём топиками.
Короче, рекомендую всем желающим объективно воспринимать реальность :-)

Tuesday, July 5, 2011

[oh shi~] теория музыки

Интересующимся сабжем советую погуглить "music theory Z/12Z". Можно найти довольно убойную муть.

Вот, например, с моноидами аффинных отображений, их генераторами и тому подобным:
www.math.uchicago.edu/~may/VIGRE/VIGRE2007/REUPapers/FINALFULL/Bartlett.pdf

Sunday, June 12, 2011

[жж] ностальгия

Знаете что? Хочу, чтоб интернет был таким, как 5 лет назад.

Во-первых, сегодня он таков, что знакомиться с кем-либо по сети совершенно не хочется. Раньше на момент начала общения о собеседнике было неизвестно ничего, кроме его ника и, быть может, аватарки, пары фотографий да истории сообщений на форуме. Сейчас же почти каждый зарегистрирован "вконтакте". И хрен бы с ним, если бы просто зарегистрирован — с некоторых пор какого-то чёрта всё это проиндексировано поисковиками и даже регистрации не нужно, чтобы узнать инфу о человеке: загуглил имя, фамилию и ещё что-нибудь — вот тебе и фотка, и интересы, и откуда родом, и где учится (ну, разумеется, если параноиков типа меня в расчёт не брать). А теперь вот ещё и френдлисты открыли. Это вообще, на мой взгляд, диковато: "скажи мне, кто твои друзья, и я скажу, кто ты". (Правда, концентрация истинных друзей там колеблется от 5 до 50 процентов в зависимости от политики френдования. Но общее представление всё же заиметь можно.) В итоге теряется весь интерес: ведь блин, вся суть знакомства в _постепенности_ раскрытия одной личности перед другой. А со всеми этими грёбаными социальными сетями можно безо всякого знакомства сделать вывод о том, что человек — кусок идиота (причём вывод вполне может оказаться неправильным); заранее узнать о наличии общих знакомых, вкусах в плане музыки и кино; о том, куда субъект ездил отдыхать этим летом и так далее. Ну что за скукота?

Во-вторых, в техническом аспекте тоже творится кошмар: как подумаешь, что весь трафик этого идиотского "вконтактика" идёт по голому HTTP безо всяких SSL — жуть берёт. Средневековье какое-то. А ведь у FaceBook HTTPS-доступ есть, между прочим. Но у нас-то Россия: как обычно, отстаём в техническом плане. И почти всем пофиг — народ и аббревиатуры "HTTP" в большинстве своём не слышал. А уж криптографические протоколы — так это и вовсе какая-то неведомая ёбаная хуйня, кому оно надо?
И, блеать, не думайте, что это всё чисто теория. Вот, нате вам видео, как чел снифать кукисы в public Wi-Fi сети: http://www.youtube.com/watch?v=jsFODcwiRFY

Так что IRC/ICQ во всех отношениях лучше были. А ещё Jabber и Skype есть... Но народ же не осилит. Да и надо же куда-то выкладывать в большинстве своём бездарные фоточки и псевдоумные цитаты, чтоб их кто-нибудь "лайкнул", подняв ЧСВ автору. Буэээээ...

Wednesday, June 1, 2011

Ruby, 64-bit, Bignum и все-все-все

Итак, свершилось! Переехал я на 64 бита, благо Intel Atom N450 их поддерживает. Вроде как всё летает просто: ещё бы, целых 8 новых регистров задействуются! Библиотеки для длинной арифметики, как и полагается, ускорились в два раза.

Ну так вот, попытался я и интерпретатор Ruby на 64 бита пересадить. Точнее, его Bignum-ы. По умолчанию никакой поддержки 64-битовых целых в качестве digit-ов почему-то не предусмотрено. «Ну фиг ли», — решил я, «тоже мне проблема», — добавил в include/ruby/defines.h несколько строчек и пересобрал:
#if defined(__x86_64__)
# define BDIGIT unsigned long
# define SIZEOF_BDIGITS SIZEOF_LONG
# define BDIGIT_DBL __uint128_t
# define BDIGIT_DBL_SIGNED __int128_t
# define PRI_BDIGIT_PREFIX ""
# define PRI_BDIGIT_DBL_PREFIX ""
#elif ...

Ну ладно, даже собралось. Правда, по поводу random.c в процессе появилось несколько варнингов — деление на ноль, например :-))) Хрень в том, что там есть такая строчка:
#define DIGSPERINT (SIZEOF_INT/SIZEOF_BDIGITS)
Почему-то предполагается, что эта шняга всегда не меньше единицы, и на неё спокойно делят. Только вот в нашем случае 4 / 8 = 0, хыхых. Надо будет поковырять rb_rand_dump и rb_rand_load.
Впрочем, с генерацией псевдорандомных длинных чисел разобраться удалось (функция limited_big_rand):
...
#elif SIZEOF_BDIGITS == 4     
# define BIG_GET32(big,i) (RBIGNUM_DIGITS(big)[(i)])
# define BIG_SET32(big,i,d) (RBIGNUM_DIGITS(big)[(i)] = (d))
#else  
    /* SIZEOF_BDIGITS == 8 */ 
# define BIG_GET32(big,i) \   
    ((i) & 1 ? \              
     RBIGNUM_DIGITS(big)[(i)>>1] >> 32 : \
     RBIGNUM_DIGITS(big)[(i)>>1] & 0xffffffff )
# define BIG_SET32(big,i,d) \ 
    do { \
        if ((i) & 1) \        
        RBIGNUM_DIGITS(big)[(i)>>1] = \
        ((d) << 32) + (RBIGNUM_DIGITS(big)[(i)>>1] & 0xffffffff); \
        else \
        RBIGNUM_DIGITS(big)[(i)>>1] &= 0xffffffff00000000ULL, \
        RBIGNUM_DIGITS(big)[(i)>>1] += (d); \
    } while(0);               
#endif 

Был и ещё один глюк: строки в числа преобразовывались верно, а вот наоборот — нифига. Чтобы пофиксить, добавил в функции rb_big2str0 (bignum.c) строки
#if SIZEOF_BDIGITS > 4
    hbase *= hbase;
#endif
сразу после такого же сравнения с двойкой.

Пришлось также вручную подправить значение BASE в ext/bigdecimal/bigdecimal.h: в противном случае возникало переполнение. BASE должно равняться 10**9, а не 10**19. Было следующее:
...
#elif SIZEOF_BDIGITS >= 8
# define RMPD_COMPONENT_FIGURES 19
# define RMPD_BASE ((BDIGIT)10000000000000000000U)
#elif SIZEOF_BDIGITS >= 4
# define RMPD_COMPONENT_FIGURES 9
# define RMPD_BASE ((BDIGIT)1000000000U)
#elif ...
Вообще говоря, эта хрень только в trunk-е появилась, и здравая логика подсказывает, что во избежание переполнения здесь везде надо '>=' заменить на '>'. (По крайней мере, в старых стабильных версиях на 32-битных машинах BASE было равно 10000).

Ну по крайней мере арифметические операции, ради которых всё затевалось, вроде работают. И скорость числодробления действительно круто возросла: взять хотя бы тот же 1000000! — одна и та же версия ruby с 32-битными digit-ами считает его за 57 секунд, а с 64-битными — всего за 19. Жесть. То бишь действительно удвоение скорости засчёт бóльшей разрядности + дополнительный прирост засчёт использования полного набора регистров (по крайней мере мне кажется, что это основные факторы).

Monday, May 30, 2011

охренительно

Ради любопытства слил сегодня свежий ruby из trunk-а, скомпилял. С удивлением обнаружил, что в 1.9.3dev (rev. 31825) наконец-то заимплементили Тоом-Кука! Не FFT, конечно, но всё же прогресс налицо. (Написать, что ли, летом Шёнхаге-Штрассена? — за два месяца можно управиться =)...)
Произошёл сий коммит, кстати говоря, совсем недавно — 22 мая (rev. 31695).
Да и в целом скорость повыше, чем у 1.9.2-p336, на котором я сидел до этого.
Так что надо почаще обновляться, пожалуй =)

Но охренительно не только это. Есть такая замечательная вещь, как Intel Vtune Amplifier — вроде как самый ништяковый профайлер на сегодняшний день (по крайней мере, для Intel-овских процессоров). Цены на лицензионный продукт просто зверские (900$). Но если побродить по сайту, ВНЕЗАПНО оказывается, что "developers who are developing software on their own time without compensation" могут скачать некоммерческую версию вообще на халяву! (правда, есть один нюанс: только для linux; причём у меня установка превратилась в долгое ковыряние с компиляцией их драйверов; впрочем, для убунты вроде поставляется с уже скомпилированными дровами).

Ну и про ещё одну забавную штуку напишу, коль скоро она соответствует заголовку: оказывается, есть гомеоморфный тору семигранник, у которого каждая грань соседствует со всеми остальными. У кого руки чешутся — можете даже склеить, там внизу есть ссылочка на pdf с развёрткой. Получите конструктивную (в наибуквальнейшем смысле :-)) оценку снизу хроматического числа тора.

Saturday, May 14, 2011

О вычислении факториала: часть 2

Когда-то я писал о наиболее продвинутом на сегодняшний день методе вычисления факториала. Сегодня, читая Википедию, наткнулся и на ссылку с оценкой сложности этого метода: держите.

Статью (пока что) не читал. Результат, который там приводится, таков:
временная сложность составляет O(\log \log n \cdot M(n \log n)), где M(n \log n) — временная сложность перемножения двух чисел длины n \log n.
(Для сравнения: в случае разбиения произведения на два произведения примерно равной длины сложность отличается тем, что вместо log(log(n)) в формуле стоит просто log(n). В случае же тупого перемножения последовательных чисел сложность равна O(n² log n).)

Таким образом, в случае использования метода Шёнхаге-Штрассена сложность — O(n\,\cdot\,(\log n \log \log n)^2)

В случае же использования метода Карацубы, для которого M(n) = n^{\log_23}, сложность, соответственно, — O((n \log n)^{\log_23}\,\cdot\,\log \log n)

Даже проверил из любопытства: (кривая - график f(N) = 1.532e-10 * (N log N)log23 * log log N)