Эффективные числовые массивы с множественной точностью

Numpy — это библиотека для эффективных числовых массивов.

mpmath при поддержке gmpy представляет собой библиотеку для эффективных чисел с множественной точностью.

Как их эффективно совместить? Или уже эффективно просто использовать массив Numpy с числами mpmath?

Нет смысла просить «эффективность, сравнимую с нативными числами с плавающей запятой», но вы можете попросить, чтобы она была близка к эффективности эквивалентного кода C (или, в противном случае, кода Java/C#). В частности, эффективный массив чисел с множественной точностью означает, что вы можете выполнять векторизованные операции и не искать, скажем, __add__ миллион раз в Global Interpreter.

Редактировать: Для близкого избирателя: мой вопрос касается эффективного способа их объединения. Ответ в возможном дубликате конкретно указывает на то, что наивный подход неэффективен.

Наличие массива numpy dtype=object может немного вводить в заблуждение, потому что мощный механизм numpy, который делает операции со стандартными dtypes сверхбыстрыми, теперь обрабатывается операторами python объекта по умолчанию, а это означает, что скорости не будет. больше


person leewz    schedule 27.06.2015    source источник
comment
возможно, связано: stackoverflow.com/questions/15307589 /   -  person cel    schedule 28.06.2015
comment
@cel Связано, но не актуально. Мой вопрос об эффективности, а в ответе упоминается неэффективность этого таким образом.   -  person leewz    schedule 04.07.2015
comment
Это более тесно связано с этим: stackoverflow.com/q/26600471/1461210   -  person ali_m    schedule 04.07.2015
comment
@ali_m Это еще один пример того, чего не следует делать, а в этом вопросе спрашивается, что делать.   -  person leewz    schedule 08.07.2015
comment
Да, конечно. Я не предполагал, что ваш вопрос был дубликатом - я просто думаю, что полезно ссылаться на другие связанные вопросы на SO для пользы других читателей.   -  person ali_m    schedule 08.07.2015


Ответы (3)


Отказ от ответственности: я поддерживаю gmpy2. Следующие тесты были выполнены с версией для разработки.

a и b — это списки из 1000 элементов, содержащие псевдослучайные значения gmpy2.mpfr с точностью 250 бит. Тест выполняет поэлементное умножение двух списков.

В первом тесте используется понимание списка:

%timeit [x*y for x,y in zip(a,b)]
1000 loops, best of 3: 322 µs per loop

Второй тест использует функцию map для выполнения цикла:

%timeit list(map(gmpy2.mul, a, b))
1000 loops, best of 3: 299 µs per loop

Третий тест — это реализация понимания списка на C:

%timeit vector2(a,b)
1000 loops, best of 3: 243 µs per loop

В третьей попытке vector2 пытается быть корректной функцией Python. Числовые типы обрабатываются с использованием правил преобразования типов gmpy2, выполняется проверка ошибок и т. д. Проверяются настройки контекста, по запросу создаются субнормальные числа, при необходимости возбуждаются исключения и т. д. Если вы проигнорируете все усовершенствования Python и примете все value уже gmpy2.mpfr, мне удалось сократить время с четвертой попытки:

%timeit vector2(a,b)
10000 loops, best of 3: 200 µs per loop

Четвертая версия не обеспечивает достаточной проверки ошибок, чтобы ее можно было использовать повсеместно, но возможна версия между третьей и четвертой попытками.

Можно уменьшить накладные расходы Python, но по мере увеличения точности эффективная экономия уменьшается.

person casevh    schedule 09.07.2015

Насколько мне известно, не существует библиотеки Python, которая поддерживает операции с векторизованными массивами для значений с множественной точностью. К сожалению, нет особенно эффективного способа использовать значения с множественной точностью в numpy ndarray, и крайне маловероятно, что когда-либо будет, поскольку значения с множественной точностью несовместимы с базовой моделью массива numpy.

Каждый элемент в ndarray numpy с плавающей запятой занимает одинаковое количество байтов, поэтому массив может быть представлен с точки зрения адреса памяти первого элемента, размеров и обычного смещения байтов (или шага) между последовательными элементами массива.

Эта схема имеет значительные преимущества в производительности — соседние элементы массива расположены по соседним адресам памяти, поэтому последовательное чтение/запись в массив выигрывает от лучшей локальности ссылок. Шаги также очень важны для удобства использования, поскольку они позволяют выполнять такие действия, как работа с представлениями одного и того же массива, без создания новых копий в памяти. Когда вы делаете x[::2], вы на самом деле просто удваиваете шаг по первой оси массива, так что вы обращаетесь ко всем остальным элементам.

Напротив, массив, содержащий несколько значений точности, должен содержать элементы неравного размера, поскольку значения с более высокой точностью будут занимать больше байтов, чем значения с низкой точностью. Таким образом, массив с множественной точностью не может регулярно перемещаться и теряет преимущества, упомянутые выше.

В дополнение к проблемам с построением массивов, даже простая арифметика для скаляров с множественной точностью, вероятно, будет намного медленнее, чем для скаляров с плавающей запятой. Почти все современные процессоры имеют специализированные блоки с плавающей запятой, тогда как арифметика с множественной точностью должна быть реализована программно, а не аппаратно.

Я подозреваю, что эти проблемы с производительностью могут быть большой частью причины, по которой еще нет библиотеки Python, которая обеспечивает искомую функциональность.

person ali_m    schedule 07.07.2015
comment
Не имеет смысла требовать такой же эффективности, как собственные числа с плавающей запятой, но вы можете попросить, чтобы она была близка к эффективности эквивалентного кода C (или, в противном случае, кода Java/C#). В частности, эффективный массив чисел с множественной точностью означает, что вы можете выполнять векторизованные операции и не искать, скажем, __add__ миллион раз в Global Interpreter. - person leewz; 08.07.2015
comment
Конечно, я ни в коем случае не утверждаю, что невозможно сделать что-то лучше, чем нынешняя ситуация, когда скаляры GMP индивидуально упакованы в Python. В своем вопросе вы специально упомянули объединение numpy и gmpy как способ повышения производительности, поэтому мой ответ был в основном направлен на объяснение, почему я думаю, что это вряд ли сработает. - person ali_m; 08.07.2015
comment
Мой вопрос был конкретно о том, как добиться большего успеха, чем наивное объединение Numpy и gmpy (т.е. заставить Numpy рассматривать их как обычные объекты Python). По-другому это можно сказать: как эффективнее всего их комбинировать? - person leewz; 08.07.2015
comment
К сожалению, просто нет более эффективного способа объединить numpy и gmpy, чем использование массива np.object (по сути, рассматривая скаляры gmpy как отдельные объекты Python). Чтобы добиться большего успеха с numpy, необходимо разработать совершенно новый тип контейнера массива (подумайте о матрицах scipy.sparse против np.ndarray). На самом деле вы не описали свой вариант использования, но, возможно, вам лучше всего написать собственное расширение на C/C++/Cython, напрямую вызывая библиотечные функции GMP. - person ali_m; 08.07.2015
comment
Я поддерживаю gmpy2. Я рассмотрел возможность добавления векторизованных версий некоторых функций gmpy2. Я сравнил понимание списка с использованием gmpy2.sin, map(sin, list) и gmpy2.sin(list), и не было большой разницы (около 10%). Я не пробовал использовать nd.array или базовые функции умножения/сложения. Если вы хотите посмотреть тестовый код, дайте мне знать. - person casevh; 08.07.2015

Текущий проект — qd, который сможет встраивать высокоточные числа в массивы Numpy, используя преимущества фиксированного размера в памяти своих значений. Прямо сейчас этот тип доступен для Numpy, но еще не как dtype; однако вы уже можете использовать его с объектом dtype.

(Если вы хотите увидеть, как будет выглядеть dtype, вы можете уже раскомментировать соответствующую строку для его компиляции с поддержкой Numpy; это должно работать для просмотра, но функция еще не реализована; следующий выпуск должен быть в сентябре или октябре.)

person Thomas Baruchel    schedule 31.07.2015