Длинная арифметика (Bignum arithmetic) c COM-интерфейсом и C API Functions для Excel на библиотеках MPIR. С/С++
Запись от bedvit размещена 26.03.2018 в 22:15
Показов 22881
Комментарии 160
Теперь часть библиотеки BedvitCOM. Проект основан на исходниках (на С++) библиотеки MPIR, Edition 3.0.0. (на основе библиотеки GMP) Полностью написан на С/С++. Скорость на порядок выше предыдущего решения. Реализовал два блока в проекте: 1.DLL c COM интерфейсом. Реализованы dual-интерфейсы с Automation-совместимыми типами данных, структур (поддержка как раннего вывязывания, так и позднего). Ранний предпочтительнее в части скорости (на 50% быстрее передача данных через СОМ-обертку). Реализовано два класса: класс целых чисел с арифметикой (BignumArithmeticInteger) и класс чисел с плавающей точкой (BignumArithmeticFloat). При создании экземпляра класса создается массив К числам можно обращаться по индексам (можно переменной присвоить индекс и работать с переменными, см. пример ниже) BignumArithmeticInteger (Bignum) увеличивается в памяти по мере расчета автоматически, перераспределяя память. BignumArithmeticFloat (Bignum), задается изначально, т.к. дробь может быть бесконечной (по умолчанию принимается минимальный размер - double). Размер чисел ничем не ограничен, кроме вашей оперативки. Регистрация COM реализовано как под админом, так и под пользователем (актуально в офисной части клиентов) Регистрация стандартная: Админ: Regsvr32 "FullName.DLL" !ПОМНИМ! В Win10 регистрация под правами админа: "правая кнопка" - "Пуск" -"Командная строка (администратор)" Пользователь: Regsvr32 /i /n "FullName.DLL" Удалить из реестра: Regsvr32 /u "FullName.DLL" Свойства и методы последней версии библиотеки COM (из .Help): Свойства и Методы BignumArithmeticInteger 1.Help(); HTML Справка (без параметров). 2.BSTR* StringBSTR = Bignum(BYTE Bignum, LONG BignumBase=10) = BSTR* StringBSTR ; Свойство. Принимает и возвращает BSTR* строку StringBSTR (задает число или возвращает значение). Bignum-индекс длинного числа в массиве (0-255). BignumBase-база длинного числа (от 2 до 36), по умолчанию = 10. 3.LONG Val = Sign(BYTE Bignum); Свойство. Возвращает знак длинного числа LONG Val.Возвращает 1 если Bignum > 0, 0 если Bignum = 0, и -1 если Bignum < 0. 4.LONG Val = Even(BYTE Bignum); Свойство. Определяет, является ли Bignum четное или нечетное. Возвращает 1 - Bignum четное, 0 - Bignum нечетное. 5.LONG Val = Compare(BYTE Bignum1, BYTE Bignum2); Метод. Сравнивает два длинных числа. Возвращает 1 если Bignum1 > Bignum2, 0 если Bignum1 = Bignum2, и -1 если Bignum1 < Bignum2. 6.BignumSet(BYTE Bignum, BSTR StringBSTR, LONG BignumBase=10); Метод. Задает число с параметрами аналогичными свойству Bignum() 7.Sum(BYTE BignumSet, BYTE Bignum1, BYTE Bignum2); Метод. Суммирует два длинных числа. BignumSet = Bignum1 + Bignum2 8.SumL(BYTE BignumSet, BYTE Bignum1, LONG_PTR LONG_PTR); Метод. Суммирует длинное число с обычным. BignumSet = Bignum1 + LONG_PTR(х64:LONG_PTR= LONGLONG, х32:LONG_PTR= LONG) 9.Abs(BYTE BignumSet, BYTE Bignum1); Метод. Возвращает модуль значения из Bignum1 в BignumSet. 10.Negate(BYTE BignumSet, BYTE Bignum1); Метод. Возвращает значение с противоположным знаком из Bignum1 в BignumSet. BignumSet = - Bignum1. 11.Subtract(BYTE BignumSet, BYTE Bignum1, BYTE Bignum2); Метод. Вычитает из одного длинного числа второе. BignumSet = Bignum1 - Bignum2 12.SubtractL(BYTE BignumSet, BYTE Bignum1, LONG_PTR LONG_PTR); Метод. Вычитает из длинного числа обычное. BignumSet = Bignum1 - LONG_PTR. 13.Multiply(BYTE BignumSet, BYTE Bignum1, BYTE Bignum2); Метод. Умножает одно длинное число на второе. BignumSet = Bignum1 * Bignum2. 14.MultiplyL(BYTE BignumSet, BYTE Bignum1, LONG_PTR LONG_PTR); Метод. Умножает длинное число на обычное. BignumSet = Bignum1 * LONG_PTR. 15.Divide(BYTE BignumQuotient, BYTE BignumRemainder, BYTE Bignum1, BYTE Bignum2); Метод. Делит одно длинное число на второе. При делении получаем частное в BignumQuotient, остаток от деления в BignumRemainder = Bignum1 / Bignum2. 16.DivideL(BYTE BignumQuotient, BYTE BignumRemainder, BYTE Bignum1, LONG_PTR LONG_PTR); Метод. Делит длинное число на обычное. При делении получаем частное в BignumQuotient, остаток от деления в BignumRemainder = Bignum1 / LONG_PTR. 17.Power(BYTE BignumSet, BYTE Bignum1, LONG_PTR LONG_PTR); Метод. Возводит в степень LONG_PTR длинное число Bignum1, результат возвращает в BignumSet. BignumSet = Bignum1 ^ LONG_PTR. 18.Clone(BYTE BignumSet, BYTE Bignum1); Метод. Копирует Bignum1 в BignumSet. BignumSet = Bignum1 19.RootRem(BYTE BignumRoot, BYTE BignumRemainder, BYTE Bignum1, LONG_PTR n_root); Метод. Извлекает корень n_root-степени из Bignum1. Целочисленный результат возвращает в BignumRoot, остаток в BignumRemainder = (n-th root)√ Bignum1. 20.Factorial(BYTE BignumSet, LONG n); Метод. Возвращает в BignumSet факториал n! 21.Fibonacci(BYTE BignumSet, LONG_PTR n); Метод. Возвращает в BignumSet число Фибоначи n. Fn+1 = Fn + Fn-1 22.LucNum(BYTE BignumSet, LONG_PTR n); Метод. Возвращает в BignumSet число Лукоса n. Ln+1 =Ln + Ln-1 23.FileSet(BYTE Bignum, BSTR StringBSTRFileName, LONG BignumBase=10); Метод. Загружает длинное число из файла (*.txt). Принимает BSTR* строку StringBSTRFileName в качестве полного пути и имени файла. Bignum-индекс длинного числа в массиве (0-255). BignumBase-база числа (от 2 до 36), по умолчанию = 10. 24.FileGet(BYTE Bignum, BSTR StringBSTRFileName, LONG BignumBase=10); Метод. Сохраняет длинное число в файл (*.txt). Принимает BSTR* строку StringBSTRFileName в качестве полного пути и имени файла. Bignum-индекс длинного числа в массиве (0-255). BignumBase-база числа (от 2 до 36), по умолчанию = 10. 25.Clear(LONG Bignum=-1); Метод. Освобождает память занятую длинным числом Bignum, или освобождает память занятую всеми числами при заданном параметре по умолчанию = -1. 26.LONG Val = BignumArraySize(); Метод. Возвращает количество чисел Bignum в созданном классе/массиве. Начиная с v2.0.0.0 (теперь массив чисел может быть произвольного размера, а не как ранее 256 чисел. Размер увеличиваться автоматически.) Свойства и Методы BignumArithmeticFloat 1.Help(); HTML Справка (без параметров). 2.LONG Val = SizeBits(BYTE Bignum, LONG_PTR* pVal) = .LONG Val; Свойство. Задает и возвращает размер длинного числа в БИТАХ LONG Val. Bignum-индекс длинного числа в массиве (0-255). 3.BSTR* String = Bignum(BYTE Bignum, LONG BignumBase=10, LONG_PTR Precision=0, BSTR Separator=”.”, VARIANT_BOOL Exponential=-1) = BSTR* String; Свойство. Принимает и возвращает BSTR* строку String (задает число или возвращает значение). Bignum-индекс длинного числа в массиве (0-255). BignumBase-база длинного числа (от 2 до 36), по умолчанию = 10. Precision – точность (кол-во цифр в числе), по умолчанию = 0 - максимальная (равна заданному размеру в битах). Separator – символ разделителя целой и дробной частей числа, по умолчанию точка(“.”). Exponential – по умолчанию =-1 экспоненциальная запись, 0 – десятичная (в разработке). (При парсинге строки в число, ожидаемая десятичная точка берется из текущей локали, на системах, предоставляющих localeconv). 4.LONG Val = Sign(BYTE Bignum); Свойство. Возвращает знак длинного числа LONG Val.Возвращает 1 если Bignum > 0, 0 если Bignum = 0, и -1 если Bignum < 0. 5.LONG Val = Compare(BYTE Bignum1, BYTE Bignum2); Метод. Сравнивает два длинных числа. Возвращает 1 если Bignum1 > Bignum2, 0 если Bignum1 = Bignum2, и -1 если Bignum1 < Bignum2. 6.SizeBitsSet(BYTE Bignum, LONG_PTR SizeBits); Метод. Задает размер длинного числа в БИТАХ LONG Val. 7.BignumSet(BYTE Bignum, BSTR StringBSTR, LONG BignumBase=10, BSTR Separator=”.”); Метод. Задает число с параметрами аналогичными свойству Bignum(). 8.Sum(BYTE BignumSet, BYTE Bignum1, BYTE Bignum2); Метод. Суммирует два длинных числа. BignumSet = Bignum1 + Bignum2 9.SumL(BYTE BignumSet, BYTE Bignum1, LONG_PTR LONG_PTR); Метод. Суммирует длинное число с обычным. BignumSet = Bignum1 + LONG_PTR(х64:LONG_PTR= LONGLONG, х32:LONG_PTR= LONG) 10.Abs(BYTE BignumSet, BYTE Bignum1); Метод. Возвращает модуль значения из Bignum1 в BignumSet. 11.Subtract(BYTE BignumSet, BYTE Bignum1, BYTE Bignum2); Метод. Вычитает из одного длинного числа второе. BignumSet = Bignum1 - Bignum2. 12.SubtractL(BYTE BignumSet, BYTE Bignum1, LONG_PTR LONG_PTR); Метод. Вычитает из длинного числа обычное. BignumSet = Bignum1 - LONG_PTR. 13.Multiply(BYTE BignumSet, BYTE Bignum1, BYTE Bignum2); Метод. Умножает одно длинное число на второе. BignumSet = Bignum1 * Bignum2. 14.MultiplyL(BYTE BignumSet, BYTE Bignum1, LONG_PTR LONG_PTR); Метод. Умножает длинное число на обычное. BignumSet = Bignum1 * LONG_PTR. 15.Divide(BYTE BignumSet, BYTE Bignum1, BYTE Bignum2); Метод. Делит одно длинное число на второе. BignumSet = Bignum1 / Bignum2 16.DivideL(BYTE BignumSet, BYTE Bignum1, LONG_PTR LONG_PTR); Метод. Делит длинное число на обычное. BignumSet = Bignum1 / LONG_PTR. 17.Root(BYTE BignumSet, BYTE Bignum1); Метод. Извлекает квадратный корень из Bignum1. Результат возвращает в BignumSet. BignumSet = √ Bignum1. 18.Negate(BYTE BignumSet, BYTE Bignum1); Метод. Возвращает значение с противоположным знаком из Bignum1 в BignumSet. BignumSet = - Bignum1. 19.Power(BYTE BignumSet, BYTE Bignum1, LONG_PTR LONG_PTR); Метод. Возводит в степень LONG_PTR длинное число Bignum1, результат возвращает в BignumSet. BignumSet = Bignum1 ^ LONG_PTR. 20.Clone(BYTE BignumSet, BYTE Bignum1); Метод. Копирует Bignum1 в BignumSet. BignumSet = Bignum1 21.FileSet(BYTE Bignum, BSTR StringBSTRFileName, LONG BignumBase=10); Метод. Загружает длинное число из файла (*.txt). Принимает BSTR* строку StringBSTRFileName в качестве полного пути и имени файла. Bignum-индекс длинного числа в массиве (0-255). BignumBase-база числа (от 2 до 36), по умолчанию = 10. (При парсинге строки в число, ожидаемая десятичная точка берется из текущей локали, на системах, предоставляющих localeconv). 22.FileGet(BYTE Bignum, BSTR StringBSTRFileName, LONG BignumBase=10, LONG_PTR Precision=0); Метод. Сохраняет длинное число в файл (*.txt). Принимает BSTR* строку StringBSTRFileName в качестве полного пути и имени файла. Bignum-индекс длинного числа в массиве (0-255). BignumBase-база числа (от 2 до 36), по умолчанию = 10. Precision – точность (кол-во цифр в числе), по умолчанию = 0 - максимальная (равна заданному размеру в битах). 23.Clear(LONG Bignum=-1); Метод. Освобождает память занятую длинным числом Bignum, или освобождает память занятую всеми числами при заданном параметре по умолчанию = -1 24.LONG Val = BignumArraySize(); Метод. Возвращает количество чисел Bignum в созданном классе/массиве. Начиная с v2.0.0.0 (теперь массив чисел может быть произвольного размера, а не как ранее 256 чисел. Размер увеличиваться автоматически.) 25.BSTR* String = GetToBignumInt(LONG Bignum, LONG BignumBase=10); Метод. Преобразовать Bignum из Float в Integer и вывести. ВАЖНО! преобразование происходит с заданной ранее точностью в битах для Float (SizeBitsSet). Без округлений, отбрасывается дробная часть. Будьте внимательнее в таких преобразованиях. Начиная с v2.0.0.0. 2.XLL для Excel с C API функциями. Добавил базовый набор. Будет потребность в дополнительных - добавлю по запросу. Для функций создано два раздела в стандартном списке с названиями классов в COM (+один общий). Функции поддерживают многопоточные расчеты. Работа с функциями как с обычными (различий нет). Обычные написаны тоже на С/С++ под C API. Список C API - функций в Excel: 1.BedvitXLLBignumArithmeticInteger - функции для работы с длинными целыми числами. Функции: 1.1 SumInteger() - сложение двух длинных/обычных целых чисел 1.2 SubtractInteger() - вычитание двух длинных/обычных целых чисел 1.3 MultiplyInteger() - умножение двух длинных/обычных целых чисел 1.4 DivideInteger() - деление двух длинных/обычных целых чисел - Неполное частное 1.5 ModInteger() - деление двух длинных/обычных целых чисел - Остаток от деления 1.6 PowerInteger() - возведение в степень длинного/обычного целого числа 1.7 ConvertBaseInteger() - конвертирование целого числа (строки) из одной базы в другую (от 2 до 36). 1.8 FactorialInteger() - факториал задаваемого числа. 2.XLLBignumArithmeticFloat - функции для работы с длинными дробными числами. Функции: 2.1 SumFloat() - сложение двух длинных/обычных чисел с плавающей точкой 2.2 SubtractFloat() - вычитание двух длинных/обычных чисел с плавающей точкой 2.3 MultiplyFloat() - умножение двух длинных/обычных чисел с плавающей точкой 2.4 DivideFloat() - деление двух длинных/обычных чисел с плавающей точкой 2.5 PowerFloat() - возведение в степень длинного/обычного числа 2.6 RootFloat() - извлечение квадратного корня из длинного/обычного числа Так же в XLL ресурсы упакована COM.DLL (первый блок проекта), распаковывается и устанавливается под пользователем - автоматом. Поэтому открываем XLL или устанавливаем как надстройку - готово (ничего регистрировать не надо). Пишем код в VBA и работаем. Советую раннее связывание. Видим свойства и методы объекта. Оные можно посмотреть и в диспетчере объектов (см. рис.) Т.е. при открытии XLL можно работать как с новыми C API функциями, так и с COM.DLL через VBA. Примеры см. ниже. Ресурсы: MPIR library, Edition 3.0.0 (freely distributable librarys) http://mpir.org/ + my code written in C / C ++ ©2018, BedvitCOM, BedvitXLL License: Freely distributable library Где тестировалось: Пример №1 (Расширенный): VBA - через индексы, раннее+позднее связывание:
Пример №3 (Простой): VBA - через буквенное обозначение, позднее связывание
Пример №4: 1С - через буквенное обозначение
26/03/2018 - Версия 0.0.0.1 под x64. 05/04/2018 - Новая версия BedvitCOM v.1.0.0.2 и BedvitXLL v.1.0.0.2 Изменения: 1. Изменен порядок аргументов в методе "BignumSet" (теперь, как во всех других методах, номер длинного числа в массиве - стоит первым аргументом), см.под спойлером Кликните здесь для просмотра всего текста
Ранее было так:
I.BignumSet "6546414654564" , 1 теперь так: I.BignumSet 1, "6546414654564" 2. Добавлены новые методы в два класса (запись длинного числа в файл .txt и чтение из файла) .FileSet, .FileGet (описание в .Help и ниже) 3. Собраны библиотеки COM и XLL в 32-разрядной версии (с корректным Help-ом, описанием интерфейса). 24/04/2018 - Новая версия BedvitCOM v.1.0.0.3 и BedvitXLL v.1.0.0.3 (поддержка х32 и х64) 1. Добавлены новые функции в два класса библиотеки COM - арифметика длинных чисел с обычными, т.е. теперь можно совершать арифметические действия длинных чисел с обычными. 2. Добавлен механизм очистки/освобождения памяти как для одного числа, так и для класса/объекта в целом. 3. Сделано новое описание для всех свойств и методов двух классов на русском языке в справке (см. под спойлером и в .HELP) 4. XLL теперь удаляет данные из реестра (COM.DLL) под пользователем при закрытии надстройки. 29/04/2022 - Новая версия BedvitCOM v.2.0.0.0 1.Класс/массив Bignum теперь может быть любого размера, а не как ранее 256 чисел. Увеличение размера происходит автоматом, в зависимости от последнего задаваемого индекса числа в массиве. 2.В связи с этим добавлен метод BignumArraySize() - Возвращает количество чисел Bignum в созданном классе/массиве. 3.Добавлено преобразование Bignum из Float в Integer (обратное преобразование было возможно и ранее). Метод GetToBignumInt(LONG Bignum, LONG BignumBase=10). ВАЖНО! преобразование происходит с заданной ранее точностью в битах для Float (SizeBitsSet). Без округлений, отбрасывается дробная часть. Будьте внимательнее в таких преобразованиях. 4.Исправлен баг в выделением памяти для разных экземпляров одного и того же класса. Теперь для каждого экземпляра - свой участок памяти. 5.Теперь деструктор класса сам очищает память (при удалении класса или завершении процедуры в VBA). Методы Clear теперь нужны только там, где нужно освободить память в действующим классе. При завершении процедуры их писать не обязательно (для VB, и для языков, где класс уничтожается при завершении процедуры - запуская деструктор). |
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 160
Комментарии
-
Запись от Avazart размещена 31.03.2018 в 12:49 -
Запись от bedvit размещена 31.03.2018 в 23:56 -
Запись от Avazart размещена 01.04.2018 в 15:16 -
Запись от bedvit размещена 01.04.2018 в 22:25 -
Запись от Avazart размещена 01.04.2018 в 23:20 -
Сообщение от Avazart
Сообщение от Avazart
Сообщение от Avazart
Запись от The trick размещена 01.04.2018 в 23:20 -
Запись от bedvit размещена 02.04.2018 в 01:08 -
Еще раз не MPIR, а GMP - да там структруры, но во первых должны быть средства для реализации этих структур на VBA, во вторых их можно обвернуть в Си ф-ции т.е сделать свою прослойку скрыв структуры за void*
Тоже самое со строками.
https://msdn.microsoft.com/en-... 87915.aspxЗапись от Avazart размещена 02.04.2018 в 10:21 -
Запись от bedvit размещена 02.04.2018 в 10:54 -
Про структуры:
Итд читаем про строки в "Variant and String Arguments"PureBasic 1 2 3 4 5
Type VB_User_Type i As Integer d As Double s As String End Type
https://msdn.microsoft.com/en-... 87915.aspxЗапись от Avazart размещена 02.04.2018 в 11:03 -
По строкам вы пишите про структуру BSTR, этот тип не обязательно будет строкой для других компиляторов . Для этого придумали Automation-типы, в которых BSTR является стандартом. По структурам я не понимаю для чего изобретать велосипед в каждом языке, если можно просто получить объект и им пользоваться.
Вы считаете, ваш пример (с оберткой структур) проще реализовать конечному пользователю на VBA, чем пользоваться одной функцией - CreateObject()?
Что у вас вызывает затруднения в com.dll?Запись от bedvit размещена 02.04.2018 в 13:05 -
Запись от Avazart размещена 02.04.2018 в 16:06 -
Сообщение от Avazart
Сообщение от Avazart
Запись от The trick размещена 02.04.2018 в 16:35 -
Avazart, поясните чем проще пользователю делать обвязку для структур и писать declare для функций, чем зарегистировать библиотеку одной строкой в командной строке win, создать объект второй в коде VBA (к примеру) и пользоваться ООП (свойствами и методами)?
Можно и без регистрации (надо подумать о раннем связывании), но в чем сложность нажать WIN+R вставить команду "Regsvr32 /i /n "FulName.DLL"" нажать enter и идти спокойно программировать.
в xll вообще автоматом все регистрируется. открывай и работай.Запись от bedvit размещена 02.04.2018 в 17:19 -
Запись от Avazart размещена 02.04.2018 в 18:07 -
Сообщение от Avazart
Сообщение от Avazart
Запись от The trick размещена 02.04.2018 в 18:28 -
Сообщение от Avazart
1. строка входящая в начале расчета,
2. исходящая в конце (затратные операции + преобразование из BSTR в char* и обратно, но происходящая всего два раза за время работы длинного числа),
3. числовые типы для функций (номер длинного числа в массиве и числовые аргумены для функций MPIR в dll)
4. собственно сама обертка - вызов методов и свойств объекта из VBA(не знаю насколько затратная).Запись от bedvit размещена 02.04.2018 в 19:08 -
Запись от bedvit размещена 02.04.2018 в 19:11 -
Запись от Avazart размещена 02.04.2018 в 20:03 -
Сообщение от Avazart
Запись от The trick размещена 02.04.2018 в 21:01