Страницы: 1 2 След.
RSS
Перевод числа с одной системы счисления в другую - VBA, Сложности перевода больших чисел
 
Всем привет! Создал тему для любителей нестандартных решений, таких как я) Написал функцию перевода из любой системы счисления в любую другую (с основанием от 2 до 36). Столкнулся со сложностями перевода больших чисел. К примеру из Десятичной (dec) в Шестнадцатеричную (hex) максимально возможное десятичное число, которое удалось перевести в Шестнадцатеричную - "79228162514264337593543950335" ("FFFFFFFFFFFFFFFFFFFFFFFF"). Из спортивного интереса, кто готов поучаствовать в составлении алгоритма для обработки больших чисел? Возможно ли это?
«Бритва Оккама» или «Принцип Калашникова»?
 
А практический смысл в этом есть? или чисто спортивный интерес?
 
Михаил С.,  больше спортивный )
Итогом данной темы будет лучшая универсальная функция перевод числа с одной системы счисления в другую в Excel, т.к. стандартные функции "слабее" почти в 3 раза. Чуть позже выложу свой вариант, пусть будет на нашем форуме, для истории и для всех пользователей.
«Бритва Оккама» или «Принцип Калашникова»?
 
У половины форумчан наверняка есть свои надстройки, никто не хочет пополнить коллекцию или сравнить алгоритмы? :)
«Бритва Оккама» или «Принцип Калашникова»?
 
Числа до 10^1000 Вас устроят?
Пример перевода из одной системы в другую через десятичную на базе длинной арифметики
Не уверен, что корректно реализовал - проверяйте
Изменено: MCH - 01.04.2016 12:59:37 (Добавил примеров)
 
http://msoffice-prowork.com/perevod-chisel-iz-raznykh-sistem-schisleniya-s-pomoshhyu-ms-excel/
у меня простая версия Экселя, в ней нет кнопки "Прочитать мысли и сгенерировать файл пример"
 
Фродо, да знаю. В районе 10 знаков ест, дальше всё...
Изменено: bedvit - 31.03.2016 19:46:30
«Бритва Оккама» или «Принцип Калашникова»?
 
MCH, ух..., здорово, буду разбираться. У меня не столь сложная, довольна простая функция, выкладываю:
Код
Function Бит(Число As String, ОснованиеЧисла As Byte, ОснованиеРезультата As Byte) As String
 Dim dec, m As Byte, i As Byte
 If ОснованиеЧисла < 2 Or ОснованиеЧисла > 36 Or ОснованиеРезультата < 2 Or ОснованиеРезультата > 36 Then Exit Function
 Число = UCase(Число)
 For i = 1 To Len(Число)
   m = Asc(Mid$(Число, i, 1)) - 48
   If m > 9 Then m = m - 7
   dec = CDec(dec * ОснованиеЧисла + m) 'max Decimal = "79228162514264337593543950335"
 Next i
 Do
   m = dec - (ОснованиеРезультата * Fix(dec / ОснованиеРезультата)) + 48
   If m > 57 Then m = m + 7
   dec = Fix(dec / ОснованиеРезультата)
   Бит = Chr$(m) & Бит
 Loop While dec > 0
End Function
«Бритва Оккама» или «Принцип Калашникова»?
 
Тоже через десятичную, на базе Decimal, в одной обертке.
«Бритва Оккама» или «Принцип Калашникова»?
 
MCH, посмотрел файл...впечатляет.... :idea:
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
bedvit написал:
У меня не столь сложная, довольна простая функция, выкладываю:
Ну так и у меня сами функции перевода очень простые (алгоритм перевода полностью идентичен)
Просто арифметические действия (умножение/деление/сложение/вычитание/остаток от деления) с длинными числами реализованы отдельными функциями
 
MCH, да, сейчас, как раз и смотрю логику. Через собственный тип это здорово. Но к нему нужны и арифметические операции описывать, с самим собой и стандартными типами (кстати о чем вы и пишите). Плюс система счисления в Вашем типе (насколько я успел разобрать) по основанию 10000. Пока сложновато переключиться, но "весч" нужная, копну её пожалуй посерьезнее.
Кстати нашел похожие Ваши работы здесь , а здесь от ikki. Кстати интересен ответ, можно ли создать алгоритм, в котором не будет промежуточного вычислений по основанию 10, а сразу в нужное основание. Ведь в этом моменте и узкое горлышко.
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
bedvit написал:
Кстати нашел похожие Ваши работы
Этот код я как раз и переделал под текущую задачу.
Можете еще здесь посмотреть. Правда реализация на FreeBasic, но работает достаточно быстро и основание счета уже не 10000 а 1000000000
Цитата
bedvit написал:
система счисления в Вашем типе (насколько я успел разобрать) по основанию 10000
Да это сделано для ускорения расчетов и выделения меньше памяти для чисел. Тип Long спокойно позволяет хранить и обрабатывать числа 9999*9999
Цитата
bedvit написал:
можно ли создать алгоритм, в котором не будет промежуточного вычислений по основанию 10, а сразу в нужное основание
Вся обычная математика в VBA реализована через десятичную систему поэтому можно легко умножать/делить/складывать/вычитать только десятичные числа.
Еще проще только двоичная система, которая реализована аппаратно.
Поэтому (IMHO) все остальные системы счисления можно реализовать только через преобразование в десятичную

Если Вам нужно считать длинные числа например в 16-ричной системе, то можно использовать опубликованный мной пример, где вместо основания 10000 можно использовать основание 16, это позволит не переделывая функции производить вычисления, а преобразование массива в текстовую строку будет сделать просто.
Изменено: MCH - 01.04.2016 13:49:00
 
MCH, спасибо за материалы и информацию, тема заинтересовала. А почему
Цитата
MCH написал: обрабатывать числа 9999*9999
Для чего умножение? В чем отличие от FreeBasic: CONST mBase AS LongInt = 1000000000 ? Размерность LongInt такая же, как и Long (х32)?
Изменено: bedvit - 01.04.2016 15:37:29
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
bedvit написал: Для чего умножение?
Хранение числа производится в виде массива, где каждая цифра - элемент массива.
Основание 10000 взято потому, что из него очень легко перевести в разряд 10 без вычислительных манипуляций, а просто преобразование из числа в текст
Тип Long - 4х байтное целое число от -2млрд до +2млрд, максимальный элемент в массиве - 9999 (если берем основание 10000), возможная операция - умножение двух максимальных элементов. Операция 9999*9999 - не вызовет переполнения в переменной типа Long, поэтому максимальное основание - 10000
Основание 100000 уже может вызвать переполнение при вычислениях.

в FreeBasic (и не только в нем) есть тип LongInt - 8ми байтовое целое число (от -9E18 до +9E18), поэтому разумнее брать именно его для хранения информации и вычислений, при этом основание числа можно взять 9-ти значным, не вызывая переполнения при вычислениях.
 
MCH, Видимо FreeBasic работает в х64 среде, раз позволяет такую адресацию к памяти. Кстати в Excel (x64), думаю Вы знаете про тип LongLong. Вот когда все перейдут на х64, можно будет и им пользоваться, а так приходится учитывать совместимость со старыми системами. + совместимость VBA7.
Подумываю отказаться от поддержки версий VBA ниже 7. Редко уже у кого Excel ниже 2010.
В таком случае LongPtr и погнал (с некоторыми исключениями).

Для справки (форумчанам):
LongLong ( LongLong целое) переменные сохраняются как числа 64-бит (8 байт) в диапазоне значений от -9,223,372,036,854,775,808 до 9,223,372,036,854,775,807. Символ объявления типа для LONGLONG является каретка (^).
Изменено: bedvit - 01.04.2016 20:15:51
«Бритва Оккама» или «Принцип Калашникова»?
 
Можно воспользоватся Decimal, там аж 29 значащих цифр, но этот тип не "родной" VBA, и пользоваться CDec не везде удобно. К тому же, подозреваю, медленнее чем все остальные (в обработке).
«Бритва Оккама» или «Принцип Калашникова»?
 
MCH, Вам большое спасибо за уже настроенный свой тип переменной. Использовал Ваши наработки, с Вашего разрешения выкладываю получившейся результат с небольшими доработками. В некоторых операциях при "максимальном количестве элементов в массиве" - "MaxL" >1000 появляются ошибки (к примеру "о счастливых билетах"). Решил этот размер не превышать. В итоге вышло 4 тыс. символов в десятичной системе :) Конструктивные замечания приветствуются!
Изменено: bedvit - 07.04.2016 14:25:44
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
bedvit написал: Конструктивные замечания приветствуются!
Я немного переделал код в 5м сообщении:
1. заменил While...Wend на Do...Loop While
Иначе при нулевом значении получается пустая строка.
2. Конструкции типа
Код
a = lMul(a, b)
a = lSum(a, c)

Заменил на
Код
a = lSum(lMul(a, b), c)

Ничего не меняет, но строчек кода меньше
 
MCH, отлично, сейчас в пути, приеду у себя поправлю тоже. А как вы смотрите на немного измененные типы переменных? Не тестировал, но на первый взгляд должны нормально отрабатывать. Главное знак посчитать)))
«Бритва Оккама» или «Принцип Калашникова»?
 
Но думаю на производительности сильно не скажется. Может и не стоило заморачиватся.
«Бритва Оккама» или «Принцип Калашникова»?
 
MCH, итак внес изменения:
1.Изменил в lMod
Код
c = lSum(a, lMul(c, d), 1)
, покороче.
2.В lDiv
Код
 c.z = a.z Xor (b < 0)
, укажите где подводные камни могут быть?
3.В ln2s
Код
If a.z Then s = "-"
, покороче.
4.Немного поменял логику забора кодов символов ASCII
5.Loop While a.len > 0 Or a.i(0) > 0, в каких случаях в функции "СистемаСчисления" может быть a.len > 0, но a.I(0) = 0? не соображу.
Внес все изменения в код, сообщение 18.
Глубоко не копал, доверяю Вашему коду как своему. Я еще ВПР() учил, когда Вы писали поиск слагаемых под нужную сумму методом "brute force" :)
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
bedvit написал:
в каких случаях в функции "СистемаСчисления" может быть a.len > 0, но a.I(0) = 0? не соображу.
десятичное число 10000
 
Хм, я явно смотрю не туда :), вот по Debug.Print a.i(0) & "  " & a.len (перевод из десятичной в десятичную):
1000  0
100  0
10  0
1  0
0  0

Наверное я не верно выразился: когда будут разные результаты при Loop While a.len > 0 Or a.i(0) > 0 и Loop While a.i(0) > 0 ?
Изменено: bedvit - 07.04.2016 14:58:09
«Бритва Оккама» или «Принцип Калашникова»?
 
любое число заканчивающееся на четыре нуля (и более), имеет длину, но при этом первый элемент - a.i(0) имеет нулевое значение
 
MCH, да верно, в данном случае с числа 100000, т.к. оно делится на основание 10. Спасибо, понял. А по п.2?
Изменено: bedvit - 07.04.2016 15:15:19
«Бритва Оккама» или «Принцип Калашникова»?
 
MCH, немного подкорректировал код, что бы правильно отрабатывал при отрицательном "коротком" числе для функций  lDiv и lMod
Скрытый текст
Изменено: bedvit - 12.04.2016 18:55:47
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
bedvit написал:
lMod = "-" & c.i(0)
А зачем так?
Можно
lMod = -c.i(0)
 
Сам удивляюсь). Кстати для частных случаев набросал с небольшим числом (до 20 знаков) при переводе с основанием 8,10,16 (другие литералы не нашел)
Код
Function HexToDec(Число As String) As String
HexToDec = CDec("&H" & Число) 'из основания 16 в 10
End Function
Function DecToHex(Число As String) As String
DecToHex = Hex(Число) 'из основания 10 в 16
End Function
Function OctToDec(Число As String) As String
OctToDec = CDec("&O" & Число) 'из основания 8 в 10
End Function
Function DecToOct(Число As String) As String
DecToOct = Oct(Число)  'из основания 10 в 8
End Function
«Бритва Оккама» или «Принцип Калашникова»?
 
MCH, при увеличении максимального кол-ва элементов в массиве (длинное число), возникает ошибка "too many local, nonstatic variables" в функции lDiv.
Гугл/Яндекс/Мягкотелые говорят следующее:
Цитата
MSDN
When compiled, the code for a procedure can't exceed 64K. This error has the following cause and solution:
Code for this procedure exceeds 64K when compiled.
Break this, and any other large procedures, into two or more smaller procedures.
и
Цитата
MSDN(Data Limitations)
...If a procedure or module exceeds the 64K code limit, Visual Basic generates a compile-time error.
If you define a procedure that has more than 64K of local variables defined, you get the error "Too many local nonstatic variables."
If you define a module that has more than 64K of module-level variables defined, or if you define a User-Defined Type larger than 64K, you get the error "Fixed or static data can't be larger than 64K."...
64К "в век когда корабли бороздят..." откуда такие ограничения? (в версии vba 7.0 x64 - аналогично)

Гугл/Яндек рекомендует:
1. Сам разработчик рекомендует при появлении такой ошибки переобъявлять такие переменные через "static", будто бы для статических переменных таких ограничений нет.
2.Можно вместо пользовательских типов попробовать использовать классы

Вы встречались с такой проблемой?
Изменено: bedvit - 16.05.2016 14:46:50
«Бритва Оккама» или «Принцип Калашникова»?
Страницы: 1 2 След.
Наверх