Программа отлаживалась достаточно долго и недостаточно аккуратно, поэтому код в разных разделах может не совпадать. Образцовая правильная версия - в разделе "код установки стопсов", остальные версии могут быть устаревшими.
Принцип:
Вообще, квадратный корень считается легко. Из формулы суммы членов арифметической прогрессии получается, что сумма первых n нечётных чисел = n^2. Из чего следует
Откуда достаточно легко выводится алгоритм вычисления квадратного корня, использовавшийся с начала 1950-х годов арифмометрами с автоматическим вычислением квадратных корней фирмы Friden. Вот тут про него можно прочитать подробнее.
Правда, у нас нет каретки, которую можно сдвигать. Вместо этого мы будем при расчёте каждого разряда увеличивать число, из которого вычитаем корень, в 100 раз, а вычисляемый корень - в 10 раз, а на каждое увеличение единицы - будем прибавлять одни и те же пятёрки. Ещё надо предусмотреть возможность того, что исходное число будет больше 100 - тогда надо вычислить порядок десятки, на который домножается полученный корень, и вычислять корень из исходного числа, сдвинутого на нужное количество пар разрядов.
Использование:
Псевдокод:
1. Получить число.
2. Расчитать степень десятки (сколько раз можно убрать пару нулей)
3. Вычислить корень после сдвига.
4. Распечатать корень и сдвиг
begin:
Read kbd*5, I // тут будет исходное число.
goto around_answer;
answer: print II, IV; goto begin;
around_answer:
III=5
II=IV=0
next: K=III<<2;
if(I>=K)
{
III=K;
IV++;
if (I!=K) goto next;
//II=1; goto answer; //Мы наткнулись на степень сотни! Для простоты игнорируем этот случай.
}
//в этом месте в III у нас 5, сдвинутое на нужную степень, а в IV - степень десятки ответа (она не понадобится до самой печати)
II=III; //записываем исходную (сдвинутую) пятёрку
I-=II; //вычитаем первый член. Оно получается - иначе бы мы сдвинулись ещё на один разряд.
next_step:
II+=III;
II+=III;
next_digit:
I-=II;
if (I==0) //мы нашли точный ответ
{
II+=III;
goto answer;
}
if (I>0) goto next_step;
I+=II;//прибавляем последнее число, которое вычли.
II-=III;//убираем пятёрку в конце
I<<=2; if (overflow) goto answer;
II<=1;
II+=III;//добавляем пятёрку в конце - но уже в следующий разряд.
goto next_digit; // одну пятёрку мы добавили, ещё две пока не нужны - поэтому next _digit находится после next_step;
Программа:
Переменные: В начале: в II вычисляемое, в I - 5, сдвинутое на несколько пар разрядов влево. В конце: I - вычисляемое (исходно, число*5) II - результат. 10,20- временные переменные K - шаг (5*100^х). 41 - степень десятки результата При первом запуске 10, 20, I, II, надо обнулить. Константы: 01 - 9Е9 11 - 1 31 - 5 1: read K; clr; 1: read 10; clr; 1: read 41; clr; //Read kbd*5, II // тут будет исходное число. //goto around_answer; //answer: print II, 41; goto begin; //around_answer; 1: stop; read kbd; II+=; prn(); 1: read kbd; II+=; 10+; //*2 *1 1: read kbd; II+=; 10+ clr; //*3 *2 1: read 10; II+=; clr; //*5 2: read II; prn(); clr; 2: read 41; prn(); clr; newline; goto prog1; goto backward1; 1: read 31; K+=; //в 31 - 5 1: read 11; II+=; goto prog2; // увеличим II на единицу - чтобы порядок в "100 ровно" превратилось в "порядок 101" - и ответ читался бы не как 10Е0, а как 1Е1 //I=K<<2 2: backward2: read K; 10+=; 20+=; I+=; // 1 1 1 2: read K; 10+=; 20+=; I+=; // 2 2 2 12: forward1: read 10; 20+=; I+=; // 2 4 4 12: read 20; 10+=; I+=; // 6 4 8 12: read I; 10+=; 20+=; // 14 12 8 12: read 10; 20+=; I+=; clr;// 0 26 22 !!!newline 12: read 20; I+=;// 0 26 48 12: read 20; I+=;// 0 26 74 12: read 20; I+=; clr;// 0 0 100 //if(II>I) // { // K=r30; // r41++; // goto next; // } 2: read II; I-=; wait; goto prog1; goto forward1;// стопс задержки ставим здесь, а не на следующем шаге! Чтобы он анализировал ЭТО значение I 1: read II; 10+=; 20+=; goto prog2; goto forward2;//1 1 1 // первая строка сдвига II<<=1; из конца программы. 1: forward1: read II; I+=; goto forward1; 1: if (I>=0) read I; clr; goto forward1;// то есть, II<I. С этого места начинаем считать корень. 1: forward1: read K; clr; //технически, он находится на шаг раньше, поэтому по условному оператору переход не осуществляется. 1: read I; K+=; clr; 1: read 11; 41+=; goto backward2;//в r11 - 1 //в этом месте в K у нас 5, сдвинутое на нужную степень, а в r41 - степень десятки ответа (она не понадобится до самой печати) // II--; //мы увеличивали число на единицу, надо это исправить. // I=II; //переносим изучаемое число в I // II=K; //записываем исходную (сдвинутую) пятёрку //I-=II; //вычитаем первый член. Оно получается - иначе бы мы сдвинулись ещё на один разряд. //next_step: // II+=K; // II+=K; //next_digit: // I-=II; 1: forward1: read 11; II-=; 1: read II; I+=; clr; //I=II; II=0; 1: read K; II+=; //II=K 1: read II; I-=; 1: backward1: read K; II+=; 1: read K; II+=; 1: forward1: read II; I-=; // if (I==0) //мы нашли точный ответ // { // II+=K; // goto answer; // } 1: read I; if (!=0) goto forward1; 1: read K; II+=; clr; goto prog2; goto forward2; //мы сюда попадаем только если I==0, поэтому обнулять его не нужно. //if (I>0) goto next_step; 1: if(I>=0) goto backward1; //I+=II;//прибавляем последнее число, которое вычли. //II-=K;//убираем пятёрку в конце 1: forward1: read II; I+=; 1: read K; II-=; // if (II>9E9) goto answer; 1: read 01; II-=; goto forward1;// в 01 - 9Е9 1: if (II>0) read I; clr; goto prog2; goto forward2; //Окей, мы нашли ответ. Обнуляем остаток исходного числа, и идём печатать ответ. 1: forward1: read 01; II+=; // Восстанавливаем I // I<<=2; 1: read I; 10+=; 20+=; // 1 1 I1 1: read I; 10+=; 20+=; clr; // 2 2 I0 1: read 20; I+=; goto forward1; // 2 2 I2 //II<<=1; //1: read II; 10+=; 20+=; //1 1 1 это выполняется в предыдущем блоке сдвига 2: forward2: read II; 10+=; goto prog1; // 2 1 II1 1: read 10; II+=; 20+=; //2 3 II3 1: read 10; II+=; 20+=; clr; //0 5 II5 1: read 20; II+=; clr;//0 0 II10 //II+=K;//добавляем пятёрку в конце - но уже в следующий разряд. //goto next_digit; // одну пятёрку мы добавили, ещё две пока не нужны - поэтому next _digit находится после next_step; 1: read K; II+=; goto forward1; goto backward1;
Код установки стопсов:
Наиболее точная версия программы. Стопсы приведены для версии, которая работает в одну строку, распечатывая только исходное число и корень из него.
Если вы хотите получить красивую распечатку таблицы, как на видео, уберите все стопсы 5/3, а на каждую команду goto backward добавьте newline (17/3). Как вариант, можно оставить 5/3 у команд 1,2,4,5,6,7 - тогда исходное число и результат будут печататься аккуратно и понятно, а всё остальное будет красивой табличкой.
01 1 0(+2)3/10 5/3 15/6 // 1: read K; clr; 02 1 5/3 10/4 15/6 23/3 36/3 39/3 // 1: read 41; clr; 03 1 10/3 12/4 // 1: read kbd; II+=; 04 1 5/3 10/3 12/4 15/6 39/4 // 1: read kbd; II+=; 10+; //*2 *1 05 1 5/3 12/4 15/6 39/4 // 1: read kbd; II+=; 10+ clr; //*3 *2 06 1 5/3 10/4 12/4 15/6 39/3 // 1: read 10; II+=; clr; //*5 07(1) 5/3 12/4 15/6 23/3 40/3 // 2: read 01; II+=; // Восстанавливаем II 08(1) 10/4 12/3 15/6 // 2: read II; prn(); clr; 09(1) 5/4 10/4 15/6 17/3 19/3 23/3 33/4 36/3 // 2: read 41; prn(); clr; newline; goto prog1; goto backward1; 10 1 3/4 5/3 15/6 23/3 37/3 // 1: read 31; K+=; //в 31 - 5 11 1 5/3 12/4 15/6 19/4 23/3 39/3 // 1: read 11; II+=; goto prog2; // увеличим II на единицу - чтобы порядок в "100 ровно" превратилось в "порядок 101" - и ответ читался бы не как 10Е0, а как 1Е1 12(1)0(+2) 3/9 5/3 14/4 15/6 38/4 39/4 44/7R(-2) // 2: backward2: read K; 10+=; 20+=; I+=; // 1 1 1 13(1) 3/9 5/3 14/4 15/6 20/5 38/4 39/4 // 2: read K; 10+=; 20+=; I+=; // 2 2 2 14 2 5/3 14/4 15/6 38/4 39/3 // 12: forward1: read 10; 20+=; I+=; // 2 4 4 15 2 5/3 14/4 15/6 38/3 39/4 // 12: read 20; 10+=; I+=; // 6 4 8 16 2 5/3 14/3 15/6 38/4 39/4 // 12: read I; 10+=; 20+=; // 14 12 8 17 2 5/3 10/4 14/4 15/6 38/4 39/3 // 12: read 10; 20+=; I+=; clr;// 0 26 22 18 2 5/3 14/4 15/6 38/3 // 12: read 20; I+=;// 0 26 48 19 2 5/3 14/4 15/6 38/3 // 12: read 20; I+=;// 0 26 74 20 2 5/3 10/4 14/4 15/6 38/3 // 12: read 20; I+=; clr;// 0 0 100 21(1)1/4 5/3 12/3 13/3 14/4 15/6 16/3 19/3 // 2: read II; I-=; wait; goto prog1; goto forward1; 22 1 5/3 12/3 15/6 16/3 19/4 38/4 39/4 // 1: read II; 10+=; 20+=; goto prog2; goto forward2;//1 1 1 // первая строка сдвига II<<=1; из конца программы. 23 1 1/5(-2) 5/3 10/4 14/3 15/6 16/3 20/5 // 1: if (I>0) read I; clr; goto forward1; // то есть, II<I. С этого места начинаем считать корень. 24 1 5/3 12/3 14/4 15/6 // 1: forward: read II; I+=; 25 1 3/10 5/3 15/6 // 1: read K; clr; 26 1 3/4 5/3 10/4 14/3 15/6 // 1: read I; K+=; clr; 27 1 5/3 15/6 19/4 20/5 23/3 33/6L 36/4 39/3 // 1: read 11; 41+=; goto backward2; goto prog2;//в r11 - 1 28 1 5/3 11/3 12/4 15/6 23/3 39/3 // 1: forward1: read 11; II-=; 29 1 5/3 10/4 12/3 14/4 15/6 // 1: read II; I+=; clr; //I=II; II=0; 30 1 3/9 5/3 12/4 15/6 // 1: read K; II+=; //II=K 31 1 5/3 12/3 13/3 14/4 15/6 // 1: read II; I-=; 32 1 0(+2) 3/9 5/3 12/4 15/6 44/7R(-2) // 1: backward2: read K; II+=; 33 1 3/9 5/3 12/4 15/6 // 1: read K; II+=; 34 2 5/3 12/3 13/3 14/4 15/6 19/3 // 12: read II; I-=; goto prog1; 35 1 1/4 5/3 7/4 14/3 15/6 16/3 // 1: read I; if (!=0) goto forward1; 36 1 3/10 5/3 12/4 15/6 19/4 33/4 // 1: read K; II+=; clr; goto prog2; goto backward1;//мы сюда попадаем только если I==0, поэтому обнулять его не нужно. 37 1 1/5(-2) 5/3 15/6 20/5 33/6L // 1: if(I>=0) goto backward2; 38 1 5/3 12/3 14/4 15/6 // 1: forward: read II; I+=; 39 1 1/4 5/3 11/3 12/4 15/6 23/3 40/3 // 1: read 01; II-=; // в 01 - 9Е9 40 1 3/9 5/3 11/3 12/4 15/6 16/3 // 1: read K; II-=; goto forward1; 41 1 2/5(-2) 5/3 10/4 14/3 15/6 19/4 20/5 33/4 // 1: if (II>0) read I; clr; goto prog2; goto backward1; //Окей, мы нашли ответ. Обнуляем остаток исходного числа, и идём печатать ответ. 42 1 5/3 12/4 15/6 23/3 40/3 // 1: forward: read 01; II+=; // Восстанавливаем II 43 1 5/3 14/3 15/6 38/4 39/4 // 1: read I; 10+=; 20+=; // 1 1 I1 44 1 5/3 10/4 14/3 15/6 38/4 39/4 // 1: read I; 10+=; 20+=; // 1: read I; 10+=; 20+=; clr; // 2 2 I0 45 1 5/3 14/4 15/6 16/3 21/5 38/3 // 1: read 20; I+=; goto forward1; // 2 2 I2 46(1) 5/3 12/3 15/6 19/3 39/4 // 2: forward2: read II; 10+=; goto prog1; // 2 1 II1 47 1 5/3 12/4 15/6 38/4 39/3 // 1: read 10; II+=; 20+=; //2 3 II3 48 1 5/3 10/4 12/4 15/6 38/4 39/3 // 1: read 10; II+=; 20+=; clr; //0 5 II5 49 1 5/3 10/4 12/4 15/6 38/3 // 1: read 20; II+=; clr;//0 0 II10 50 1 3/9 5/3 12/4 15/6 19/4 33/6L // 1: read K; II+=; goto prog2; goto backward2;
Фотография собранной доски (без стопсов 5/3, со стопсами 17/3):
Кликните для увеличения.
Что должно распечатываться при вычислении корня из 400:
Переменные: В начале: в II вычисляемое, в I - 5, сдвинутое на несколько пар разрядов влево. В конце: I - вычисляемое (исходно, число*5) II - результат. 10,20- временные переменные K - шаг (5*100^х). 41 - степень десятки результата При первом запуске 20, I, II, надо обнулить. Константы: 01 - 9Е9 11 - 1 31 - 5 ??? 1: read K; clr; ??? 1: read 10; clr; ??? 1: read 41; clr; //Read kbd*5, II // тут будет исходное число. //goto around_answer; //answer: print II, 41; goto begin; //around_answer; 400 1: stop; read kbd; II+=; prn(); 400 1: read kbd; II+=; 10+; //*2 *1 400 1: read kbd; II+=; 10+ clr; //*3 *2 800 1: read 10; II+=; clr; //*5 2: read II; prn(); clr; 2: read 41; prn(); clr; newline; goto prog1; goto backward; 5 1: read 31; K+=; //в 31 - 5 1 1: read 11; II+=; goto prog2; // увеличим II на единицу - чтобы порядок в "100 ровно" превратилось в "порядок 101" - и ответ читался бы не как 10Е0, а как 1Е1 //I=K<<2 5 2: backward2: read K; 10+=; 20+=; I+=; // 1 1 1 5 2: read K; 10+=; 20+=; I+=; // 2 2 2 10 12: forward1: read 10; 20+=; I+=; // 2 4 4 20 12: read 20; 10+=; I+=; // 6 4 8 40 12: read I; 10+=; 20+=; // 14 12 8 70 12: read 10; 20+=; I+=; clr;// 0 26 22 130 12: read 20; I+=;// 0 26 48 130 12: read 20; I+=;// 0 26 74 130 12: read 20; I+=; clr;// 0 0 100 //if(II>I) // { // K=r30; // r41++; // goto next; // } 2001 2: read II; I-=; wait; goto prog1; goto forward1;// стопс задержки ставим здесь, а не на следующем шаге! Чтобы он анализировал ЭТО значение I 1: read II; 10+=; 20+=; goto prog2; goto forward2;//1 1 1 // первая строка сдвига II<<=1; из конца программы. 2001 1: forward1: read II; I+=; goto forward1; 1: if (I>=0) read I; clr; goto forward1;// то есть, II<I. С этого места начинаем считать корень. 5 1: read K; clr; 500 1: read I; K+=; clr; 1 1: read 11; 41+=; goto backward2;//в r11 - 1 //в этом месте в K у нас 5, сдвинутое на нужную степень, а в r41 - степень десятки ответа (она не понадобится до самой печати) // II--; //мы увеличивали число на единицу, надо это исправить. // I=II; //переносим изучаемое число в I // II=K; //записываем исходную (сдвинутую) пятёрку //I-=II; //вычитаем первый член. Оно получается - иначе бы мы сдвинулись ещё на один разряд. //next_step: // II+=K; // II+=K; //next_digit: // I-=II; 1: forward1: read 11; II-=; 1: read II; I+=; clr; //I=II; II=0; 1: read K; II+=; //II=K 1: read II; I-=; 1: backward2: read K; II+=; 1: read K; II+=; 12: read II; I-=; goto prog1; // if (I==0) //мы нашли точный ответ // { // II+=K; // goto answer; // } 1: read I; if (!=0) goto forward1; 1: read K; II+=; clr; goto prog2; goto backward1; //мы сюда попадаем только если I==0, поэтому обнулять его не нужно. //if (I>0) goto next_step; 1: if(I>=0) goto backward2; //I+=II;//прибавляем последнее число, которое вычли. //II-=K;//убираем пятёрку в конце 1: read II; I+=; // if (II>9E9) goto answer; 1: read 01; II-=; // в 01 - 9Е9 1: read K; II-=; goto forward1; 1: if (II>0) read I; clr; goto prog2; goto backward1; //Окей, мы нашли ответ. Обнуляем остаток исходного числа, и идём печатать ответ. 1: read 01; II+=; // Восстанавливаем I // I<<=2; 1: read I; 10+=; 20+=; // 1 1 I1 1: read I; 10+=; 20+=; clr; // 2 2 I0 1: read 20; I+=; goto forward1; // 2 2 I2 //II<<=1; //1: read II; 10+=; 20+=; //1 1 1 это выполняется в предыдущем блоке сдвига 2: forward2: read II; 10+=; goto prog1; // 2 1 II1 1: read 10; II+=; 20+=; //2 3 II3 1: read 10; II+=; 20+=; clr; //0 5 II5 1: read 20; II+=; clr;//0 0 II10 //II+=K;//добавляем пятёрку в конце - но уже в следующий разряд. //goto next_digit; // одну пятёрку мы добавили, ещё две пока не нужны - поэтому next _digit находится после next_step; 1: read K; II+=; goto backward2; goto prog2;
Что должно распечатываться при вычислении корня из 2:
Переменные: В начале: в II вычисляемое, в I - 5, сдвинутое на несколько пар разрядов влево. В конце: I - вычисляемое (исходно, число*5) II - результат. 10,20- временные переменные K - шаг (5*100^х). 41 - степень десятки результата При первом запуске 20, I, II, надо обнулить. Константы: 01 - 9Е9 11 - 1 31 - 5 ??? 1: read K; clr; ??? 1: read 10; clr; ??? 1: read 41; clr; //Read kbd*5, II // тут будет исходное число. //goto around_answer; //answer: print II, 41; goto begin; //around_answer; 2 1: stop; read kbd; II+=; prn(); 2 1: read kbd; II+=; 10+; //*2 *1 2 1: read kbd; II+=; 10+ clr; //*3 *2 4 1: read 10; II+=; clr; //*5 2: read II; prn(); clr; 2: read 41; prn(); clr; newline; goto prog1; goto backward; 5 1: read 31; K+=; //в 31 - 5 1 1: read 11; II+=; goto prog2; // увеличим II на единицу - чтобы порядок в "100 ровно" превратилось в "порядок 101" - и ответ читался бы не как 10Е0, а как 1Е1 //I=K<<2 5 2: backward2: read K; 10+=; 20+=; I+=; // 1 1 1 5 2: read K; 10+=; 20+=; I+=; // 2 2 2 10 40 12: forward1: read 10; 20+=; I+=; // 2 4 4 20 80 12: read 20; 10+=; I+=; // 6 4 8 40 160 12: read I; 10+=; 20+=; // 14 12 8 70 280 12: read 10; 20+=; I+=; clr;// 0 26 22 130 520 12: read 20; I+=;// 0 26 48 130 520 12: read 20; I+=;// 0 26 74 130 520 12: read 20; I+=; clr;// 0 0 100 //if(II>I) // { // K=r30; // r41++; // goto next; // } 11 2: read II; I-=; wait; goto prog1; goto forward1;// стопс задержки ставим здесь, а не на следующем шаге! Чтобы он анализировал ЭТО значение I 10 140 1: read II; 10+=; 20+=; goto prog2; goto forward2;//1 1 1 // первая строка сдвига II<<=1; из конца программы. 11A 1: forward1: read II; I+=; goto forward1; 500 A 1: if (I>=0) read I; clr; goto forward1;// то есть, II<I. С этого места начинаем считать корень. 1: read K; clr; 1: read I; K+=; clr; 1: read 11; 41+=; goto backward2;//в r11 - 1 //в этом месте в K у нас 5, сдвинутое на нужную степень, а в r41 - степень десятки ответа (она не понадобится до самой печати) // II--; //мы увеличивали число на единицу, надо это исправить. // I=II; //переносим изучаемое число в I // II=K; //записываем исходную (сдвинутую) пятёрку //I-=II; //вычитаем первый член. Оно получается - иначе бы мы сдвинулись ещё на один разряд. //next_step: // II+=K; // II+=K; //next_digit: // I-=II; 1 1: forward1: read 11; II-=; 10 1: read II; I+=; clr; //I=II; II=0; 5 1: read K; II+=; //II=K 5 1: read II; I-=; 5 5 5 5 5 1: backward2: read K; II+=; 5 5 5 5 5 1: read K; II+=; 15 105 115 125 135 145 12: read II; I-=; goto prog1; // if (I==0) //мы нашли точный ответ // { // II+=K; // goto answer; // } -10 395 280 155 20 -125 1: read I; if (!=0) goto forward1; 1: read K; II+=; clr; goto prog2; goto backward1; //мы сюда попадаем только если I==0, поэтому обнулять его не нужно. //if (I>0) goto next_step; 1: if(I>=0) goto backward2; //I+=II;//прибавляем последнее число, которое вычли. //II-=K;//убираем пятёрку в конце 15 145 1: read II; I+=; // if (II>9E9) goto answer; -00 -00 1: read 01; II-=; // в 01 - 9Е9 5 5 1: read K; II-=; goto forward1; 1: if (II>0) read I; clr; goto prog2; goto backward1; //Окей, мы нашли ответ. Обнуляем остаток исходного числа, и идём печатать ответ. 00 00 1: read 01; II+=; // Восстанавливаем I // I<<=2; 5 20 1: read I; 10+=; 20+=; // 1 1 I1 5 20 1: read I; 10+=; 20+=; clr; // 2 2 I0 10 40 1: read 20; I+=; goto forward1; // 2 2 I2 //II<<=1; //1: read II; 10+=; 20+=; //1 1 1 это выполняется в предыдущем блоке сдвига 10 140 2: forward2: read II; 10+=; goto prog1; // 2 1 II1 20 280 1: read 10; II+=; 20+=; //2 3 II3 20 280 1: read 10; II+=; 20+=; clr; //0 5 II5 50 700 1: read 20; II+=; clr;//0 0 II10 //II+=K;//добавляем пятёрку в конце - но уже в следующий разряд. //goto next_digit; // одну пятёрку мы добавили, ещё две пока не нужны - поэтому next _digit находится после next_step; 5 5 1: read K; II+=; goto backward2; goto prog2;