«Как именно ты собираешься запрещать воздерживание? „
Если это вопрос ко мне — то аннулированием всех оценок человека если он не проголосовал за все работы в секции где взялся голосовать. Ну опять таки с поправкой на голосование за себя выше.
Ну авторов можно сделать исключениями. По хорошему они как раз должны воздерживаться чтобы не влиять на результат своей работы. По моему это самое логичное.
Среднее это именно среднее — при этом если кто-то воздерживается, то он просто не влияет на результат.
А если всех кто воздержался заменять на «ну так себе», то это именно значит что они голосуют «так себе» и влияют на результат.
Вещи неравнозначные и по мне так неучёт воздерживающихся логичнее по сути процесса.
Если запретить воздерживание, то разница между подсчётами просто исчезнет.
«Но при подсчёте суммы тоже иногда заменяют голоса воздержавшихся чем-то вроде среднего»
Сомнительная практика — так если 1 голос 10 и другой воздержался, то среднее — 10. А если 10+5/2, то 7,5.
Тут или запрещать не голосовать либо считать по среднему.
Среднее — более объективная оценка если можно не голосовать. Когда человек _воздерживается_ от голосования это означает именно то, что он не хочет чтобы его мнение влияло на итоговую оценку, а не то что он голосует против.
Отличная статья!
Никак не ожидал что даже для обвязочного кода демы будет достаточно cc65 — рассматривал код который он генерирует и плакать хотелось. Особенно адово с локальными переменными/параметрами дела обстоят. Всё-таки для 8-битных реалий компилятор — это падение производительности где то на порядок. Хотя если всё на глобальных переменных мутить может и будет получше.
На другом ресурсе указали похоже не только на корни стиля, но и источник для оцифровки видеоматериала: youtu.be/gkxGs4ETeg4
:D Даже не знал что есть такой стиль.
P.S.
Причесал код и внедрил условия и сделал все ключевые слова в нижнем регистре для консистентности. Ссылка на исходник потому изменилась: yadi.sk/d/fTZqZ1n12dD72A
Условия пишутся в любом месте инструкции:
@@ — всегда
@z или @nz — ноль/не ноль
@c @nc — перенос
@gt @gte — больше и больше-или-равно (пока не реализовано)
теперь работает такое:
r0 = $8
loop [ counter ] =-1 [ counter ]
r0 =-1 r0
pc = loop @nz // эта инструкция перейдёт на loop если не ноль
dw 0
org $0030
counter dw $0010
Проапгрейдил ассемблер Simpleton еще дальше, теперь программа берет внешний файл source.asm, собирает и исполняет его с адреса 0 пока не наткнётся на инструкцию с кодом 0 (R0 = R0).
Теперь поддерживаются ключевые слова =, org и dw с нюансами.
Программа теперь может выглядеть так:
R0 = $FFFF
R1 = $CCCC
R0 -= R1
[ first ] = R0
[ second ] =+1 [ first ]
[ third ] += 16
dw 0 // DEF WORD 0 помещает в текущую ячейку компиляции константу
org $0020 // компилируем теперь начиная с адреса $0020
first dw 0 // first и second теперь заданы
second dw 0 // как два нулевых слова в памяти
org $0030 // смещаем адрес компиляции в $0030
third dw forth // пример что в качестве DEF WORD слова можно указать символ, причём forward
forth = $1000 // через = значение символа задаётся напрямую без записи данных в память
dw 1 // эта единица в памяти программы следует сразу за $1000 (third)
Основные моменты — регистрозависимость всех идентификаторов и ключевых слов.
Имена регистров: R0-R4, R5 (он же SP), R6 (он же PC), R7 (он же FLAGS).
Машинные команды имеют вид
DEST OP SRC
Где SRC это один из регистров, константа/символ или адрес задаваемый как регистр или константа/символ в квадратных скобках.
OP это операторы в стиле Си:
= присваивание
=+1 инкремент
=-1 декремент
<?> сравнение
+=
-=
+c= то же что и += с учетом флага переноса
-c= то же что и -= с учетом флага переноса
DEST может быть всем тем же что и SRC кроме константы/символа (не в квадратных скобках)
Числовые константы/литералы или десятичные или начинаются с $ и тогда являются шестнадцатеричными.
Если строка начинается не с пробельного символа, то создаётся символ.
Если он предшествует машинной инструкции или dw, то в него записывается её адрес.
Если он предшествует знаку =, то в него записывается константа или значение символа по правую часть от знака. Формульная математика пока не поддерживается вообще.
Если он предшествует ключевому слову org, то он будет равнятся адресу куда переводит компиляцию этот org.
org переводит запись генерируемых инструкций на указанный адрес (origin)
dw прописывает в текущую ячейку данное — оно может быть или константой или символом.
В стиле ассемблера Zilog 80 (и не в стиле ассемблера Intel) имя символа в чистом виде означает адрес ячейки памяти если это метка, а не значение в этой памяти. Чтобы адресовать ячейку надо использовать квадратные скобки.
Т.е.
some_addr = $1000
R0 = some_addr // в R0 запишется $1000
R0 = [ some_addr ] // в R0 запишется значение в ячейке с адресом $1000
some_addr = R0 // такое вообще запрещено, т.к. в констансту нельзя писать, надо:
[ some_addr ] = R0 // а вот это запишет R0 в ячейку памяти
Чтобы проверить архитектуру на практике, пусть и виртуальной, решил написать то что доступно — эмулятор машины Simpleton 3.x, текущий исходник, если вдруг кому интересно, что конечно вряд ли, можно качнуть тут: yadi.sk/d/-PGx1pEBf_O6kw
Сейчас довёл его до уже нормально исполняющего простые инструкции ассемблера, так вот такой код на C++:
m.parseStart();
int line = 0;
m.parseLine( line++, "start R0 = $FFFF" ); // в R0 грузим константу $FFFF
m.parseLine( line++, " R1 = $CCCC" ); // в R1 грузим константу $CCCC
m.parseLine( line++, " R0 -= R1" ); // из R0 вычитаем R1 и заносим результат в R0
m.parseLine( line++, " [ first ] = R0" ); // в ячейку памяти по адресу first заносим R0
m.parseLine( line++, " [ second ] =+1 [ first ]" ); // в ячейку памяти по адресу second заносим инкремент ячейки first
m.parseLine( line++, " R0 = R0" ); // NOP и ноль - эмулятор останавливается на команде NOP
m.parseLine( line++, "first R0 = R0" ); // метка first ячейки с данными 0
m.parseLine( line++, "second R0 = R0" ); // метка second ячейки с данными тоже 0 (DW пока не делал)
m.parseEnd();
m.show();
while ( m.mem[ m.reg[ REG_PC ] ] != 0 ) // nop as stop
m.step();
m.show();
генерирует и исполняет следующий очищенный от C++ код на ассемблере Simpleton 3.x:
start R0 = $FFFF // в R0 грузим константу $FFFF
R1 = $CCCC // в R1 грузим константу $CCCC
R0 -= R1 // из R0 вычитаем R1 и заносим результат в R0
[ first ] = R0 // в ячейку памяти по адресу first заносим R0
[ second ] =+1 [ first ] // в ячейку памяти по адресу second заносим инкремент ячейки first
R0 = R0 // NOP и ноль - эмулятор останавливается на команде NOP
first R0 = R0 // метка first ячейки с данными 0
second R0 = R0 // метка second ячейки с данными тоже 0 (DW пока не делал)
Как видно синтаксис этого ассемблера строго подчиняется С-подобному обозначенному в статье синтаксису.
Код сей собирается, успешно исполняется и даёт после выполнения всех команд такую карту регистров и памяти:
Здесь видно что PC дошёл до 000A и остановился — это где первый искуственный NOP (R0 = R0) — check.
В R0 разница между FFFF и CCCC = 3333 — check.
В R1 — CCCC — check.
По адресу 000B хранится 3333 — это метка first — check.
По следующему адресу — метке second хранится увеличенное на 1 значение в first — 3334 — check!
Можно посмотреть в коды инструкций — адреса (а это между прочим forward reference для которых надо было запоминать адреса которые надо поправить после конца парсинга) 000B и 000C явно видно в ячейках с инструкциями по адресам 0006 и 0008-0009.
Забавное ощущение когда свой ассемблер делаешь виртуальной несуществующей машины. :D
Парсер и генератор кода конечно примитивный — лишь бы откровенных ошибок с подстановкой совсем уж неверных типов лексем не на свои места не было. Например косвенная адресация просто как флаг взводится и сбрасывается при встрече символов [ и ] поэтому такой код будет валидным: [ R0 = R1 ] и эквивалентен [ R0 ] = [ R1 ] (строго говоря валидно и [ R0 = R1
Но тем не менее в мнемониках кодировать весьма удобно становится. :)
Когда еще будет время реализую условия и попробую делать циклы.
Кстати, если вспоминать о бейсике в частности и ЯВУ в целом, то для Manchester Mark I/II было разработано несколько ЯВУ с общим названием Autocode: en.wikipedia.org/wiki/Autocode
Но забавным мне показался второй — Mark 1 Autocode, причём он довольно широко использовался, судя по википедии.
Пример программы:
Что можно интересного сказать:
— одна операция — одна строка
— 18 целочисленных переменных с именами от n1 до n18
— столько вещественных переменных сколько было доступно прочей памяти с именами вида v1..v999
— оператор j7 переходит на строку пронумерованную как 7, после запятой пишется условие
— если нужно обращаться с ячейками памяти как с массивом, то используется конструкция vnx, например vn10 которая означает переменную v… с номером который хранится в переменной n10
Конечно это было прямо несколько шагов вперёд по сравнению с программирование в символах телетайпа.
Ну про инженеров — это я вообще ко всему коллективу работавшему над машиной обращался, там всё-таки согласно википедии 300000 человеко-часов было затрачено даже на предыдущую итерацию Mark I (Manchester Baby) у которого было всего 7 машинных команд (практически эзотерическая машина!) из которых арифметико-логические только вычитание и смена знака числа. Но вообще да, мозговой центр там был сплошь из профессоров и кандидатов наук.
я уже не понимаю зачем там вам нужно что-то перечитывать. что вы собираетесь найти? всё просто так как я констатировал и всё. двойных смыслов в тех фразах нет, это не афоризмы.
P.S.
Раскопал, что такая странная кодировка на самом деле не странная, а просто повторяет кодировку британского телеграфного кода тех лет — вставил картинку в статью.
P.P.S.
Интересно, залез сейчас взглянуть на документацию еще какого-нибудь из предтеч. И выбрал в этот раз Manchester Mark I — его «родитель» Manchester Baby был вообще первым компьютером с программой хранимой в ОЗУ. Этот компьютер был некоммерческим, поэтому документации какой то официальной долгое время не было и почитать можно было только статьи в разные журналы и издания. Например: curation.cs.manchester.ac.uk/computer50/www.computer50.org/kgill/mark1/natureart.html curation.cs.manchester.ac.uk/computer50/www.computer50.org/kgill/mark1/natureart51.html curation.cs.manchester.ac.uk/computer50/www.computer50.org/kgill/mark1/conf.html curation.cs.manchester.ac.uk/computer50/www.computer50.org/kgill/mark1/ssem.html
Так вот — несмотря на то что в этих статьях подробно описываются такие вещи как память, аккумулятор и счётчик инструкций — слово register не используется вообще.
К 1951 году коммерческая жилка всё-таки врывается в цех и выпускается коммерческий вариант (с поднятыми характеристиками) Manchester Mark I с названием Ferranti Mark I.
Для него конечно же уже появляется официальная документация по программированию за авторством самого Алана Тюринга (!) которую можно почитать тут: curation.cs.manchester.ac.uk/computer50/www.computer50.org/kgill/mark1/RobertTau/turing.pdf
Так вот — если там тоже дать на поиск слово «register» то оно найдётся два раза, но не в тексте инструкции, а в предисловии которое написано много много позже. Сам Алан Тюринг нигде не использует слово «регистр». Надо заметить, правда, что как ОЗУ так и аккумулятор там хранились на электронно-лучевых трубках (именно ЭЛТ!) и поэтому к ним чаще всего применяется эпитет «tubes». Такое ощущение, что британцы слово «регистр» переняли у американцев когда то позднее.
P.S.
Что касается UNIVAC — это один из первых компьютеров общего назначения вообще и видно что в нём регистры памяти противопоставляются несмотря на то что всё сделано на электронно-лучевых-трубках и первое же место где слово register встречается во второй документации говорит что registers are identical to memory, но присутствуют в единичных экземплярах и как бы находятся между памятью и вычислительным устройством — и тут приводится аналогия с табло калькулятора. В общем у тех кто писал документацию к UNIVAC уже есть сложившаяся терминология в этом смысле и по видимому так просто корней не найти, т.к. скорее всего это были кулуарные штуки конкретных коллективов людей работавших в оборонке под грифом секретно до того.
Если это вопрос ко мне — то аннулированием всех оценок человека если он не проголосовал за все работы в секции где взялся голосовать. Ну опять таки с поправкой на голосование за себя выше.
А если всех кто воздержался заменять на «ну так себе», то это именно значит что они голосуют «так себе» и влияют на результат.
Вещи неравнозначные и по мне так неучёт воздерживающихся логичнее по сути процесса.
Если запретить воздерживание, то разница между подсчётами просто исчезнет.
Сомнительная практика — так если 1 голос 10 и другой воздержался, то среднее — 10. А если 10+5/2, то 7,5.
Тут или запрещать не голосовать либо считать по среднему.
Никак не ожидал что даже для обвязочного кода демы будет достаточно cc65 — рассматривал код который он генерирует и плакать хотелось. Особенно адово с локальными переменными/параметрами дела обстоят. Всё-таки для 8-битных реалий компилятор — это падение производительности где то на порядок. Хотя если всё на глобальных переменных мутить может и будет получше.
:D Даже не знал что есть такой стиль.
Причесал код и внедрил условия и сделал все ключевые слова в нижнем регистре для консистентности. Ссылка на исходник потому изменилась: yadi.sk/d/fTZqZ1n12dD72A
Условия пишутся в любом месте инструкции:
@@ — всегда
@z или @nz — ноль/не ноль
@c @nc — перенос
@gt @gte — больше и больше-или-равно (пока не реализовано)
теперь работает такое:
Теперь поддерживаются ключевые слова =, org и dw с нюансами.
Программа теперь может выглядеть так:
Основные моменты — регистрозависимость всех идентификаторов и ключевых слов.
Имена регистров: R0-R4, R5 (он же SP), R6 (он же PC), R7 (он же FLAGS).
Машинные команды имеют вид
Где SRC это один из регистров, константа/символ или адрес задаваемый как регистр или константа/символ в квадратных скобках.
OP это операторы в стиле Си:
= присваивание
=+1 инкремент
=-1 декремент
<?> сравнение
+=
-=
+c= то же что и += с учетом флага переноса
-c= то же что и -= с учетом флага переноса
DEST может быть всем тем же что и SRC кроме константы/символа (не в квадратных скобках)
Числовые константы/литералы или десятичные или начинаются с $ и тогда являются шестнадцатеричными.
Если строка начинается не с пробельного символа, то создаётся символ.
Если он предшествует машинной инструкции или dw, то в него записывается её адрес.
Если он предшествует знаку =, то в него записывается константа или значение символа по правую часть от знака. Формульная математика пока не поддерживается вообще.
Если он предшествует ключевому слову org, то он будет равнятся адресу куда переводит компиляцию этот org.
org переводит запись генерируемых инструкций на указанный адрес (origin)
dw прописывает в текущую ячейку данное — оно может быть или константой или символом.
В стиле ассемблера Zilog 80 (и не в стиле ассемблера Intel) имя символа в чистом виде означает адрес ячейки памяти если это метка, а не значение в этой памяти. Чтобы адресовать ячейку надо использовать квадратные скобки.
Т.е.
Сейчас довёл его до уже нормально исполняющего простые инструкции ассемблера, так вот такой код на C++:
генерирует и исполняет следующий очищенный от C++ код на ассемблере Simpleton 3.x:
Как видно синтаксис этого ассемблера строго подчиняется С-подобному обозначенному в статье синтаксису.
Код сей собирается, успешно исполняется и даёт после выполнения всех команд такую карту регистров и памяти:
Здесь видно что PC дошёл до 000A и остановился — это где первый искуственный NOP (R0 = R0) — check.
В R0 разница между FFFF и CCCC = 3333 — check.
В R1 — CCCC — check.
По адресу 000B хранится 3333 — это метка first — check.
По следующему адресу — метке second хранится увеличенное на 1 значение в first — 3334 — check!
Можно посмотреть в коды инструкций — адреса (а это между прочим forward reference для которых надо было запоминать адреса которые надо поправить после конца парсинга) 000B и 000C явно видно в ячейках с инструкциями по адресам 0006 и 0008-0009.
Забавное ощущение когда свой ассемблер делаешь виртуальной несуществующей машины. :D
Парсер и генератор кода конечно примитивный — лишь бы откровенных ошибок с подстановкой совсем уж неверных типов лексем не на свои места не было. Например косвенная адресация просто как флаг взводится и сбрасывается при встрече символов [ и ] поэтому такой код будет валидным: [ R0 = R1 ] и эквивалентен [ R0 ] = [ R1 ] (строго говоря валидно и [ R0 = R1
Но тем не менее в мнемониках кодировать весьма удобно становится. :)
Когда еще будет время реализую условия и попробую делать циклы.
Но забавным мне показался второй — Mark 1 Autocode, причём он довольно широко использовался, судя по википедии.
Пример программы:
Что можно интересного сказать:
— одна операция — одна строка
— 18 целочисленных переменных с именами от n1 до n18
— столько вещественных переменных сколько было доступно прочей памяти с именами вида v1..v999
— оператор j7 переходит на строку пронумерованную как 7, после запятой пишется условие
— если нужно обращаться с ячейками памяти как с массивом, то используется конструкция vnx, например vn10 которая означает переменную v… с номером который хранится в переменной n10
Конечно это было прямо несколько шагов вперёд по сравнению с программирование в символах телетайпа.
Но если прям интересно, то тут (документация по UNIVAC I от 59 года): www.bitsavers.org/pdf/univac/univac1/UNIVAC1_Programming_1959.pdf
Это страница 16 со слов: «The arithmetic registers are identical to memory cells except...»
Раскопал, что такая странная кодировка на самом деле не странная, а просто повторяет кодировку британского телеграфного кода тех лет — вставил картинку в статью.
Интересно, залез сейчас взглянуть на документацию еще какого-нибудь из предтеч. И выбрал в этот раз Manchester Mark I — его «родитель» Manchester Baby был вообще первым компьютером с программой хранимой в ОЗУ. Этот компьютер был некоммерческим, поэтому документации какой то официальной долгое время не было и почитать можно было только статьи в разные журналы и издания. Например:
curation.cs.manchester.ac.uk/computer50/www.computer50.org/kgill/mark1/natureart.html
curation.cs.manchester.ac.uk/computer50/www.computer50.org/kgill/mark1/natureart51.html
curation.cs.manchester.ac.uk/computer50/www.computer50.org/kgill/mark1/conf.html
curation.cs.manchester.ac.uk/computer50/www.computer50.org/kgill/mark1/ssem.html
Так вот — несмотря на то что в этих статьях подробно описываются такие вещи как память, аккумулятор и счётчик инструкций — слово register не используется вообще.
К 1951 году коммерческая жилка всё-таки врывается в цех и выпускается коммерческий вариант (с поднятыми характеристиками) Manchester Mark I с названием Ferranti Mark I.
Для него конечно же уже появляется официальная документация по программированию за авторством самого Алана Тюринга (!) которую можно почитать тут: curation.cs.manchester.ac.uk/computer50/www.computer50.org/kgill/mark1/RobertTau/turing.pdf
Так вот — если там тоже дать на поиск слово «register» то оно найдётся два раза, но не в тексте инструкции, а в предисловии которое написано много много позже. Сам Алан Тюринг нигде не использует слово «регистр». Надо заметить, правда, что как ОЗУ так и аккумулятор там хранились на электронно-лучевых трубках (именно ЭЛТ!) и поэтому к ним чаще всего применяется эпитет «tubes». Такое ощущение, что британцы слово «регистр» переняли у американцев когда то позднее.
Тьфу, смешались люди-кони, «электронно-лучевых-трубках» читать как «электронных лампах».
Что касается UNIVAC — это один из первых компьютеров общего назначения вообще и видно что в нём регистры памяти противопоставляются несмотря на то что всё сделано на электронно-лучевых-трубках и первое же место где слово register встречается во второй документации говорит что registers are identical to memory, но присутствуют в единичных экземплярах и как бы находятся между памятью и вычислительным устройством — и тут приводится аналогия с табло калькулятора. В общем у тех кто писал документацию к UNIVAC уже есть сложившаяся терминология в этом смысле и по видимому так просто корней не найти, т.к. скорее всего это были кулуарные штуки конкретных коллективов людей работавших в оборонке под грифом секретно до того.