Помогите с заданиями

Книга адресована школьникам средних и старших классов, желающим испытать себя в «олимпийских схватках». Может быть полезна студентам-первокурсникам и преподавателям информатики.

Модераторы: Oleg_D, Модераторы

Помогите с заданиями

Сообщение A.N.Onim » 24.12.2012 00:31:23

Добрый день!
Пытаюсь программировать на Паскале.
Учу по "Песни по Паскале".
Все вопросы буду писать в этой теме.
Прошу не злиться на мою смекалку :D

Задача. Создайте процедуру, печатающую все числа, кроме единицы, на которые
без остатка делится число N, где N – параметр процедуры. Напишите программу
для проверки этой процедуры.


Вот что вышло:
Код: Выделить всё
program p_20_2;
var n: integer;

procedure BezOst (n: integer);
var i, s: integer;
begin
for i:= 1 to n do
                 s:= n mod i;
                 if s=0 then
                            if i<>1 then
                                        write(i);
end;

begin
writeln('Введите число: ');
readln(n);
BezOst(n);
readln;
end.


Какое число ввожу, такое и выводит. Где ошибка?
A.N.Onim
новенький
 
Сообщения: 17
Зарегистрирован: 24.12.2012 00:18:52

Re: Помогите с заданиями

Сообщение Putnick » 24.12.2012 09:18:34

У вас цикл получается такой:
Код: Выделить всё
for i:= 1 to n do begin
   s:= n mod i;
end;

а должен быть
Код: Выделить всё
for i:= 1 to n do begin
   s:= n mod i;
   if s=0 then
     if i<>1 then write(i);
end;

И, кстати, цикл можно гнать не до n, а до квадратного корня из n.
Putnick
новенький
 
Сообщения: 62
Зарегистрирован: 18.03.2009 13:02:56

Re: Помогите с заданиями

Сообщение Oleg_D » 24.12.2012 10:04:33

Или так, без лишних переменных:
Код: Выделить всё
for i:= 2 to n div 2 do
   if (n mod i)=0 then  writeln(i);
Последний раз редактировалось Oleg_D 24.12.2012 10:05:17, всего редактировалось 1 раз.
Причина: опечатка
Oleg_D
постоялец
 
Сообщения: 390
Зарегистрирован: 09.05.2011 11:28:36

Re: Помогите с заданиями

Сообщение bormant » 24.12.2012 15:16:32

А ещё лучше (по крайней мере, не не хуже :wink: ):
Код: Выделить всё
for i := n div 2 downto 2 do
  if (n mod i) = 0 then
    writeln(i);
Аватара пользователя
bormant
постоялец
 
Сообщения: 407
Зарегистрирован: 21.03.2012 11:26:01

Re: Помогите с заданиями

Сообщение A.N.Onim » 24.12.2012 18:39:48

Putnick, спасибо понял ошибку :D , но:
Putnick писал(а):И, кстати, цикл можно гнать не до n, а до квадратного корня из n.

Как? Если я ввожу число 100, то 100 мне не выведет уже, а максимум 10 :?: . Или я не так понял?
Oleg_D писал(а):Или так, без лишних переменных:
Код: Выделить всё
for i:= 2 to n div 2 do
   if (n mod i)=0 then  writeln(i);

Почему n div 2? Зачем? :?:
A.N.Onim
новенький
 
Сообщения: 17
Зарегистрирован: 24.12.2012 00:18:52

Re: Помогите с заданиями

Сообщение bormant » 24.12.2012 19:33:02

A.N.Onim писал(а):Почему n div 2? Зачем? :?:

Минимальный возможный делитель числа N (в условии не считается 1) равен 2, следовательно, между N/2 и N делители числа N заведомо отсутствуют. А зачем тогда их там искать?
Ах да, это было бы правильным решением, если бы в условии было сказано "все числа, кроме единицы и самого числа N, на которые
без остатка делится число N".
Но поскольку в условии нет подчёркнутого, при строгом формальном подходе, само число N должно быть выведено тоже. Для этого не обязательно перебирать числа от N/2..N, достаточно просто добавить writeln(N).

Но полагаю, что условие задачки всё же задумывалось симметричным ("кроме 1 и самого числа N")...
Аватара пользователя
bormant
постоялец
 
Сообщения: 407
Зарегистрирован: 21.03.2012 11:26:01

Re: Помогите с заданиями

Сообщение Paster Fob » 24.12.2012 19:38:59

A.N.Onim писал(а):Почему n div 2? Зачем? :?:

Потому что максимальный делитель кроме самого числа будет ровно половина.Например ввёл 100 значит максимальный делитель равен 50,Всё что больше на 100 не делится.Так что зачем лишние телодвижения в цикле.
Аватара пользователя
Paster Fob
постоялец
 
Сообщения: 188
Зарегистрирован: 22.02.2011 21:53:36
Откуда: Новосибирск.

Re: Помогите с заданиями

Сообщение bormant » 24.12.2012 19:41:29

Putnick писал(а):цикл можно гнать не до n, а до квадратного корня из n.
До n/2. У 100 есть делитель 50, который явно больше 10 (√100).
Аватара пользователя
bormant
постоялец
 
Сообщения: 407
Зарегистрирован: 21.03.2012 11:26:01

Re: Помогите с заданиями

Сообщение A.N.Onim » 24.12.2012 22:45:57

bormant писал(а):Но поскольку в условии нет подчёркнутого, при строгом формальном подходе, само число N должно быть выведено тоже.

Я думал, что правильно будет если и число n будет выводиться.
bormant писал(а):достаточно просто добавить writeln(N)

Наверное так и сделаю - это экономит ресурсы компа?
bormant писал(а):
Putnick писал(а):цикл можно гнать не до n, а до квадратного корня из n.
До n/2. У 100 есть делитель 50, который явно больше 10 (√100).

Так это Putnick немного ошибся?

Добавлено спустя 10 минут 7 секунд:
Всё, переписал:
Код: Выделить всё
program p_20_2;
var n: integer;

procedure BezOst (n: integer);
var i: integer;
begin
for i:= 2 to n div 2 do
                       begin
                       if (n mod i)=0 then
                                          writeln(i);
                       end;
end;

begin
writeln('Введите число: ');
readln(n);
BezOst(n);
writeln(n);
readln;
end.

Вроде работает.
A.N.Onim
новенький
 
Сообщения: 17
Зарегистрирован: 24.12.2012 00:18:52

Re: Помогите с заданиями

Сообщение Максим » 25.12.2012 00:53:40

A.N.Onim писал(а):
bormant писал(а):
Putnick писал(а):цикл можно гнать не до n, а до квадратного корня из n.
До n/2. У 100 есть делитель 50, который явно больше 10 (√100).

Так это Putnick немного ошибся?

Нет, он не ошибся. Запустите нижеприведённую программу.
Код: Выделить всё
program div_test;
var n: integer;

procedure BezOst (n: integer);
var i, k: integer;
begin
  for i:= 2 to trunc(sqrt(n)) do
  begin
    if n mod i=0 then
    begin 
      writeln(i);
      k:=n div i;
      if i<>k then
        writeln(k);
    end; 
  end;
end;

begin
  write('Enter number: ');
  readln(n);
  BezOst(abs(n));
  writeln(n);
  readln;
end.
Аватара пользователя
Максим
энтузиаст
 
Сообщения: 597
Зарегистрирован: 27.07.2007 01:51:43
Откуда: Москва

Re: Помогите с заданиями

Сообщение bormant » 25.12.2012 08:31:54

Так это Putnick немного ошибся?
Выше уже показали, что не ошибся. Дело в том, что делители числа n, не считая 1 и самого числа n, помимо того, что расположены в интервале [n,n/2], еще являются парными, найдя один делитель k, можно тут же получить и n/k. Поэтому самый большой из опорных делителей k не превышает корня квадратного из n (k*k=n), и цикл достаточен от 2 до sqrt(n).
Аватара пользователя
bormant
постоялец
 
Сообщения: 407
Зарегистрирован: 21.03.2012 11:26:01

Re: Помогите с заданиями

Сообщение Oleg_D » 25.12.2012 09:45:45

Для A.N.Onim на будущее.
В вашем решении begin-end лишний, но это не ошибка. Используйте для отступов два пробела -- этого достаточно. И в дальнейшем, цитируя задачу, давайте сразу её номер по книге, чтобы всем легче было искать её.

По поводу парных делителей.
В 20-й главе книги ещё не рассмотрены функции Sqrt и Trunc, поэтому я не предполагал от новичка ничего такого. Но мысль интересная, и решение может быть таким:
Код: Выделить всё
{ Печатаются все делители числа, кроме единицы и самого числа }
procedure BezOst (n: integer);
var p, q : integer;
begin
  p:=2; q:=n div 2;
  repeat
    if n mod p = 0 then begin
      q:= n div p;
      Writeln(p);
      if p<>q then Writeln(q);
    end;
    p:= p+1;
  until p>=q;
  Writeln;
end;

begin
  BezOst(15);   BezOst(16);   BezOst(160);
  Readln;
end.


Добавлено спустя 2 минуты 1 секунду:
Кстати, и цикл While здесь тоже пока не проходили.
Oleg_D
постоялец
 
Сообщения: 390
Зарегистрирован: 09.05.2011 11:28:36

Re: Помогите с заданиями

Сообщение A.N.Onim » 26.12.2012 00:00:43

Максим писал(а):Нет, он не ошибся.

Понял. :!:
Oleg_D писал(а):В вашем решении begin-end лишний, но это не ошибка.

Там после then было 3 строки - я укоротил а begin-end забыл убрать.
Oleg_D писал(а):И в дальнейшем, цитируя задачу, давайте сразу её номер по книге, чтобы всем легче было искать её.

Хорошо.
Oleg_D писал(а):Но мысль интересная, и решение может быть таким:

Это, наверное, запутанее.

Добавлено спустя 38 минут 39 секунд:
Начал изучать отладку(глава 21).
Итак, приступим к поиску «жучков», притаившихся в программе «P_20_1».
Хорошо бы проследить за изменением переменных в ходе выполнения программы.
Для этого вставим переменные в окно обзора «Watches». Поместите курсор под
переменной k и нажмите «Ctrl+F7». Появится диалоговое окно для добавления
переменной в окно обзора (рис. 47).

Изображение
Вместо Add Watch появляется окно Edit Watch. Как не пробывал всё равно. И после этого отладка не так, как в книге идёт.
A.N.Onim
новенький
 
Сообщения: 17
Зарегистрирован: 24.12.2012 00:18:52

Re: Помогите с заданиями

Сообщение Oleg_D » 26.12.2012 09:19:56

A.N.Onim писал(а):Вместо Add Watch появляется окно Edit Watch.

Это несущественно. Те картинки, что в книге, остались от Borland Pascal, а на Free они немного другие. Прикладываю к сему посту отладочную картинку со своего компьютера (версия FP-2.6.0).
На Free отладчик немного кривоват, как мне кажется. Так, для ввода строки в пошаговом режиме вам придётся нажимать Enter дважды. Может быть, надо отразить это в книге.
Вложения
Debug_FP.png
Отладочная картинка на FP-2.6.0
Oleg_D
постоялец
 
Сообщения: 390
Зарегистрирован: 09.05.2011 11:28:36

Re: Помогите с заданиями

Сообщение A.N.Onim » 27.12.2012 00:20:25

Как мне обновить Фрее Паскаль?
Сейчас пишет:
- Free Pascal IDE Version 1.0.12;
- Compiler Version 2.4.4;
У меня Windows ХР 32-бит.
A.N.Onim
новенький
 
Сообщения: 17
Зарегистрирован: 24.12.2012 00:18:52

След.

Вернуться в Книга "Песни о Паскале"

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3

Рейтинг@Mail.ru