Программирование

Давайте здесь устроим поле для обсуждения неясных моментов программирования на Паскале

задача 1

  1. program kol_cifr;
  2. var N,k: word;
  3.     i: byte;
  4. begin
  5.   write ('vvedite chislo ');
  6.   readln (N);
  7.   k:=0;
  8.   for i:=1 to 5 do begin
  9.     N:=N div 10;
  10.     if N>0 then k:=k+1;
  11.     if N=0 then begin
  12.       k:=k+1;
  13.       break
  14.     end
  15.   end;
  16.   writeln ('kol_vo = ', k)
  17. end.

Не знаю, закрыта ли эта задача, просто поздно увидела задания, а искать в комментариях долго.
Цикл до 5 потому что в условии сказано, что N типа Word, а в этом типе больше чем три цифры быть не может.

Виталия, ты ошибаешься...

Виталия, ты ошибаешься, тип word имеет диапазон от нуля до 65535, поэтому твоя программа работает не верно при 4-ёх и 5-изначных числах...

спасибо, я уже заметила что

спасибо, я уже заметила что перепутала и исправила, только почему-то в одном месте "три" забыла всё-таки заменить.

Виталия, можно было решить проще

Виталия, можно было решить проще, посмотри моё решение этой задачи на предыдущей странице...

Виталия

В точности как у меня, только можно использовать N в цикле for, как конечное значение и когда N обнулится мы выйдем из цикла, тем самым избавимся от одного if внутри цикла for, просто после выхода из цикла добавить операцию k := k + 1. Но есть более изящное решение, если интересно, поищи в комментариях решение Романа Мгоева.

Богдан

Можно решить ещё проще))

задача 5

  1. program nechet;
  2. var a: word;
  3.     n,i,p: byte;
  4. begin
  5.   readln (n); //вводим количество цифр
  6.   read (p); //вводим первую цифру
  7.   a:=p;
  8.   for i:=2 to n do begin
  9.     read (p);
  10.     a:=a*10+p
  11.   end;
  12.   writeln (a)
  13. end.

Прошу прощение если вдруг здесь есть опечатка - с интернетом проблемы, стараюсь побыстрее печатать.

Задача 1

По поводу задачи 1. Я немного не понял, если введено число 0, то оно однозначное или вообще не имеет десятичной значности? Если же оно не имеет десятичной значности, то предлагаю слегка измененное решение Богдана:

  1. program zd1;
  2.   var N:word;
  3.         S,i:Byte;
  4. begin
  5.   readln(N);
  6.   S:=0;
  7.   For 1 to 5 do begin
  8.       If N=0 then break;
  9.       N:=N div 10;
  10.       Inc(S)
  11.   end;
  12.   writeln ('Число ', N,' - ', S, ' значное')
  13. end.

Ну и в решении Богдана можно заменить S:=S+1 на Inc(s)

Андрей

Андрей, как решить ещё проще?

Андрей

если использовать в цикле i до N, то как бы не изменялось N, цикл будет повторяться столько раз, каким было значение N изначально, так как в цикле for N копируется при входе и далее используется не значение N, а его копия, которую никак не поменять и досрочно можно выйти только с помощью break

Вита, в задаче 5 программа

Вита, в задаче 5 программа выведет не все цифры

Вика

Я ввела эту задачу в паскаль, всё прекрасно работает. Что именно тебе не нравится в ней? Укажи на ошибку точно

Богдан

  1. program zadacha_1;
  2. var i :integer;
  3.         n :word;
  4. begin
  5. readln(n);
  6.   for i := 1 to 5 do begin
  7.      n := n div 10;
  8.      if n = 0 then break
  9.  end;
  10.  writeln(i);
  11.  readln
  12. end.

Решение не моё, автор Роман Мгоев.

в принципе решение такое же

в принципе решение такое же как и у Багдана. Отличие только в том, что он взял лишнюю переменную, а Рома заметил, что значение i при выходе из цикла как раз будет равно кол-ву цифр. А я еще и лишнее if добавила

Виталия

Значение N меняется внутри цикла for, ты присваиваешь N новое значение операцией N := N div 10; , как говорится N стремится к нулю, при чём довольно стремительно)) Посмотри внимательно на код.

Виталия

В этом и изящность)) Минус одна операция и минус одна переменная.

Вита, когда я её проверяла у

Вита, когда я её проверяла у себя, то при вводе, например, 3-х цифр программа выводит 2 последние

я не говорила, что значение N

я не говорила, что значение N не меняется, правильно оно меняется, но цикл будет идти до первоначального значения N (если в цикле указано i:=.. to N do ..), так как при входе в цикл значение N копируется и используется копия

Вика

у меня всё отлично работает, как я и говорила. Возможно ты ошиблась с вводом. Первая цифра - это количество цифр. Если ты ввела "3", то дальше ты должна ввести еще три цифры. Например, это будет выглядеть так (с выводом результата):
3
4
6
2
462
Мы вводим n (кол-во)
дальше вводим первую цифру и присваиваем значение а, после этого, если кол-во цифр больше 1, то мы входим в цикл for, если до двух, то умножаем а на 10 и прибавляем уже введенную следующую цифру и тд

Виталия

Меняется. Анализируй это:

  1. program zadacha1;
  2. var  N, i, S :Word;
  3. begin
  4. S := 0;
  5. Writeln('Vvedite chislo');
  6. Readln(N);
  7.   for i := 1 to N do begin
  8.        N := N div 10;
  9.        if N > 0 then S := S + 1;
  10.    end;
  11. S := S + 1;
  12. Writeln(S);
  13. Readln
  14. end.

тестовая задача с case-оператором

Подскажите пожалуйста, что за нерешенная задача с case - оператором, нигде не могу ее найти

Андрей

У тебя ошибка - i должна быть integer, если i типа word, то программа не работает.

Андрей

Вы наверно лекции плохо учили. Программа работает верно не спорю, ибо N у нас становится меньше нуля, а в if указано, что s:=s+1 только если N>0, но цикл проходится до конца, до самого первоначального N. Вот запустите эту программу и вы увидите, что как бы мы не меняли N цикл будет повторяться количество раз равное первоначальному значению N

  1. program zadacha1;
  2. var  N,S :Word;
  3.      i: byte;
  4. begin
  5. S := 0;
  6. Writeln('Vvedite chislo');
  7. Readln(N);
  8.   for i := 1 to N do begin
  9.        N := N div 10;
  10.       write (i, ' ')
  11.    end;
  12. readln
  13. end.

Богдан

Необязательно. Не знаю, у меня всё работает.

Андрей

Кроме того при i типа integer, программа верно работает...

Андрей видимо запускает в

Андрей видимо запускает в Delphi, а вы в Pascal. Это не страшно

Артём

посмотрите на странице 5 или 6

Виталия

Твой пример совершенно другой случай, write() расположен внутри цикла и выводит значение i, которое выводит количество итераций цикла, а нам нужно вывести количество делений N на десять, которое хранится в переменной S. Всё равно S не изменится, когда N станет меньше нуля. Но да, цикл таки будет бежать до конечного N, моё упущение. Получается бесполезная нагрузка процессора бесполезной работой.

ну, наконец-то ты меня понял!

ну, наконец-то ты меня понял! Я же не говорила что "искусственный" счетчик s будет бежать, а говорила про количество повторений цикла)
а эту программу я написала для того чтобы показать на наглядном примере "это упущение"

Виталия

Да, я свято верил в то, что N изменяется внутри цикла, но ошибался. Я написал самую бессмысленную программу, которая заняла бы первое в конкурсе: "Нагрузи процессор бесполезной работой")) Но, на ошибках учатся, спасибо за ценное указание на ошибку.

всегда пожалуйста)

всегда пожалуйста)

В связи с этим, прошу не

В связи с этим, прошу не защитыват моё решение задачи номер 1, потому что она решена совершенно неприемлемым образом. Думаю ясно, почему это решение неприемлемо.

Валерий Шахамболетович,может

Валерий Шахамболетович,может я немножко забегаю вперед, но объясните пожалуйста, почему в программе

  1. program vv1;
  2. type
  3.    days=(mo,tu,we,th,fr,sa,su);
  4.    weekend=sa..su;
  5. var
  6.   i:integer;
  7.   w:weekend;
  8. begin
  9.   w:=sa;
  10.   i:=ord(w);
  11.   writeln(i)
  12. end.

функция ord(w) вернет значение 5, а pred(w) приведет к ошибке?
То есть про ord(w) понятно, а вот почему pred....

Виктория

pred(X) возвращает параметр того же типа, что и X, являющийся предшественником X. В данном случае ты пытаешься присвоить типу Integer переменную типа weekend. Поэтому с ord(X) отработает нормально, а с pred(X) приведёт к ошибке. А что означает строчка weekend = sa..su?

спасибо что пояснил,

спасибо что пояснил, подзабыла об этом факте. Эта строчка означает неделю и её дни

Вика, что это за программа?

Вика, что это за программа? она просто выводит 5....она должа выводить следующий день за субботой,как я поняла..так? или я не правильно понимаю(

АНАЛИЗ1.

1.В ТП дано натуральное число N типа Word. Используя оператор FOR, определить его десятичную значность, т.е. длину его десятичной записи (Например, 3035 - четырёхзначное).
Первое, приемлемого качества решение этой задачи за Мгоевым Р.:

  1. program  Znachnost;
  2.     var n:  word;
  3.            i:Byte;
  4. Begin
  5.     readln(n);
  6.     for i:=1 to 5 do  begin
  7.              n:=n div 10;
  8.              if n=0 then break
  9.     end;
  10.     writeln(i);
  11. end.

Было представлено много и других вариантов решения этой задачи (Ведлер А.- самое первое решение, Гостев Б., Пальчикова В. и др.). Но они или хуже, или неправильны или просто повторяют это решение. Самый неприятный (как я говорил на лекции, крайне не рекомендуемый!) приём в некоторых из этих решений попытка принудительного изменения значений переменной N в теле цикла For:= … To N Do… .

Исходя из соображений стиля программирования (исключить оператор break), я бы предпочёл следующий, например, вариант решения этой задачи :

  1. program  Znachnost;
  2.     var n:  word;
  3.            I,s: Byte;
  4. Begin
  5.     readln(n);
  6.     s:=1;
  7.     for i:=1 to 5 do  begin
  8.            n:=n div 10;
  9.            If n>0 then Begin
  10.                 Inc(s)
  11.            End;
  12.     end;
  13.     writeln(s);
  14. end.

Или, если стремиться к предельной простоте, возможно, даже такой:

  1. program  Znachnost;
  2.     var n:  word;
  3. Begin
  4.     Readln(n);
  5.     Writeln( trunc(exp(n)/exp(10) ) +1)
  6. End.

Попробуйте это! Eсли работает, постарайтесь обосновать (а если не работает -подправить).

2.Используя минимально возможное число операторов, напечатать все нечётные натуральные числа, не превосходящие 100.

Первыми задачу одновременно решили Ширшов Н. и Белецкая В. в варианте с 3-мя операторами (for, if, writeln):

  1. program Odds;
  2.     var i: Byte;
  3. begin
  4.      for i:=1 to 100 do begin
  5.           if odd(i) then begin
  6.                  writeln(i,', ');
  7.           end;
  8.      end;
  9. end.

Суть алгоритма – генерация(перечисление) всех чисел от 1 до 100 (цикл For) с последующим отбором нечётных (If odd(i) …) и их выводом (Writeln).
Здесь следует обратить внимание на функцию odd(i), которая всегда предпочтительней более медленно вычисляемому булевскому выражению (i mod 2) =1 .

Оптимальное её решение (с 2-мя операторами) позднее предложил Новокрещенов А.:

  1. program zd2;
  2.     var i:Byte;
  3. begin
  4.     for i:=1 to 50 do begin
  5.         writeln(2*i -1)
  6.     end
  7. end.

Cмысл улучшения состоит в более сложном перечисляющем выражении (2*i -1, вместо i), которое сразу же выдаёт требуемые значения, за счёт чего отпадает необходимость в последующем отборе (фильтрации) с помощью If. В результате – более короткий и более быстрый (50 повторений цикла вместо 100) код.

Не вполне удовлетворительное , но при этом, неожиданное по выбранному методу и так же короткое решение предложил Гостев Богдан:

  1. program r;
  2. var i: integer;
  3. begin
  4.   for i:=1 to 99 do write ( i*(i mod 2), ',')
  5. end.

Попробуйте в этом решении разобраться сами.

3.Дано 2 натуральных числа M и N. Вывести в порядке убывания все их общие делители.

Автором первого правильного решения этой задачи является Зуева В.:

  1. Program deliteli;
  2.    var i, m, n:Word;
  3. begin
  4.    readln(n,m);
  5.    if n>m then begin
  6.       for i:=n downto 1 do begin
  7.          if ((n mod i)=0) and ((m mod i)=0) then begin
  8.              writeln(i);
  9.          end;
  10.       end
  11.    end
  12.    else begin
  13.          for i:=m downto 1 do begin
  14.            if ((n mod i)=0) and ((m mod i)=0) then begin
  15.              writeln(i)
  16.            end
  17.          end
  18.    end
  19. end.

Идея проста – перечислять в цикле FOR все натуральные числа, не превосходящие меньшего из заданных чисел M и N, тут же отбирая для вывода те из них, на которые одновременно делятся M и N.

Но если пренебречь возможностью некоторого замедления программы и начать не с меньшего, а с любого из заданных чисел M и N, то код можно укоротить:

  1.  
  2. Program DeliteliShort;
  3.       var n,m,d: Word;
  4. begin
  5.       Readln(m,n);
  6.       for d:=n downto 1 do  begin
  7.              if (n mod d=0) and (m mod d=0) then begin
  8.                     Write(d, '  ')
  9.             End
  10.       end;
  11.  end.

Такое решение нашла Джанчатова З.(правда мне пришлось потрудиться над приданием презентабельного вида этому решению).

Итак, 1-е решение - более быстрое, 2-е решение - более короткое. Никто не подумал о том, как соединить достоинства этих двух решений. Вот так:

  1.  
  2. Program DeliteliFastShort;
  3.       var n,m, k, d: Word;
  4. begin
  5.       Readln(m,n);
  6.       k:=m;
  7.       If n<k then k:=n; //выбрали в k наименьшее из m,n.
  8.       for d:=k downto 1 do  begin
  9.             if (n mod d=0) and (m mod d=0) then begin
  10.                     Write(d, '  ')
  11.             End
  12.       end;
  13.  end.

ПРОДОЛЖЕНИЕ АНАЛИЗА СЛЕДУЕТ, НО НЕ СЕГОДНЯ!

Ксюша, это программа по

Ксюша, это программа по прошлой лекции о перечислимых типах. Здесь я использовала тип-диапазон, который является подмножеством основного типа, который обозначается как type

то есть тип, который создаем

то есть тип, который создаем мы сами.Программа выводит число 5, потому что задана функция ORD в 10-й строке, которая преобразует данные в целое число

Валерий Шахамболетович, может

Валерий Шахамболетович, может я что-то упустила, но поясните, почему в 1-й задаче i от 1 до 5?

а...да да да

а...да да да

Вика

потому что тип Word от 0(1 знак) до 65535(5 знаков)

понятно,Никит:-)

понятно,Никит:-)

фу, ели нашол вашу

фу, ели нашол вашу ошибку , ЗАДАЧА №1

  1. program Znachnost;
  2. var n:word;
  3. begin readln(n);
  4. writeln(trunc(ln(n)/ln(10))+1)
  5. end.

Молодец, Роман! И здесь Вы

Молодец, Роман! И здесь Вы первый!
Однако, мне не нравится оформление Вашего кода. Исправляйтесь.

Красивое оформление

извините что так поздно,пролемы с интернетом

  1. program Znachnost;
  2.      var n:word;
  3. begin    
  4.      write('Введите число: ');
  5.      readln(n);
  6.      writeln('Число знаков в числе: ', trunc(ln(n) / ln(10)) + 1)
  7. end.

Всем добрый ночи

Всем добрый ночи

АНАЛИЗ2

4.Дана входная последовательность из N целых чисел. Найти значение наибольшего члена этой последовательности.

С этой задачей (наименее популярной, из-за кажущейся её сложности) всё достаточно просто, если знать принцип поиска (который я рассматривал, правда, в рамках своих лабораторных занятий). Действуем так.

Считываем первый элемент в некоторую переменную (Max, например).
Далее, последовательно, в цикле читаем все остальные N-1 элементов в некоторую переменную A, сравнивая каждый из них с Max и копируя его в Max, если он оказался больше того элемента, который там находился. По завершению процесса, в Max осядет наибольшее значение.

Программную реализацию этого алгоритма с необходимыми пояснениями привёл Решеткин Саша:

  1. program Task4;
  2.      var n, i, a, max : integer;
  3. begin
  4.      write ('Введите n: ');
  5.      readln (n);      // Ввод длины последовательности
  6.      readln (max);  // Ввод первого члена последовательности
  7.      for I := 2 to n do begin // Ввод и обработка остальных членов
  8.            readln (a);
  9.            if a > max then max:= a  //Если нов. эл. > того, что в Max, то его в Max    
  10.      end;
  11.      writeln ('Максимум: ', max);
  12. end.

Принципиально иных подходов эффективного решения этой задачи я не вижу.

5.Ввести N десятичных цифр (знаков) и образовать из них соответствующее значение A типа Word (Например, введя 4 цифры: ‘3’,’0’,’5’,’2’, мы должны сформировать значение A=3052).

Почти все при решении этой задачи пошли по ложному пути, не сумев до конца понять условия, в котором говорится о цифрах (знаках, символах, т.е. значениях типа Char, заключаемых в апострофы –о чём недвусмысленно кричал пример! ) и решали другую задачу, которую в силу её поучительности, мы так же рассмотрим:

5B. Ввести N однозначных десятичных значений (неотрицательных, не превышающих 9 целых чисел) и образовать из них соответствующее значение A типа Word (Например, введя 4 числа: 3,0,5,2, мы должны сформировать значение A=3052).

В такой новой постановке первым и практически оптимально эту задачу решил Давтян Сурен (в его решении есть досадные, правда, не влияющие на окончательный результат недочёты, которые я подправил):

  1. program Number_5;
  2. var
  3.    n,a,i,s: Word;
  4. Begin
  5.    readln (n);
  6.    s:=0;
  7.    for i:=1 to n do begin
  8.        readln(a);
  9.        s:=s*10+a;
  10.    end;
  11.    writeln(s)
  12. end.

Все остальные решения либо по существу, повторы этого, либо хуже, либо содержат ошибки.

Но давайте внимательней посмотрим, что в этой задаче дано и что нужно вычислить.
Дано n - число цифр, и даны сами цифры A1,A2, … An.
Сформировать (вычислить) нам нужно число:
A=A1*10^(n-1) + A2*10^(n-2) + …+An-1*10^1 + An

Вам эта запись ничего не напоминает?
А если переписать её вот так: A=A1*X^(n-1) + A2*X^(n-2) + …+An-1*X^1 + An,
где X=10

Узнали? Да, это полином (многочлен) cтепени (n-1) и его можно вычислять двумя способами:

  1. Непосредственно, т.е. «в лоб», считая степени 10-ти, умножая их на коэффициенты и всё складывая – долгое и сложное решение;
  2. По схеме Горнера – простое и наиболее эффективное решение, при котором ничего ни в какую степень возводить не надо.

Для данного в условии примера (даны 4 значения: 3, 0, 5, 2), этим двум способам соответствуют записи:
1) A= 3*10^3 + 0*10^2 +5*10^1 +2; - непосредственное вычисление.
2) A= ( (3*10 + 0)*10 + 5)*10 +2; - схема Горнера.

Вторая запись как раз и приведёт к выше указанному решению Сурена по циклически повторяющейся схеме : «умножай на 10 - читай- прибавляй» (хотя, я думаю, автор этого решения нашёл его интуитивно, вряд ли догадываясь, что действует по схеме Горнера).

Попытка же прямой реализации первой из двух выше указанных записей потребует немедленного возведения числа 10 в степень (n-1) и дальнейшего уменьшения этой степени по мере продвижения по многочлену вправо.
Соответственно, мы получим, в конечном счёте, либо ошибку, пытаясь, например, записать невозможное в ТП выражение типа 10^(N-1), либо получим верную, но при этом неоптимальную программу. Обе эти ситуации представлены в Ваших решениях и в поучительных целях, показаны ниже:

  1. program five; // НЕОПТИМАЛЬНЫЙ КОД С ОШИБКОЙ ВОЗВЕДЕНИЯ В СТЕПЕНЬ
  2.         var  N, i, K,  A:  Word;
  3. begin
  4.       A:=0;          //обнуляем  сумму
  5.       read(N);    //считываем количество знаков нашего числа
  6.       for i:=N-1  downto 0 do begin //запускаем счетчик на убывание
  7.            read(K);    //считываем значение очередной цифры
  8.            A:=A+K*(10^i)   //  ОШИБКА!!!        10^i  в ТП невозможно!
  9.       end;
  10.       write(A)    //выводим  результат
  11. end.

  1. program zadacha5;  // НЕОПТИМАЛЬНОЕ, НО  ВЕРНОЕ  РЕШЕНИЕ
  2.      var i, n: Word;
  3.            a, b, c: Word;
  4. begin
  5.     c := 0;
  6.     b := 1;
  7.     Readln(n);
  8.  
  9.     for i := 2  to n do Begin
  10.          b := b * 10;
  11.     End;   // Нашли  b=10^(n-1)
  12.  
  13.     for i := 1 to n do begin
  14.          Readln(a);  // читаем значение очередной цифры
  15.          c := c + (a * b);  //добавляем  соответствующее слагаемое
  16.          b := b div 10;  // уменьшаем на 1 степень десяти
  17.     end;
  18.     Writeln(c);
  19. end.

А теперь вернёмся к нашей задаче в исходной постановке, т.е., когда на вход подаются не числовые значения, а значения типа Char. В нашем примере, это : ‘3’,’0’,’5’,’2’, а не уже рассмотренные нами: 3, 0, 5, 2 .

Решение – на поверхности. Надо научиться по каждой цифре вычислять её числовое значение (математическое, а не то, которое кодирует эту цифру в таблице ASCII !).

Нетрудно сообразить, что искомое значение каждой цифры от ‘0’ до ’9’ совпадает с её отдалённостью (в дискретах) от цифры ‘0’. Например, ‘3’ – стоит в ASCII таблице на третьем месте после нуля. Величину i этого смещения вправо относительно ‘0’ для любой цифры С (т.е. числовое значение цифры С) легко подсчитать по очевидной формуле:
i=ord(С)- ord(‘0’).
Это и есть формула перехода от десятичных цифр (имеющих тип Char) к их числовым значениям. А что делать с числовыми значениями, мы уже знаем.

Первым всё это осознал Мгоев Роман, решение исходной задачи которого (немного подредактировав ), я воспроизвожу ниже:

  1.  
  2. program fv;
  3. var c: char;
  4.      a,n,i, s: word;
  5.  
  6. begin
  7.      readln(n);
  8.      s:=0;
  9.      for i := 1 to n do begin // накопление значений цифр по сх. Горнера
  10.             readln(c);  // очередная цифра
  11.             a:= ord(c) - ord('0'); // её числовое значение
  12.             s := s * 10 + a;
  13.       end;
  14.       writeln(s);
  15. end.

БАЛЛЫ.

Результаты бонусной сессии (26 -28 октября 2012 г.)
(учитывались результативность, активность, пытливость, отзывчивость)

1. Мгоев Роман -3
2. Ведлер Андрей 2
3. Давтян Сурен - 1.
4. Новокрещенов Артём - 2
5. Белецкая Виктория -1
6. Зуева Виктория – 2
7. Пальчикова Виталия – 1
8. Решеткин Александр – 2
9. Ширшов Никита – 1
10. Хорунжий Дмитрий -1
11. Панова Ксения. - 1
12. Джанчатова Зарина- 2.
13. Гостев Богдан - 1

Валерий Шахамболетович

А что на счёт задачи с case оператором?