Вы представляете
Прошли годы.
Через мои руки прошли не один, и не два компьютера.
Я уже сбился со счёта всем этим программам, языкам программирования, оболочкам, драйверам, модификациям, устройствам и операционным системам. В моей голове уже давно КАША.
Хочется напиться, и забыться. А на утро проснуться с абсолютно чистой памятью. Мне иногда кажется, что стариком меня делает не тело, а голова. Если на протяжении 30 лет неустанно грузить в себя всё новые, и новые подробности из сферы IT-технологий, то поневоле станешь калекой.
А ещё я мечтал написать свою Шахматную программу. Я по-наивности думал, что современный мощный компьютер легко организует перебор всех возможных вариантов ходов из начальной позиции, и тогда можно (задав внутрь программы шахматные правила) находить такие партии, которые кончаются МАТОМ.
Записывать протокол ходов под очередным номером в файл, а ходы возвращать назад, делать следующие возможные – и так постепенно перебрать и выловить все партии, которые кончаются МАТОМ.
Конечно, у такой программы не будет «мозгов». Она будет совершать глупые ходы. Но это не важно, думал я. Главное, чтобы она ничего не пропускала. Обошла всё пространство состояний всех вариантов игр и выбрала партии с МАТОМ в конце.
А уже потом можно писать другие «программы-примочки», которые займутся сравнением этих протоколов. И тогда можно будет находить среди огромной кучи бестолковых партий и редкие красивые решения: шахматные задачи! У них всех должна быть общая точка пересечения! Они на несколько заданных ходов назад (разных ходов!) должны совпасть в своей позиции.
Эта идея сравнима с расчётом криптовалюты. Только в результате должны получаться не бестолковые биткоины. А шахматные задачи! Вот это была бы вещь! – Думал я.
Но, увы!
Если на доске всего три фигуры: белый Король, белая пешка и чёрный Король, то для сквозного перебора всех возможных ходов для проведения пешки в Ферзи, например, за 10 ходов, потребуется перебрать следующее число вариантов: у белых на каждом ходе 9 вариантов ходов, а у чёрных 8, следовательно всего 8 * 9 = 72 варианта на одном ходе. А на 10 ходах это будет 72 ^ 10 = 4 * 10 ^ 18 (округлённо). Т.е. 72 в 10 степени = приблизительно 4 на 10 в 18 степени! А после нахождения вариантов провода пешки в ферзи, следует решение задачи постановки мата: у белых Ферзь и Король, а у чёрных Король. Ферзь имеет максимально возможное число ходов 28 шт. , а Король 8 шт. Итого получается, что у белых на каждом ходе 36 вариантов ходов, а у чёрных 8 вариантов. Умножаем 36 * 8 = 288 шт. – Это число вариантов для одного хода. А для 10 ходов (для постановки мата Ферзём и Королём – округлённо) число вариантов будет равно 288 ^ 10 = 4 * 10 ^ 24 (приблизительно).
Спрашивается, за какое время можно произвести такой расчёт? Чтобы за 20 ходов из начальной позиции Король провёл пешку в Ферзи и поставил мат чёрным.
Предположим, что время нам известно: это год непрерывной работы программы. Вопрос, сколько вариантов должна перебирать программа в секунду в этом случае? Ответ: 1 * 10 ^ 17 шт.
Т.е. 100 000 000 000 000 000 шт. ходов за 1 сек.
Вы можете это себе представить? А? Реально это? Как оценить?
Это можно смоделировать так:
PRINT DATE$, TIME$
FOR i1% = 1 TO 100
FOR i2% = 1 TO 1000
FOR i3% = 1 TO 1000
FOR i4% = 1 TO 1000
FOR i5% = 1 TO 1000
FOR i6% = 1 TO 1000
'а здесь очередной ход
NEXT i6%
NEXT i5%
NEXT i4%
NEXT i3%
NEXT i2%
NEXT i1%
PRINT DATE$, TIME$
END
Как показывает практика, такое быстродействие ещё не достижимо для современных компьютеров. Посмотрите, что получилось у меня, при попытке реализовать усечённый вариант вложенных циклов. Я уменьшил число циклов до четырёх. Таким образом, получил не 17-ю степень, а 11-ю.
TB v 1.0
cls
print date$, time$ '04-25-2022 19:11:46
for i1% = 1 to 100
for i2% = 1 to 1000
for i3% = 1 to 1000
for i4% = 1 to 1000
next i4%
next i3%
next i2%
next i1%
print date$, time$
'04-25-2022 19:18:42 = 6 min 56 sec v TB srede
end
Турбо Бейсик не позволил создать мне EXE-файл. Отказался. Поэтому выполнение программы было в самой среде Турбо Бейсика. Результат работы я вписал в комментарии к программе уже после выполнения. Итого 6 минут 56 секунд.
PWRBASIC
cls
print date$, time$ '04-25-2022 19:43:45
for i1% = 1 to 100
for i2% = 1 to 1000
for i3% = 1 to 1000
for i4% = 1 to 1000
next i4%
next i3%
next i2%
next i1%
print date$, time$ '04-25-2022 19:52:14 = 8,5 min v DOS
end
Power_BASIC создал EXE-файл и выполнил в ДОС с приведёнными в комментариях результатом. Т.е. 8,5 минут.
QBASIC
cls
print date$, time$ '04-25-2022 20:52:18
'for i1% = 1 to 100
for i2% = 1 to 1000
for i3% = 1 to 1000
for i4% = 1 to 1000
next i4%
next i3%
next i2%
'next i1%
print date$, time$ '04-25-2022 20:53:34 = 1 min 16 sec
' * 100 = 2 hasa 6 min 40 sec v QBASIC srede
system
end
Неприятно удивил Q_BASIC. Я конечно знал, что он ИНТЕРПРЕТАТОР. Но никогда не думал, что разница между ИНТЕРПРЕТАТОРОМ и КОМПИЛЯТОРОМ будет настолько большой! Я не дождался конца выполнения программы. Оборвал её по Ctrl-Break. Убрал один вложенный цикл (внешний, самый маленький). И тогда результат был получен за 1 минуту 16 секунд. Естественно, что если бы я не убрал один цикл, то мне бы пришлось ждать конца выполнения в сто раз дольше. Т.е. 2 часа 6 минут 40 секунд. Вот тебе и «Кю»!
QUICK_BASIC_V_4.5
CLS
PRINT DATE$, TIME$ '04-25-2022 20:12:33
FOR i1% = 1 TO 100
FOR i2% = 1 TO 1000
FOR i3% = 1 TO 1000
FOR i4% = 1 TO 1000
NEXT i4%
NEXT i3%
NEXT i2%
NEXT i1%
PRINT DATE$, TIME$ '04-25-2022 20:14:52 = 2 min 19 sec v DOS
END
Напротив, Quick Basic v 4.5 приятно удивил. Он выполнил задачу в EXE-файле всего за 2 минуты 19 секунд! Ощутите разницу между ИНТЕРПРЕТАТОРОМ QBasic с его 2-мя часами работы, и КОМПИЛЯТОРОМ Quick Basic v 4.5 с его 2-мя МИНУТАМИ!
TC v 2.0
/* PROBA.C */
#include <dos.h>
#include <stdio.h>
main()
{
struct date today;
struct time now;
int i1, i2, i3, i4;
getdate(&today);
gettime(&now);
printf("--", today.da_day, today.da_mon, today.da_year);
printf(" ::\n", now.ti_hour, now.ti_min, now.ti_sec);
/* 26-04-2022 00:31:17 */
for (i1=0; i1<100; i1++)
{
for (i2=0; i2<1000; i2++)
{
for (i3=0; i3<1000; i3++)
{
for (i4=0; i4<1000; i4++)
{};
};
};
};
getdate(&today);
gettime(&now);
printf("--", today.da_day, today.da_mon, today.da_year);
printf(" ::\n", now.ti_hour, now.ti_min, now.ti_sec);
/* 26-04-2022 00:38:14 = 6 min 57 sec v DOS */
}
Turbo C v 2.0 не показал достойного результата, хотя я расчитывал, что программа на Си должна работать быстрее, чем на Бейсике. Увы! Время того же порядка, что и у всех: 6 минут 57 секунд. Причём, заметьте! Все програмы (даже те, которые выполнялись изнутри языковой среды программирования) были запущены на ЭЛЕКТРОННОМ ДИСКЕ, значит, всё они держали в оперативной памяти. И жесткий диск тут не причём.
Потом я занялся сочинением того же самого на АССЕМБЛЕРЕ! Но так как «долгие годы уже не брал в руки фишки», то сместерил вариант для Дебагера. Запуск программы произвёл из командного файла. А результат работы получил в виде протокола при помощи перенаправления потока. Таким образом, вместо одного файла программы, у меня оказалось несколько разных файлов:
Вот командный файл PROBA.BAT
@echo off
cls
date<yes.txt
time<yes.txt
echo -------------------
debug <upr.txt >prot.txt
echo.
echo -------------------
date<yes.txt
time<yes.txt
Файл yes.txt ничего в себе не содержит, кроме нажатия одного <Enter>. Т.е. два байта <ВК>, <ПС> = 0D, 0A – перевод строки и возврат каретки. (Смешные термины? Да? Это дремучее наследие пишущих машинок… Практически, это всё, что от них уцелело).
Попутно я посетую, что Бейсик оказался более функционален. Посмотрите с какой лёгкостью он выводит текущую Дату и Время! Всего лишь обращается к готовым глобальным текстовым строкам! И какой маразм начинается в Си и в Ассемблере, чтобы получить тоже самое! В Си нужно подключить Хедр <DOS.H>, создать для даты и времени свою структуру. Вызвать функцию getdate() или gettime() передав им в качестве параметра указатель на нужную структуру. А потом ещё помнить при выводе ИМЕНА элементов структуры, чтобы правильно обратиться к каждому. Вот эта мутатень: <имя структуры.da_day>, <имя структуры.da_mon>, <имя структуры.da_year>, <имя структуры.ti_hour>, <имя структуры.ti_min>, <имя структуры.ti_sec> . Конечно, я не спорю, что при этом появляется возможность оперирования сразу отдельными частями данных. Поэтому дата и время представляются так, как хочет этого программист. А в Бейсике так, как это угодно СИСТЕМЕ. Но разница в восприятии информации настолько незначительна, и человек так быстро адаптируется к новому, что, честное слово! – не стоило из-за этого городить весь этот огород. Я так считаю.
А уж сколько мук я испытал, когда искал ошибки в программе на Си!!! Пока не догадался написать всё МАЛЕНЬКИМИ БУКВАМИ! И поменять местами Хедры, чтобы они были в АЛФАВИТНОМ ПОРЯДКЕ. Не знаю, что именно помогло. Но в конце концов все ошибки ушли сами. И всё заработало.
Но, вернёмся к Дебагеру! Я показал вам только командник для запуска программы. А где сама программа?
Вот она.
Файл UPR.TXT
a 100
mov cx,0064
push cx
mov cx,03e8
push cx
mov cx,03e8
push cx
mov cx,03e8
nop
loop 010f
pop cx
loop 010b
pop cx
loop 0107
pop cx
loop 0103
nop
u 100 11b
r
g=100 11b
q
Между последним нопиком и командой Дебагера u 100 11b обязателен пропуск в виде одной пустой строки! Это выведет Дебагер из режима ассемблирования, в который он попадает сразу же по команде a 100 в самом начале. Команда U 100 11B – не обязательна. Я её поставил для красоты, чтобы в выходной протокол работы вышла ещё и набранная программа со всеми кодами и адресами. И команда R – тоже только для информации о регистрах. А вот команда G=100 11B – она как раз и совершает ЗАПУСК программы на исполнение, и ловит точку останова последнего НОП-ика по адресу 11B . Q - это просто выход из Дебагера.
А вот что получилось при выводе в протокол!
Файл PROT.TXT
-a 100
184B:0100 mov cx,0064
184B:0103 push cx
184B:0104 mov cx,03e8
184B:0107 push cx
184B:0108 mov cx,03e8
184B:010B push cx
184B:010C mov cx,03e8
184B:010F nop
184B:0110 loop 010f
184B:0112 pop cx
184B:0113 loop 010b
184B:0115 pop cx
184B:0116 loop 0107
184B:0118 pop cx
184B:0119 loop 0103
184B:011B nop
184B:011C
-u 100 11b
184B:0100 B96400 MOV CX,0064
184B:0103 51 PUSH CX
184B:0104 B9E803 MOV CX,03E8
184B:0107 51 PUSH CX
184B:0108 B9E803 MOV CX,03E8
184B:010B 51 PUSH CX
184B:010C B9E803 MOV CX,03E8
184B:010F 90 NOP
184B:0110 E2FD LOOP 010F
184B:0112 59 POP CX
184B:0113 E2F6 LOOP 010B
184B:0115 59 POP CX
184B:0116 E2EF LOOP 0107
184B:0118 59 POP CX
184B:0119 E2E8 LOOP 0103
184B:011B 90 NOP
-r
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=184B ES=184B SS=184B CS=184B IP=0100 NV UP EI PL NZ NA PO NC
184B:0100 B96400 MOV CX,0064
-g=100 11b
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=184B ES=184B SS=184B CS=184B IP=011B NV UP EI PL NZ NA PO NC
184B:011B 90 NOP
-q
26-04-2022 02:36:46.37
26-04-2022 02:46:47.69
Дату и время начала и конца я срисовал с экрана и дописал в конец протокола сам. Хотя наверное можно было модифицировать командник и создавать протокол вначале, дописывая в конец файла PROT.TXT и дату и время. Но я не стал мудрить и сделал всё ручками. Поэтому и дата правильная (как в Си) и время без буквы A или P в конце. Результат работы Дебагера НЕ УДИВЛЯЙТЕСЬ! 10 минут!!! Т.е. он проигрывает всем языкам, кроме QBasic-а. Почему? Ведь программа выполняется в машинных кодах! Занимает всего 27 байт! Не считая последнего НОП-ика. Который 28-ой. Почему же 10 МИНУТ?!
А сравните размеры программ на других языках:
28 байт под Дебагер
10 101 байт на Си
15 648 байт на Квик Бейсике
19 152 байт на Поуэр Бейсике
Турбо Бейсик EXE не дал сгенерировать.
А Кю Бейсик в принципе этого делать не умеет.
Но, тем не менее, время выполнения у них меньше, чем у Дебагера!
Дебагер 10 минут 1 секунда
Си 6 минут 57 секунд
Квик Бейсик 2 минуты 19 секунд
Поуэр Бейсик 8 минут 30 секунд
Турбо Бейсик 6 минут 56 секунд
Кю Бейсик 2 часа 6 минут 40 секунд
Почему же? Потому что! Потому что машинные коды в Дебагере выполняются не оптом, а в режиме ОТЛАДКИ, то есть с прерыванием после выполнения каждой инструкции и отслеживанием адреса для ТОЧКИ ОСТАНОВА. Практически, это равносильно работе Кю Бейсика в режиме ИНТЕРПРЕТАТОРА. Только здесь выполняемый код занимает чуть-чуть в машинных инструкциях, а у Кю Бейсика ещё и код занимает килобайты, хотя мы этого и не видим (поскольку нет EXE-файла). Вот поэтому! Я так думаю…
А вот так будет выглядеть настоящая ассемблерная программа:
PAGE 60,132
TITLE PROBA.ASM формат COM тест вложенных циклов
CODSEG SEGMENT PARA 'Code'
ASSUME CS:CODSEG,DS:CODSEG,SS:CODSEG,ES:CODSEG
ORG 100H ;счетчик команд для COM
START: call get_cmos ;вывести на экран дату и время
call print_vkpc ;вывести ВК, ПС
mov cx,0064h
METKA0: push cx
mov cx,03e8h
METKA1: push cx
mov cx,03e8h
METKA2: push cx
mov cx,03e8h
METKA3: nop
loop METKA3
pop cx
loop METKA2
pop cx
loop METKA1
pop cx
loop METKA0
call get_cmos ;вывести на экран дату и время
ret
;процедура print_vkpc - выводит управляющие символы ВК, ПС
print_vkpc proc near
mov al,0Dh
int 29h
mov al,0Ah
int 29h
ret
print_vkpc endp
;процедура get_cmos - читает текущую дату и время из CMOS
;и выводит их на экран в формате ДД-ММ-ГГГГ чч:мм:сс
get_cmos proc near
mov al,0Bh ;CMOS 0Bh - управляющий регистр B
out 70h,al ;порт 70h - индекс CMOS
in al,71h ;порт 71h - данные CMOS
and al,11111011b ;обнулить бит 2 (форма чисел - BCD)
out 71h,al ;и записать обратно
mov al,7 ;CMOS 07h - день
call print_cmos ;вывод на экран
mov al,'-' ;минус
int 29h ;вывод на экран
mov al,8 ;CMOS 08h - текущий месяц
call print_cmos
mov al,'-' ;еще один минус
int 29h
mov al,32h ;CMOS 32h - две старшие цифры года
call print_cmos
mov al,9 ;CMOS 09h - две младшие цифры года
call print_cmos
mov al,' ' ;пробел
int 29h
mov al,' ' ;пробел
int 29h
mov al,' ' ;пробел
int 29h
mov al,4 ;CMOS 04h - час
call print_cmos
mov al,':' ;двоеточие
int 29h
mov al,2 ;CMOS 02h - минута
call print_cmos
mov al,':' ;двоеточие
int 29h
mov al,0h ;CMOS 00h - секунда
call print_cmos
ret
get_cmos endp
; процедура print_cmos
; выводит на экран содержимое ячейки CMOS с номером в AL
; считает, что число, читаемое из CMOS, находится в формате BCD
print_cmos proc near
out 70h,al ;послать AL в индексный порт CMOS
in al,71h ;прочитать данные
push ax
shr al,1 ;выделить старшие четыре бита
shr al,1
shr al,1
shr al,1
add al,'0' ;добавить ASCII-код цифры 0
int 29h ;вывести на экран
pop ax
and al,0Fh ;выделить младшие четыре бита
add al,30h ;добавить ASCII-код цифры 0
int 29h ;вывести на экран
ret
print_cmos endp
CODSEG ENDS
END START
А вот так она транслируется, линкуется и переделывается из EXE-формата в COM-формат.
>masm proba.asm
>link proba.obj
>exe2bin proba.exe proba.com
И получается PROBA.COM размером в 145 байт! Правда, при выполнении время точь-в-точь совпадает с временем Дебагера (??). И этого я уже объяснить не могу… Так же, как не могу объяснить скорострельность Quick Basic…
И что хотите со мной делайте.
(Я могу лишь робко предположить, что раз процессор на этой машинке 64-х разрядный, значит, 16-ти разрядные коды он выполняет в неродном режиме. Наверное, от этого… )
Одно я утверждаю точно: вложенные циклы с числом повторений 1 * 10 ^ 11 будут занимать на современной технике время от минут до десятков.
И это для 11-ой степени! А для 17-й это будет в 1 000 000 раз больше!
А так как все циклы холостые (без вычислительной нагрузки), то надо ещё накинуть пару – тройку порядков (для порядка). И тогда получается, что простейшая позиция в Шахматах методом слепого перебора решается … за … МИЛЛИАРД ЛЕТ!!! А уж о свозном переборе из начальной позиции и мечтать не моги. Скорее Солнце потухнет, чем пространство состояний Шахмат будет пройдено хоть на 1%.
Вы представляете?!
P.S. А вы мне тут мозги канифолите какой-то криптовалютой! Да ваша крипта, по сравнению с Шахматами – тьфу! И ничего более!
Вот так.
P.P.S.
Кстати, это наглядно доказывает необоснованность утверждений о самозарождении Жизни на Земле, необоснованности упования Человечества на незримую силу Эволюции, на невидимую силу Стихии рынка, на слепую саморегуляцию; поэтому так смешны ссылки Чиновников на «общемировые тенденции», на «всеобщий тренд развития», особливо на «технический прогресс»! За всеми этими якобы самопроизвольными процессами скрывается чья-то воля. И весь вопрос в том, насколько зла эта воля: какому критерию она служит, эта самая воля? Если она озабочена только собственным процветанием! То естественно, что она способна привести вас только на кладбище. И конечной её целью, как бы эта воля не маскировалась, не упиралась, не кричала об обратном, является низведение вас к нулю. Чтобы вас было поменьше, а её побольше.
И как же наивны те люди, которые верят в «доброго Царя-батюшку», а потом начинают сокрушаться: вот опять какая-то зараза привязалась, вот опять цены скаканули, вот опять и наука, и медицина, и образование финансируются «по остаточному принципу». А мы так верили. А мы так надеялись. Что всё наладится.
Зря верили. И зря надеялись.
Всякая власть обеспечивает сначала собственные насущные потребности и питает свои интересы и амбиции, а всем остальным … что останется… Если останется…
А подумать о перспективе на будущее просто некому. Какой смысл думать на перспективу? Когда это будущее непредсказуемо! И завтра может ахнуть в любом месте! Вот и занимаются все «тушением очагов возгораний» различных текущих проблем общества. А до перспективного планирования просто руки не доходят. В этом общемировом раздрае и полной несогласованности, и антагонистических противоречиях, и «волотильности», и «пандемийности» прослеживается только один устойчивый тренд – на всеобщую деградацию: и природной среды, и самого человека.
Тут либо на Господа Бога уповать, на Деда Мороза, на Хоттабыча, на Великого и Ужасного. Хотя уже всем понятно, что эти упования тщетны. Либо отгородиться ото всех «железным занавесом» и прекратить всякие сношения с внешним миром. Тогда только можно начать строить собственную жизнь по собственным правилам в собственных интересах. И не зависеть ни от кого. Потому что переделать весь мир – это не в силах человека. Попробуй их всех собери! Попробуй их всех распропагандируй! Убеди! – Это невозможно, это компетенция Всевышнего. Но ведь это тоже тупиковый путь? Это всё уже было в нашей Истории! «Железный занавес» устроили, а построить так ничего и не смогли. Вроде как начали, начали… А чем закончилось? Все в курсе. Ничем.
И куда теперь?
P.P.P.S.
Вот только не надо мне мозги пудрить своими Windows-ми 8,9,10,11… Я тоже могу! Сейчас программулька закончит свою работу под Windows-7 64-bit, и я вам предоставлю результат. Удивлю по полной программе. По вот этой:
Sub Proba()
'
' Proba Макрос "Тест вложенных циклов"
Dim MyStr As String
Dim i1 As Integer, i2 As Integer, i3 As Integer, i4 As Integer
MyStr = Str(Date) + " " + Str(Time)
For i1 = 1 To 100
For i2 = 1 To 1000
For i3 = 1 To 1000
For i4 = 1 To 1000
Next i4
Next i3
Next i2
Next i1
MyStr = MyStr + " *** " + Str(Date) + " " + Str(Time)
MsgBox (MyStr)
' Макрос создан 27.04.2022 Мудman
'
End Sub
Да! Внутри Word и Excel живёт свой Бейсик. Он и выполняет Макросы. И на этом Бейсике я написал вот эту (см.выше) программульку. И запустил…
И получил…
Для Microsoft Word
27.04.2022 10:20:44 *** 27.04.2022 10:40:57
Итого 20 минут 13 секунд!
Для Microsoft Excel
27.04.2022 10:41:53 *** 27.04.2022 11:02:04
Итого 20 минут 09 секунд!
А теперь сравните с ДОС режимом и программами, которые я привёл выше. А? Что? Съели?
А чтобы вы не думали, что я вас надуваю, я вам и картинки приведу (см.файл изображения в самом начале).
P.P.P.P.S.
Короче, Склифосовский.
Всем вам домашнее задание от Мудman-а Великого и Ужасного: написать такую же программу из четырёх вложенных пустых циклов с общим количеством повторений 10 в степени 11, но на PASCAL-е. И чтобы вначале выдавала строчку с системной датой и временем. И такую же в конце, после прогона всех циклов. И посмотрим, какой мощой ваши тачки снабжены! А? Слабо?
А я потом приду, и проверю!
Адью.
Все свободны.
11:09:45 27.04.2022 12CE4D989D50
Свидетельство о публикации №222042700636