Модифицированное сито для поиска простых чисел в схеме

Я работаю над тем, чтобы придумать решение для списка простых чисел с использованием решета Эратосфена. Таким образом, программа должна находить простые числа до определенного числа n. Я считаю, что нашел неполное решение, но не уверен, как действовать дальше.

;;;This is a helper function
(define sievehelper 
   (lambda (list)
      ;;; This is the base condition where we are comparing 
      ;;; that the divisor is less than the square root of n""
      (if (> (car list) (sqrt (car (reverse list))))
          '()
          ;;; If the base condition has not be reached, then send it through 
          ;;; this filter function where not-divisible by will go through
          ;;; the specified list and only output the list which contains
          ;;; the numbers that are not divisible by (car list)
          (filterfunc (not-divisible-by (car list)) 
                      list)))

Я протестировал другую вспомогательную функцию fliterfunc сам по себе, и она отлично работает.

;;;; This is the main function that calls the above helper function
(define sieve 
   (lambda (n)
      ;;; `makelist` is a helper function to generate the list from 2 to n
      (sievehelper (makelist n))))

Я протестировал вспомогательную функцию makelist отдельно, и она отлично работает.

Мой вопрос связан с вспомогательной функцией sievehelper с точки зрения того, как перебирать различные элементы в списке в качестве делителя.

Любая помощь приветствуется. Спасибо.


person user15155886    schedule 23.02.2021    source источник
comment
Обратите внимание, что решето Эратосфена не включает проверку на делимость. Если вы это сделаете, у вас будет другое сито.   -  person molbdnilo    schedule 23.02.2021
comment
Я согласен, что это не связано с делимостью. Вот почему я попытался назвать его модифицированным решетом, потому что это то, что нас просили сделать, в частности, функцию фильтра.   -  person user15155886    schedule 23.02.2021
comment
Ну, я читал, что работаю [...] над решением [...] с использованием Решета Эратосфена. (Вам нужен еще один шаг в дополнение к проходу фильтрации; я подозреваю, что вы застряли, пытаясь выполнить всю работу одной функцией.)   -  person molbdnilo    schedule 23.02.2021
comment
Мой вопрос касается вспомогательной функции sievehelper с точки зрения того, как перебирать различные элементы в списке в качестве делителя. на самом деле это совсем не ясно. в чем именно сложность? во-первых, вам нужно показать нам функции, которые, как вы говорите, вы реализовали и протестировали, в основном, filterfunc. makelist очевидно, но filterfunc может пойти разными путями, и нам нужно увидеть ваш, чтобы иметь возможность помочь. тогда осталось not-divisible-by. Вам нужна помощь в реализации, это вопрос? вы пробовали его кодировать? просьба уточнить.   -  person Will Ness    schedule 23.02.2021


Ответы (2)


Один фрагмент кода, который приводит к зависанию, — это (if ( > (car list) (sqrt (car(reverse list)))), который очень похож на условие цикла, которое вы могли бы использовать в других языках (и слово iterate также намекает на просмотр в других языках).
Я бы порекомендовал вы начинаете сначала, с другой стратегией.

Когда вы работаете со списками, вы обычно хотите рекурсивно использовать только их структуру.

Предположим, что у вас есть список всех целых чисел, начиная с 2.
В качестве первого шага вы хотите сохранить двойку и удалить все ее кратные из оставшейся части списка.
Теперь результат этого удаления даст вам список, который начинается со следующего простого числа, т.е. 3, так что вы можете повторить процедуру с этим частичным результатом, который удалит все кратные 3, и повторить снова с этим частичным результатом, и так далее, пока не будет больше нет списка.

(Обратите внимание, что это далеко не так эффективно, как могло бы быть, но это скорее начало работы с рекурсивным уровнем внушения. Прочтите ответ Уилла, чтобы узнать больше.)

Если принять желаемое за действительное и предположить, что существует процедура remove-multiples-of, которая делает то, на что она похожа, это могло бы выглядеть так:

(define (my-sieve-helper ls)
  (if (null? ls)
      '()
      (cons (car ls)
            (my-sieve-helper (remove-multiples-of (car ls) (cdr ls))))))

Итак, remove-multiples-of...
Это то же самое, что хранить все числа, которые не делятся на числа, так что давайте придумаем другую функцию:

(define (remove-multiples-of x ls) (filter (not-divisible-by x) ls))

где (not-divisible-by x) — это процедура, которая принимает число и возвращает, не делится ли это число на x.

(define (not-divisible-by n) (lambda (x) (not (zero? (remainder x n)))))

И теперь мы можем добавить подходящую обертку.
Я сделал так:

(define (from-to m n)
  (if (> m n)
      '()
      (cons m (from-to (+ m 1) n))))

(define (my-sieve n) (my-sieve-helper (from-to 2 n)))

Контрольная работа:

> (my-sieve 100)
'(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97)
person molbdnilo    schedule 23.02.2021
comment
Большое спасибо за предложение. я попробую это - person user15155886; 23.02.2021
comment
до тех пор, пока список не закончится, также является условием остановки цикла, но оно заметно ухудшает временную сложность кода OP. :) - person Will Ness; 23.02.2021
comment
Спасибо @molbdnilo. Мои проблемы были 2 раза, проверка базового условия была неправильной, а также был обратный вызов рекурсивной структуры. Также в этой части не могли бы вы объяснить, что делает cons (car ls) '''(cons (car ls) (my-sieve-helper (remove-multiples-of (car ls) (cdr ls)))) Is он создает список, добавляя 1-й элемент оставшегося списка обратно в начало списка - person user15155886; 24.02.2021
comment
@user15155886 user15155886 нет, (cons (car ls) (my-sieve-helper (remove-multiples-of (car ls) (cdr ls)))) == (let* ( (x (car ls)) (xs (cdr ls)) (ys (remove-multiples-of x xs)) (zs (my-sieve-helper ys)) ) (cons x zs)), поэтому он добавляет первый элемент списка к результату рекурсивной обработки результата удаления кратных первого элемента в остальной части списка. - person Will Ness; 28.02.2021

Что ж, ваш вопрос представляет собой интересный случай недостаточной спецификации, который может быть выгодным, задерживая фактическую спецификацию, а не просто реализацию, как обычно, подпрограмм, используемых вашим фрагментом кода.

Здесь у нас есть sievehelper, который использует нереализованные неуказанные filterfunc и not-divisible-by. Несмотря на их наводящие на размышления названия, эти функции могут делать что угодно, пока они работают, когда используются вместе, и заставляют функцию, использующую их, sievehelper, также выполнять свою работу, как предполагалось. Отложенная спецификация для победы!

Итак, давайте сначала посмотрим, что может означать sievehelper как данное, что он делает? Предполагая очевидное значение двух подпрограмм, кажется, что она предназначена для выполнения одноэтапной фильтрации своей рабочей последовательности, отбрасывая ее из любых кратных ее головному элементу, который находится в его позиции car.

Это сигнализировало бы об условии остановки, возвращая (). Это условие остановки a*a > z для входного списка [a,b,c,...,z].

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

Таким образом, это обнаруженное требование относится к третьему нереализованному используемому подмаршруту, makelist. Вы упомянули, что он должен создать список последовательных натуральных чисел от 2 до n, и теперь мы понимаем, зачем нам это нужно.

Итак, чтобы перебирать через различные версии входного списка, поскольку каждый делитель по очереди отфильтровывается из него, используя ваш sievehelper определение как дано, ваша sieve функция должна быть изменена, например, как

(define sieve 
   (lambda (n)
      (let ((init (makelist n)))
        (let loop ((this              init ) 
                   (next (sievehelper init)))
            (if (null? next)
              this
              (cons (car this) 
                    (loop              next 
                          (sievehelper next))))))))

Этот код основан на работе с парой — текущей последовательностью и ее следующей итерацией. На каждом шаге следующая версия списка находится после удаления из него всех кратных его элементу head на sievehelper (включая сам элемент head, следующее найденное простое число) -- или пустой список вместо этого возвращается, чтобы сигнализировать об окончании обработки, когда известно, что все числа в списке уже являются простыми, по построению.

Пробуем в Racket:

> (sieve 50)
'(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47)

(Приведенный выше код включает исправление от ad-absurdum из последующей записи вопросов и ответов к ошибке, которая изначально содержалась в этом коде) .

Чтобы запустить его, необходимо было сделать дополнительные определения:

(define filterfunc filter)

(define (not-divisible-by n)
  (let ((m n))
    (lambda (x)
      (let ((ret (not (= x m))))
         (if (>= x m) (set! m (+ m n)) #f)
         ret))))

(define (makelist n)
  (range 2 (+ 1 n)))   ;; in Racket

Определение not-divisible-by таким, как мы сделали здесь, делает его действительно решетом Эратосфена, работающим только посредством дополнений и сравнений. А ранняя остановка, как и в исходном коде, не позволяет его временной сложности ухудшиться, чем должна.

person Will Ness    schedule 23.02.2021
comment
Спасибо Уилл. Это также определенно помогает мне лучше понять эту проблему и предоставляет другое решение, над которым я могу работать. - person user15155886; 24.02.2021