Вы представляете

Когда-то давным давно я мечтал о собственном компьютере, который сможет решать все задачи, которые я только захочу. Он будет мощный, быстрый, легко программируемый! – Думалось мне тогда.

Прошли годы.

Через мои руки прошли не один, и не два компьютера.

Я уже сбился со счёта всем этим программам, языкам программирования, оболочкам, драйверам, модификациям, устройствам и операционным системам. В моей голове уже давно КАША.

Хочется напиться, и забыться. А на утро проснуться с абсолютно чистой памятью. Мне иногда кажется, что стариком меня делает не тело, а голова. Если на протяжении 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


Рецензии