Как стать автором
Обновить

Комментарии 22

вроде есть - 49 бардовая, как все кратные 7

Казалось бы, при чём тут барды

Но в C++ ведь есть словарь - map. В Си можно сделать так:

struct Pair 
{
  int key;
  int value;
};

// еще какой-то код
Pair* pev_primes = malloc(new_size*Pair); 
// логика обработки предыдущих простых

Конечно, тут надо оптимизировать -- писал навскидку (Иначе один словарь будет пахнуть квадратичной сложностью).

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

исходная задача такая: сделайте Эратосфен (или а ля Эратосфен), но не для фиксированного интервала (а стандартный Эратосфен именно именно об этом), но чтобы найти нужное число простых чисел. дурацкая - не дурацкая, но я встретил именно такую постановку.

я за любую оптимизацию, но надо четко понимать, оптмизация ЧЕГО. самого алгоритма или его имплементации.

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

Строго говоря, кстати, стандартный Эратосфен с математической точки зрения, не нуждается в фиксированном интервале -- он применяется ко всему множеству натуральных :). Но я понимаю, о чем вы.

о том и речь, что с математической точки зрения у нас есть БЕСКОНЕЧНАЯ бумажка, на которой мы пишем числа. в том и состоит (учебный, ничего особо умного, конечно - это чисто учебная задача для школьников) прикол, как эту бесконечность ЭМУЛИРОВАТЬ в вычислительном процессе

зачем оптимизировать изначально не оптимальный метод?

Есть на много шустрее методы получения простых чисел,

на тех же самых делителях например и без потребления такого объёма памяти

(сохраняем все простые числа в массив, проходимся по каждому натуральному числу и проверяем есть ли у него делитель из прежде найденных, если нет, то добавляем в наш массив, изначально он содержит только 2)

(можно оптимизировать ищя только по простым числам меньше квадратного корня (p*p<n))

Кстати верхняя граница тоже высчитывается математически как интегральный логарифм (см. пи функция)

речь не об оптимизации.

не эта задача ставилась. исходная задача - сделать именно и конкретно Эратосфен. но раздвижной.

с другой стороны, вы перемешали - оптимизация ЧЕГО. оптимизация кода и оптимизация алгоритма. Эратосфен не оптимален, но никто и не говорил что он оптимален.

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

Определение не до конца верное. Стоит добавить, что это не просто числа, а натуральные числа, так как без этого уточнения, -7 вполне подходит под определение простого числа.

Не подходит. -7 mod (-1) = 0

Так ведь и 7 кратно -1, то есть 7 - не простое. Я пользуюсь достаточно простым определением простого числа - натуральное число, у которого всего 2 различных натуральных делителя

>> Как построить алгоритм «раздвижного решета» для языка Си или С++?

<< А в чем проблема? Словари (и все "раздвижные" структуры данных) на С пишутся при помощи ссылочек в память. Стандартно описанный во многих учебниках код . Или я чего то не допонял? Решение не доброе тем, что легко выстрелить себе в ногу, но более чем рабочее.

В обычном решете Эратосфена внешний цикл можно делать до корня из maxNum, а внутренний цикл начинать с i * i. Так будет слегка быстрее - процентов на 30.

(единицу, как и договорились, мы сразу выбросим из рассмотрения)

Мы не договаривались

Если в качестве границы брать совершенные числа, то ничего запоминать не придётся. но 1 проход нужен будет, что бы забрать все найденные простые. Жаль только, что эти числа редко встречаются…

Для Вашего случая подойдет оптимизация решета Эратосфена с запоминанием минимального простого делителя.

В словарь заносятся только произведения текущего числа на простые числа не меньше его минимального простого делителя.

По основной теореме арифметики составное число будет занесено в словарь только один раз.

var primes = new List<int>();
var divisors = new Dictionary<int, int>();
for (int num = 2; ;++num) {
  if (divisors.TryGetValue(num, out int divisor){
    //составное число
    divisors.remove(num);
    foreach(int mul in primes){
      if (mul > divisor)
        break;
      divisors[num*mul] = mul;
    }
  } else {
    yield return num;
    primes.Add(num);
    foreach(int mul in primes){
      divisors[num*mul] = mul;
    }
  }
}

большое спасибо, но речь была НЕ об оптимизации. это учебная задача с одной конкретной целью - обычный Эратосфен, но произвольно раздвинутый.

А зачем вообще хранить «последнее удаленное» число если оно вычисляется целочисленным делением ?
Достаточно хранить только сами простые числа, чтобы использовать их в "последующих проходах"

например, на интервале [0..99] вы храните {37:74}

а для интервала от 100 оно элементарно получается как 100//37*37 = 74

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

Об этом стоило упомянуть

Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации