Рассылка закрыта
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
← Август 2001 → | ||||||
1
|
3
|
4
|
5
|
|||
---|---|---|---|---|---|---|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
13
|
14
|
15
|
16
|
17
|
18
|
19
|
20
|
21
|
22
|
23
|
24
|
25
|
26
|
27
|
28
|
29
|
30
|
31
|
Автор
Гость
Статистика
3.612 подписчиков
за неделю
за неделю
Низкоуровневое программирование для дZенствующих (FAQ) #6
НИЗКОУРОВНЕВОЕ ПРОГРАММИРОВАНИЕ ДЛЯ ДZЕНСТВУЮЩИХ (FAQ) АРХИВ MAIL-КОНФЕРЕНЦИИ RTFM_HELPERS ЗА ИЮНЬ 2001 Сайт: http://hi-tech.nsys.by/ Информация о конференции: http://hi-tech.nsys.by/forum/ ИО модератора aka DZ Kir777: kir777@hotmail.com Co-moderator aka Serrgio: serrgio@gorki.unibel.by [В О П Р О С - О Т В Е Т] ======================================================================= ВОПРОС: Хотел попросить каких-нибудь ссылок в нете, где можно почитать про низкоуровневое программирование под linux. Плиз. ооочень интересно. MAXP: Вот только тут надо уточнить что называется низкоуровневым программированием? Т.е. это же вам не какой-нибудь ДОС, где, грубо говоря, то что писалось на Васиках,Клипперах и пр., называлось высокоуровневым, а всякие резиденты которые крайне неудобно писались на чем-либо, кроме ассемблера называли низкоуровневым. В линуксе есть ядро с исчернпывающим и описанным API, как для пользовательских программ, так и для ядерных модулей. Все это в основном описывается в терминах языка C. На тему документации хороший старт - linuxdoc.org ANDREW: Да на сколько я знаю сам язык программирования С был разработан при создании UNIX а LINUX его клон таким образом удобнее писать все ж на нём. MAXP: Ядро предоставляет много всякого для драйверописателей. Чтобы пообщаться с железкой надо, в общем, для начала хорошенько почитать даташит от нее, а потом все те же inb() outb(), разумеется иногда надо иногда знать как маппятся различные адресные пространства друг на друга. Еще надо обязательно разобраться с интерфейсом к драйверам, ( /dev/* для примеру ). Отонсительно кернельных API - недавно пришлось копаться во внутренностях драйвера видеограббера (типа как Avermedia выпускает). Там сделано так - на карте кроме граббера могут быть еще всякие тюнеры, которые управляются при помощи I2C (это поселдовательная шинка как раз для управления всякими набортными девайсами) Эта шина выведена на какой-то там регистр самого граббера BT878, драйвер при загрузке регистрирует эту шину в кернеле и просто отдает туда простенькие ф-ции типа послать байт, принять байт. После чего ядреный модуль i2c-core уже знает, что есть такая шина, и он умеет работать с ней, знает разные протоколы работы с ней и т.п. Самое забавное, что когда bttv драйвер хочет порулить тюнером, он обращается к достаточно высокоуровневому интерфейсу i2c, который потом уже вызывает обратно низкоыровневую ф-цию из bttv, которыя уже ставит битики в регистре BT878, которые в свою очередь выведены на I2C шину. ----------------------------------------------------------------------- ВОПРОС: Подскажите где можно скачать какой-нибудь мануал по асму под винды ? GOLOVA: Для начала смотаться на http://win32asm.cjb.net, хапнуть там masm32 (tasm под мастдай не слишком рулёзен), заодно заглянуть в раздел tutorials и слить там все туторы от Iczelion'a - этого вполне должно хватить (разумеется при наличи опыта писания под вынь на высокоуровневых языках, знании АПИ и некотороых принципов работы винды). Коешта вкусного можно надыбить на http://masm32.cjb.net (типа сам масм, апдейты, итклюдники и немного интересных примеров). ВЛАДИМИР: Это один из самых лучших ресурсов в сети по win32asm. Там есть и тюдориал, написанный Iczelion'ом. ----------------------------------------------------------------------- ВОПРОС: В IDA 3.7 есть пункт "пропатчить прогу". Так он у меня не работает :-( Ида выпадает с сообщением об ошибке грануляции Вопрос таков: можно ли как-нибудь это обойти и пропатчить прогу из Иды ? А дизасмить по новой патченную прогу как-то не охота ..... NICK: Во-первых есть Freeware ida 4.1. Во-вторых можно попробовать через idc команду PatchByte. В-третьих, для особо продвинутых через idc команды работы с массивами. GOLOVA: А ты не дизасмь - жми File/Reload Input File - по идее ИДА передизасмит только изменившиеся байты, по крайней мере у меня так и получается.Может все-таки стоит обновить ИДУ? Фришную не бери - там лимитов слишком много - по инету гуляет варезная 4.04 - вот она подойдет. У меня на 4.11 патчи прекрасно накладываются (тока что проверил). NICK: Ты наверно перепутал demo версию и freeware версию. В freeware версии нет никаких существенных ограничений. И freeware версия 4.1 лучше чем поломанная 4.04. GOLOVA: Да, я имел в виду именно демо версию :) Так где можно поглядеть на freeware 4.1 ??? Чето я не нашел ее на datarescue. Кстати, 4.04 вовсе не поломанная - как я сказал, она варезная :) Вполне сгодится для любых целей. NICK: Что-то плохо искал :). Вот ссылка: http://www.datarescue.be/downloadfreeware.htm DINOZAUR: На ftp://ftp.datarescue.be/pub/ida есть idafree.zip ----------------------------------------------------------------------- ВОПРОС: Объясните, pls, чем отличаются флаги CF и OF? NICK: Флаг CF устанавливаеться в случае переполнения беззнаковых чисел, а флаг OF - чисел со знаком. Т.е. если например в 16-ти битном режиме к числу 7fffh прибавить 1, то OF - установиться, а CF - нет. ХЕМУЛЬ: В ассемблере (читай: в архитектуре,реализуемой процессорами Intel x86) имеется модель памяти, состоящая из последовательности байт (плюс "нюансы" типа сегментации) и есть набор инструкций, которые с этими байтами работают (а некоторые инструкции работают с группами байт, называемых "слово", "двойное слово", "одинарная точность" и т.п.). Соответственно, интерпретация значения ячеек памяти зависит только от программиста, который и выбирает соответствующие инструкции (и в этом отличие от типизированных/полиморфных языков, в которых операции для разных типов имеют общее имя, а соответствующий набор инструкций потом выбирается компилятором). С другой стороны, для отрицательных чисел в x86 используется дополнительный код, а замечательным свойством этого кода заключается в том, что результат арифметических инструкций сложения и вычитания идентичен независимо от интерпретации знаковости аргументов. Тем не менее, для умножения и деления эта универсальность всё равно не выполняется и инструкции здесь разные. Соответственно, инструкции сложения и вычитания устанавливают в зависимости от результата оба (на самом деле больше) флага - и CF, и OF, так что программист потом может выбрать, который из флагов ему анализировать (читай: выбрать, как ему интерпретировать результат - как знаковый или как беззнаковый). Таким образом, Nick (это ведь Nick дал вышепроцитированное объяснение?) совершенно прав, просто он не упомянул, что оба флага меняются одновременно. Обычно это подразумевается, но если нет уверенности, следует всегда заглядывать в руководство за информацией о том, какие инструкции какие флаги трогают/меняют. ANDREW: Коль такая дисскусси пошла на тему флагов, то я даже не поленился и проверил и вот что получил: FFFF + 10 CF = 1 OF = 0 1 - 10 CF = 1 OF = 0 7FFF + 10 CF = 0 OF = 1 8001 - 10 CF = 0 OF = 1 Чё-то не видно, что бы они оба вместе менялися.. BELTSY: > 1 - 10 > CF = 1 OF = 0 > 7FFF + 10 > CF = 0 OF = 1 только один поменялся??? а мне кажется, раз СF был 1, и стал 0, то он поменялся, и OF был нуль, а стал 1 тоже вроде поменялся, похоже оба поменялись??? :)) если ты имеешь в виду, что они оба не стали 1, так вроде никто и не говорил, что они оба становятся 1. NICK: Вот тут я бы хотел уточнить. Во-первых есть две команды которые меняют OF но при этом не меняют CF - это INC и DEC. А во-вторых есть целая группа команд которая менят флаг CF не меняя флаг OF. Правда эти команды к арифметике отношения не имеют ;) но всетаки. VOVA: В одном из справочников дано такое интересное объяснение флага OF: ======begin================ Сигнализирует о потере старшего бита результата в связи с переполнением разрядной сетки при работе со знаковыми числами. При сложении флаг OF устанавливается в 1, если происходит перенос в старший бит, но нет переноса из старшего бита, или наоборот, есть перенос из старшего бита, но нет переноса в него; в случае несоблюдения вышеперечисленных условий этот флаг устанавливается в 0. При вычитании флаг OF устанавливается в 1, если возникает заем из старшего бита, но нет заема в старший бит, либо есть заем в старший бит, но отсутствует заем из него. ======end================= ----------------------------------------------------------------------- ВОПРОС: Спасибо! С CF разобралась. Теперь буду спрашивать про OF Например, есть у нас 16-ти разрядное число. Мы его можем рассматривать двояко: 1. Как 16-ти разрядное беззнаковое. 2. Как 15-ти разрядное плюс старший бит - его знак. Старший бит называется "значащим", потому что мы можем с его помощью (при желании) работать со знаковыми числами. Я права? NICK: Не совсем. 1. Правильно. А как знаковое это будет число -108. В x86 архитектуре знаковые числа кодируються обратным кодом. Таким образом -1 = FFh, -2 = FEh и т.д. > AL = 1001 0100. Самый левый бит называется "значащий". > Правильно? Вот с этим сложнее, тут я могу высказать только свое мнение. Так как учился я давно, то точных определений не помню :(. На мой взгляд "значащими" битами являються все биты содержащие значение. Т.е. в беззнаковых числах это все биты, а в знаковых все кроме самого старшего. Самый старший бит в знаковых числах правильнее называть "знаковым", а не "значащим". Но еще раз повторюсь, что это только мое мнение. ANDREW: То что все биты являются значащими это точно... как-то ранее правильно было написано: СТАРШИЙ значащий бит.... Потому, что если значащий бит только старший то нафига остальные...??? Другое дело знаковый бит... Но процу до лампочки с какими работать.. всё зависит от команд.. И коль про флаги и знаки чисел идёт такая дискуссия, то хочу спросить: А почему все рассматривают только положительные и отрицательные числа ??? Ведь как рассматривать - это дело абсолютно субъективное... Почему бы не сделать для себя больше знаков ??? Скажем из 16 бит, биты 14, 15 отводим под свои нужды и имеем число с 5 знаками !!! Просто после операции с числом делаем: AND reg/mem, C000h и по своим битам определяем знаки числа.. Можно чуть проще: pushf and reg/mem, C000h popf И далее по флагам флагового регистра определяем то что нам нужно.. Можно и другие биты отвести под свои знаки..тока не столь удобно пользоваться будет... Но можно.. ----------------------------------------------------------------------- ВОПРОС: Хочу узнать, если способ на масм32 генерить не ехе файлы а только бинарник кода (но не в виде obj файла), без DOS Stub и прочей муры, тоесть мне хочется получить только откомпиленный код настроянный на заданный адрес загрузки. Насколько мне известно, Netwide Asm это может, но уж больно у него непривычный синтаксис. ХЕМУЛЬ: В качестве комментария: в TASM+TLINK чтобы сделать "нестандартное" размещение (т.е. не .EXE или .COM, а что-то типа .SYS), нужно создавать .EXE и отрезать заголовок с помощью EXE2BIN (NB: DOS по меньшей мере с 5.0 позволяет держать .SYS в .EXE - и EMM386 тому примером). B.WOLF: LOL. COM файл скомпилить. ----------------------------------------------------------------------- ВОПРОС: Разбираясь с дзен-рассылкой ?20 п.Примечания для продвинутых, я не оказавшись оным уперся в проблемму. Как посмотреть флаги состояний? в Дебуге (-r)они как я догадываюсь есть, но мнемоники совершенно не совпадают с названиями флагов или дебуг не для этого надо другой отладчик? ХЕМУЛЬ: В дебаге показывается _значение_, а не мнемоники флагов. Например: NV - No oVerflow, NC - No Carry, CY - CarrY, PL - PLus, NG - NeGate, etc. Вроде не совсем удобно, но что-то в этом есть, особенно если к этому привыкнуть. Небольшой трюк, который, кажется, ещё не рассказывали. Если использовать завершающей инструкцией кода в дебаге (и только в нём!) int3 вместо int20, то значение регистров и флагов сохраняется и показывается после исполнения int3. Также можно сваять "скрипт" для отладки фрагмента кода и пользоваться им. Вот, например, если мы хотим посмотреть результат работы инструкции деления, то мы можем сваять следующий файл: _________O\_/_________________________________\_/O_________ a mov dx,0 mov ax,105 mov cx,10 div cx int3 g=100 q ___________________________________________________________ O/~\ /~\O Теперь, если выполнить следующую команду: "debug<script>result" то в файле с именем RESULT мы получим следующее: _________O\_/_________________________________\_/O_________ -g=100 AX=0010 BX=0000 CX=0010 DX=0005 SP=FFEE BP=0000 SI=0000 DI=0000 DS=0E90 ES=0E90 SS=0E90 CS=0E90 IP=010B NV UP EI NG NZ NA PE CY ___________________________________________________________ O/~\ /~\O Здесь ты можешь видеть значение флагов после инструкции и значение регистров (в данном случае AX и DX). Надо ли говорить, что использование скриптов избавляет нас от ручной работы по постоянному вбиванию одного и того же фрагмента кода, при этом нам доступны все средства по неинтерактивной отладке (например, мы можем внутри фрагмента кода расставить инструкции сохранения в памяти временных результатов, а потом смотреть их с помощью команды D)? Единственный (?) серьёзный недостаток дебага при этом - неумение расставлять метки, что заставляет либо пересчитывать адреса меток вручную, либо раскидывать код на отдельные фрагменты по фиксированным адресам. Наконец, если тебе не нравятся мнемоники значений флагов, то ты можешь посмотреть на регистр флагов в двоичном виде (хотя для этого нужно помнить размещение нужных флагов по битам). Например, в предыдущем скрипте добавь после div (и перед int3!) инструкции pushf и pop cx, и ты сможешь увидеть в результате значение регистра флагов, скопированного в CX. ----------------------------------------------------------------------- ВОПРОС: Запускаю Иду, она дизасмит, что-то еще на автомате делает... все, закончила. Иду в Файл->сделать выходной файл->сделать ехе. Ехе генерится. размер тот же. НО! При сравниваниии файлов они различаеются, и довольно значительно :-(( Сравниваю так : fc /B num1.exe num2.exe Правда делает новый файл вроде то же , что и старый... Такая вещь происходит и с "3.7 про", и с "4.1 фрее" версиями. Я хочу получить в результате пропатченный файл, который отличается по минимуму от исходного... А именно в тех местах, где я его пропатчил. Можно конечно отлавливать в исходном файле HEX последовательности и править с помощью hex editor'а , но при этом приходится дизасмить по новой :-(( чтобы убедиться, что пропатчил правильно. Что же делать ??? ХЕМУЛЬ: В качестве предположения: структура экзешника несколько гибкая и позволяет небольшие вариации. Например, все экзешники могут иметь дырки в области заголовка и произвольный порядок релокаций, я в NewEXE (NE, PE, etc) в произвольном порядке может располагаться туча секций, из которых состоит файл.C помощью FC/B выясни, какой именно блок файла отличается (то есть в каком диапазоне адресов идут отличия), а затем посмотри по заголовкам .exe (например, в .hiew), на какую часть файла эти изменения приходятся. Как я уже говорил, я предполагаю, что скорее всего отличие в двух файлах идёт за счёт отсортированной таблицы релокаций. NICK: IDA умеет выдавать текстовый файл, почти в формате CRK (для которого есть туча программ) со всеми пропатчеными местами. В конце концов по этому файлу и ручками все можно пропатчить или написать свою программу. Файл генерируется командой File|Produce Output File|Produce DIF file. В freeware версии эта команда есть. ----------------------------------------------------------------------- ВОПРОС: Господа, есть у кого-нибудь идеи (а лучше - сырцы), как можно реализовать сабж? Неужели придется искать на функциях int3 и прыжки??? ApiHooks allows to execute user code in the context(s) of specified/all local 32bit process(es) in Microsoft Windows (x86,32bit). ApiHooks doesn't use drivers and can operate under NT guest account. ApiHooks doesn't change files or system registry. ApiHooks contains built-in code for (un)loading modules and for hooking APIs. APIs to hook must be exported by modules. Establishing API hooks is something like hooking interrupts in MS DOS - your module(s) is/are per-process resident and catch/es API calls between modules. You can change hooked function parameter(s) before call to original function as well as you can change returned value(s) and buffers contents. ApiHooks exports several useful APIs in DLL that developer can call from her/his programs. Т.е. если быть кратким, то после того как некто внедрит свою длл мне в процесс и подменит АПИ функции моей проге на свои - он сможет делать с моим процессом все что ему захочется, например прибить проверку CRC можно очень просто - достаточно перехватить у процесса CreateFile, и как только он начнет открывать самого себя, под сунуть ему вместо пропатченного файла чистенький... :( Типа примеров по инету гуляет много, вот один из них: http://www.anticracking.sk/EliCZ/ (типа там в экспорте в самом низу). NICK: Ну хорошо, допустим ты поборешь ApiHooks. Но то-же самое можно сделать либо подстановкой своей dll, либо изменением имени dll в таблице импорта. С этим в принципе невозможно бороться, такова структура Windows :( GOLOVA: Похоже мы говорим о разных вещах. 1) Подстановка своей длл невозможна - программа использует только стандартные библиотеки мастдая - их не подменишь. 2) Изменение имени длл в таблице импорта тоже меня мало беспокоят - это крайне легко отловить контрольной суммой. А с хуками ситуация другая, и меня это очень пугает.Читаем: ApiHooks allows to execute user code in the context/s of specified/all local 32bit process(es) in Microsoft Windows (x86,32bit) 95, 98, ME, NT4, 2K. ApiHooks doesn't use drivers and can operate under NT guest account. ApiHooks doesn't change files or system registry. Типа вот, и как прикажите мне искать изменение, когда его нет - изменился только адрес в IAT. Пока на ум приходит только перебирать внутренние структуры загрузчика мастдая в поисках имен всех длл процесса (естественно без помощи ToolHelp или PSAPI) и прибивать чужеродную - но это не слишком умно, к тому же я пока знаю как это делать только под НТ, а надобы еще и под 9х. >С этим в принципе невозможно бороться, такова структура Windows :( С этим можно бороться, некоторые пакеры/криптеры это умеют, такова структура Windows :) Скажу штаа мне сейчас просто некогда дизасмить эти самые пакери и отдирать код. ANDREW: Ведь размер и структура и т.п. твоих dll - то известна.. поэтому если кто-то подсунул dll с ApiHook, то после проверки dll прога должна вылетать из памяти... А для того что б кто-то посторонний не смог контролировать процесс проверкиdll просто переключи ApiHook на свою процедуру обработки и всё... то же можно сделать по всей проге. скажем перед вызовом чего-нить из API твой Hook что-то делает и функция работает, а если не сделано этого, то ясно, что кто-то дебажит... GOLOVA: Cвоих конечно знаю, а вот системных - никак нет, откуда мне знать что придумает Билли в следующем билде мастдая Приемлимое решение, только сложное, да и тормозить наверняка будет, к тому же мне это не для своей программы надо - придется обьяснять людям как прально записывать те либы что юзает прога :) Всетаки я хочу остановиться на подсчете количества используемых прогой длл - ищу решение для вынь9х. ANDREY: А зачем проверять каждый раз? Достаточно поместить блок в начале проги, в котором перечислены (якобы вызываются) все необходимые АПИ-вызовы: jmp EndPseudoCall ;эта часть управление не получит, ;но загрузчик-то об этом не знает: call GetCommandLineA call GetMessageA call PlaySoundA EndPseudoCall: ...... И проверяешь правильность адресов только один раз! Откуда взяться тормозам? GOLOVA: Я вот щас подумал, может мне самому из собственной проги захуть собственный же импорт, интересно как на это отреагирует apihook.dll ??? ANDREW: Я помниться то же самое предлогал.. Во первых. надо бы решить с чем бороться, а то надо ли скажем кому-нить пытаться отслеживать весь трафик данных мышки ??? Или же тебе надобно что б никто не отслеживал, кто работу с меню, скрулбарами, всякими диалоговыми окнами... А если тебя интересует что бы никто не мог перехватить скажем чтение из файла то используй захват WH_DEBUG. Win NT вызывает процедуру захвата WH_DEBUG прежде, чем вызвать процедуры захвата, связываемые с любым другим захватом в систему. Можно использовать этот захват, чтобы определить и позволить системе вызывать процедуры захвата, связываемые с другими типом захватов. Но к сожалению она работает тока на NT :(( НО ВОТ ЕСТЬ ЛИ ПОВОД ДЛЯ БЕСПОКОЙСТВА?? так как захват устанавливается самим приложением и этим же приложением снимается.... Поэтому если приложение не Хутит себя то и незачем беспокоиться.. ----------------------------------------------------------------------- ВОПРОС: Имеются такие переменные: unsigned int segment, offset; /* Хранят сегмент и смещение */ char far ptr; / far-указатель на байт в памяти */ как из переменных segment и offset запихнуть значения в указатель, т.е., сделать так, чтобы указатель показывал на segment:offset? Расскажите, плз, если кто знает :) ALEXANDR: Легко void far *MK_FP(unsigned seg, unsigned ofs); т.е. ptr = (char far*)MK_FP(segment, offset); NICK: В Borland C есть хороший макрос MK_FP. Использовать следующим образом: ptr=MK_FP(segment,offset); DMITRY: Эту проблему можно решить, например, с использованием возможности приведения типов переменных: *((unsigned*) &ptr) = offset; *((unsigned*) &ptr + 1) = segment; Как известно, far-указатели занимают в памяти 4 байта или 2 слова (что равносильно 2 переменным типа unsigned). Вышеприведенный код берет адрес в памяти, где находится указатель ptr (т.е. &ptr), приводит значение этого адреса к указателю на слово (т.е. (unsigned*) &ptr), таким образом мы получили указатель на слово в памяти, где хранится смещение, на которое указывет указатель ptr, теперь, применяя операцию разыменования указателя (*), "приписываем" нашему указателю необходимое смещение (т.е. *((unsigned*) &ptr) = offset). "Приписывание" сегмента указателю происходит аналогичным образом, с учетом лишь того, что он (сегмент, а точнее, его значение), хранится в памяти на слово раньше, поэтому к полученному указателю на смещение прибавляют 1. Вот и все :)) ХЕМУЛЬ: Я бы отметил тут три момента. Во-первых, я описал бы сегмент со смещением как беззнаковые числа (читай: unsigned или вообще word). Во-вторых, обрати внимание на кастинг перед MK_FP - в C++ это обязательно. В-третьих, не забудь про far в кастинге. unsigned от unsigned int ничем не отличается (кроме отсутствия необязательного слова), а вот с int разница принципиальная: переменные этих типов интерпретируются по разному. И если на x86, в которых знаковые числа кодируются в доп.коде, при сложении и вычитании разницы нет, но ведь есть и другие операции: конвертация в строку, сдвиг вправо и т.п. ND> Еще тут немного непонятно :( Кастинг ставится из-за того, что мой указатель есть char far*, а MK_FP возвращает void far*, не так ли? Так. А C++, в отличие от C, не позволяет присваивать void* ничему, кроме void*. ND> А если я сделаю свой уазатель как void far* ptr, можно ли тогда убрать кастинг? Можно. Но тогда нужно будет использовать кастинг уже при использовании свмого указателя (если только речь не идёт о его передаче в функции, параметры которых описаны как void far*). ND> Отдельное спасибо, Дмитрию, за его вариант и содержательные пояснения :) DSK>> *((unsigned*) &ptr) = offset; DSK>> *((unsigned*) &ptr + 1) = segment; Во-первых, чисто синтаксически это можно записать по другому: ((unsigned*)&ptr)[0] = offset, ((unsigned*)&ptr)[1] = offset; Во-вторых, если тебе хочется трюков, посмотри, как реализован MK_FP в борланде: _________O\_/_________________________________\_/O________ #define MK_FP( seg,ofs )( (void _seg )( seg ) +( void near )( ofs )) __________________________________________________________ O/~\ /~\O ----------------------------------------------------------------------- ВОПРОС: Rто-нибудь в курсе можно ли определить, НЕ экспериментальным путем, длинну последовательности обычного ГСЧ X(n+1) = X(n)*A mod B где A, B и X(0) - естественно известны. ANDREY: Ну, верхнюю оценку дать очень легко: длинна в _самом__лучшем случае будет равна (B-1). При этом Х пробежит по всем значениям от 1 до B. В случае же Х(0)=0 получаем вырожденную последовательность 0;0;0;0... (не забыть отследить!) А все это потому, что следующее значение последовательности зависит только от одного предыдущего элемента. DZeMAN: Вопрос о приблизительном значении периода экспоненциальной последовательности сам по себе некорректен. В кольце вычетов по модулю B (mod B) для экспоненциальной последовательности может и не быть полного цикла (м.б. цикл с "подходом",если элемент A имеет с B общий делитель, отличный от 1). Т.е., сам элемент А (при отсутствии взаимной простоты с B) после 0-го такта в генерируемой последовательности не появится. ( Для посвященных: элементы цикла образуют циклическую подгруппу кольца вычетов, порожденную некоторой степенью А) Максимальным период такой последовательности задается значением Ф(B), где Ф - функция Эйлера. В частности, когда B - простое число, ее значение и будет B-1. Число, степень которого порождает все обратимые элементы кольца вычетов по mod B, называется его генератором. Сами же генераторы существуют для значений В = 2, 4, (степени простого нечетного числа) и (ей же умноженной на 2).(**) Кто не хочет "тонуть" в теории, пусть представит себе путника (А), спускающегося со скользкой горы (В). Соскользнув с ее склона, он попадает на твердую почву, но на вершину он вернуться не в силах, а лишь только движется вокруг основания горы. Гора может быть абсолютно плоской, для указанных значений В (**). Да и путник иногда (значение А) может считать гору В простой (взаимная простота значений), и запросто двигаться вокруг нее по склонам. Но чтобы двигаться вокруг горы по максимально большой траектории и гора должна быть уютной (**), да и путник (А) - не простой, а из нового "поколения" (быть генератором). ===================================================================== (С) HI-TECH group. All rights reserved and reversed. Оригинальная грамматика авторов сохранена.
http://subscribe.ru/
E-mail: ask@subscribe.ru | Отписаться | Рейтингуется SpyLog |
В избранное | ||