Быстрый код C для простых операций с фиксированной (многократной) точностью (добавить, div, mul, sub)?

Я писал некоторый код на cython для реализации операций с массивами с множественной точностью (в основном точечные произведения и инверсия матриц), которые я хочу использовать в python. Я использовал mpfr в качестве базовой библиотеки C, и, тестируя как на C, так и на Cython, я обнаружил, что mpfr (с точностью 200 бит) работает в 50-200 раз медленнее (в зависимости от операции), чем numpy (с машинной точностью). Я знаю, что mpfr работает очень быстро, но я все равно нахожу эти накладные расходы удивительно большими. Поскольку мои потребности очень ограничены (фиксированная точность, только основные операции, такие как добавление, множение и т. д.), мне было интересно, могу ли я просто вручную закодировать некоторые операции с множественной точностью (не обращая внимания на тщательное округление и т. д.). К сожалению, это требует довольно много работы, поэтому я надеялся найти несколько бесплатных фрагментов кода на C или ассемблере Intel для выполнения базовой арифметики с множественной точностью. Я был бы признателен за любые ссылки на последнее или причины, по которым я должен или не должен использовать этот подход.

ОБНОВЛЕНИЕ: я должен был упомянуть, что уже пробовал библиотеку QD, и она на самом деле (немного) медленнее, чем MPFR с аналогичной точностью (212 бит). Я предполагаю, что это должно быть связано с накладными расходами С++.


person user2153813    schedule 08.05.2013    source источник
comment
Сравнение 200-битной точности с машинной точностью — это сравнение яблок с апельсинами. Штраф к скорости в 50-200 раз мне не кажется чем-то необычным. Я сомневаюсь, что вы превзойдете его, даже если вы хотите поддерживать только простые операции, такие как умножение.   -  person MatthewD    schedule 08.05.2013
comment
Я не понимаю, почему некоторые пользователи голосуют за закрытие этого вопроса. Что с этим не так? ОП использует MPFR, но считает, что это больше, чем ему нужно. ОП очень ясно, что причина, по которой он / она ожидает, что для него можно найти быстрее, заключается в том, что он / она не использует все функции, предлагаемые MPFR. Как выясняется, другие уже почувствовали такую ​​же потребность, и даже существует по крайней мере одна готовая к использованию альтернатива.   -  person Pascal Cuoq    schedule 08.05.2013
comment
@MatthewD Для вычисления двойного сложения требуется несколько двойных сложений. Если доступна инструкция FMA (как в процессорах PowerPC и самых последних процессорах Intel/AMD для настольных ПК), умножение дважды-двойное также занимает всего несколько инструкций.   -  person Pascal Cuoq    schedule 08.05.2013
comment
Спасибо, Паскаль, именно так я и рассуждал. Я видел (в другом потоке SO), где кто-то дал некоторые инструкции по сборке CUDA для 128-битных операций, и они заявили, что это ~ 16 инструкций, поэтому я ожидаю такого порядка замедления, а не в 100-200 раз. Даже при использовании 120 бит я получаю значительное замедление (60-100x).   -  person user2153813    schedule 08.05.2013
comment
Попробуйте профилировать свою программу, чтобы узнать, какие функции MPFR используют больше всего времени.   -  person brian beuning    schedule 10.07.2013


Ответы (1)


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

Эти библиотеки требуют, чтобы базовое оборудование работало в точности в соответствии со стандартом IEEE 754. Они ломаются, если вычисления производятся с избыточной точностью. Если вы ориентируетесь на современный настольный процессор, убедитесь, что ваш компилятор генерирует инструкции SSE2 для вычислений с плавающей запятой. Если вы по какой-то причине застряли с инструкциями 8087, вам лучше использовать двойную расширенную библиотеку (числа представлены в виде суммы двух 80-битных чисел). В CRlibm есть один, который должен выйти без особых усилий.


В качестве альтернативы, возможно, стоит попробовать тип MPF GMP. Это может быть быстрее, поскольку он не пытается быть таким же хорошим, как MPFR, в соответствии с часто задаваемыми вопросами последнего.

person Pascal Cuoq    schedule 08.05.2013
comment
Я не изучал это внимательно, предполагая, что проблемы с округлением влияют только на младшие значащие биты? Если это так, то они в основном не имеют значения для меня, поскольку мне просто нужно повысить точность (помимо машинной точности), но я могу позволить себе иметь ошибки округления в наименее значащих битах. На самом деле я тестировал QD вместе с MPFR, и он всегда был медленнее (с MPFR на 212 бит). Это свидетельствует о впечатляющих оптимизациях MPFR (или накладных расходах C++ QD). - person user2153813; 08.05.2013
comment
MPF может дать небольшое улучшение, но при поиске в Google разница составляет, может быть, 20%, тогда как я ищу ускорение x3-6. Одна большая проблема заключается в том, что и MPFR, и GMP используют произвольную точность, поэтому внутренне сохраняют число как указатель на массив. Поскольку я могу исправить точность во время компиляции, я могу сохранить число внутри структуры. Это может быть очень важно при выполнении больших скалярных произведений, потому что весь доступ будет осуществляться в непрерывной памяти. Я хочу что-то вроде QD, но почему-то QD медленнее, чем MPFR. Так что сейчас я просто ищу какой-нибудь код на C, чтобы начать писать свой собственный. - person user2153813; 08.05.2013
comment
Чтобы пояснить вышеизложенное: мне нужен простой базовый код для оценки накладных расходов MPFR, чтобы определить, стоит ли писать мои собственные функции MP, которые я, кроме того, могу оптимизировать для доступа к массиву (т.е. точечные продукты MP). Я мог бы просто начать с алгоритма в файле qd.pdf, на который вы указали, но я надеялся начать с какого-то реального кода. Я проверю CRlibm. Спасибо за все предложения! - person user2153813; 08.05.2013