Говоря о циклах, можно и зациклиться - так много есть красивых примеров, иллюстрирующих их применение в программировании, поэтому мы напишем всего 2 программы, но если вы будете наблюдательны, то найдёте циклы ещё на многих страницах этого сайта.
Римские числа
Все дороги ведут в Рим. Из ответа на уроке географии
Древние римляне создали огромную, могущественную империю, которую назвали в свою честь, но что касается чисел, то тут они изрядно начудили и придумали столь вычурную систему обозначения чисел буквами, что даже простейшие арифметические вычисления давались им с большим трудом. Существенно облегчили школярам тяготы учёбы пришедшие на смену римским арабские цифры, которые почему-то придумали индийцы.
Римская империя давно пала под натиском варваров, а их вычурные цифры сохранились до сих пор в первозданном виде. К счастью, нам не нужно пользоваться ими на уроках математики, но как украшательство мы можем найти их в книгах для обозначения глав, для подсчёта столетий, царей, съездов и других исторических событий.
Поскольку компьютер не понимает не только римских цифр, но даже и арабских, то напишем простую программу, которая поможет нам разобраться в премудростях римской нумерации.
Установим на форме заветную кнопку sbtGoс призывной надписью Найти, да и нажмём её:
procedure TfrmMain.sbtGoClick(Sender: TObject);
var n: integer;
begin
n:= speNum.Value; rome(n); end;
Но мы не в сказке, и, конечно, ничего не произойдёт, поэтому введём новый тип-запись TRome, который будет хранить и само число, и его «римское» представление. Если бы не краткость нашей жизни, мы могли бы просто записать все числа от 1 до 3999 в арабском и римском виде, но поскольку это не так, то схитрим и в массиве numсохраним только 13 самых необходимых сочетаний чисел, а остальные придётся вычислять.
type
TRome=record an: 1..1000; rn: string; end;
var
frmMain: TfrmMain;
num: array[1..13] of TRome;
При запуске программы заполняем массив num:
procedure TfrmMain.FormCreate(Sender: TObject);
begin
num[1].an:=1000; num[1].rn:='M';
num[2].an:=900; num[2].rn:='CM';
num[3].an:=500; num[3].rn:='D';
num[4].an:=400; num[4].rn:='CD';
num[5].an:=100; num[5].rn:='C';
num[6].an:=90; num[6].rn:='XC';
num[7].an:=50; num[7].rn:='L';
num[8].an:=40;
num[8].rn:='XL';
num[9].an:=10;
num[9].rn:='X';
num[10].an:=9;
num[10].rn:='IX';
num[11].an:=5;
num[11].rn:='V';
num[12].an:=4;
num[12].rn:='IV';
num[13].an:=1;
num[13].rn:='I';
end;
Легко понять, почему нам понадобились именно эти числа - остальные довольно просто собрать из них, как ожерелье из бусин.
И вот как это делается:
//НАЙТИ РИМСКОЕ ЧИСЛО procedure rome(number: integer);
var n: integer;
s: string; begin
if (number < 1) or (number> 3999) then exit; //frmMain.lstProtokol.Clear;
n:=0; s: = ’’;
while number>0 do begin
inc(n);
while num[n].an <= number do begin
s:= s + num[n].rn; number:= number - num[n].an; end; end;
frmMain.lstProtokol.Items.add(s);
end;
Как мы и договаривались, разумно ограничим себя числом 3999 сверху и 1 снизу (а меньше у римлян и не было), поэтому «сверхъестественные» числа просто игнорируем.
Для подсчёта числа и формирования строки нам потребуются: переменная nцелого типа и строка s. Вся премудрость конвертирования чисел таится в двух циклах while. Мы последовательно сравниваем заданное число numberс числами, которые хранятся в массиве num, начиная с тысяч. Внутренний цикл как раз и нужен для того, чтобы определять, сколько в numberимеется тысяч, сотен, десятков и единиц (все остальные римские числа - 900, 500, 400, 90, 50, 9, 5, 4 - могут быть только в единственном числе).
Если текущее значение numberне меньше этих чисел, то из него число вычитаем, а в строку добавляем буквы, соответствующие этому числу в римской записи. Как только от числа ничего не осталось (это контролирует внешний цикл while), преобразование числа заканчивается, и мы смело можем печатать на экране перевод римского числа на современный европейский математический язык.