сито из эратосфена в ц

0

Вот мой код для сита эратосфенов в C. Он дает мне следующий результат.

2 3 5 7 11 13 17 19 23 25 31 35 37 41 43 47

Мой вывод включает в себя 25 и 35 также, которые не являются простыми числами, и не включает 29.

Может ли кто-нибудь сказать мне, где я ошибаюсь.

#include<stdio.h>
#include<math.h>
int main()
{
    int i,a[50],b[50],j,n=0,s;
    for(i=0;i<50;i++)
        a[i] = 1;
    a[0]=a[1] = 0;

    for(i=2;i<50;i++)
        if(a[i])
            for(j=pow(i,2);j<50;j+=i)
                a[j] = 0;

    for(i=0;i<50;i++)
        if(a[i])
        {
            b[n] = i;
            n++;
        }

    for(j=0;j<n;j++)
        printf("%d\n",b[j]);
    return 0;
}
  • 2
    Я не могу воспроизвести ошибку. Возможно, у вас другая реализация pow() . Попробуйте i*i вместо этого.
  • 0
    То же самое для меня. Пожалуйста, укажите версию компилятора и более подробную информацию о среде.
Показать ещё 6 комментариев
Теги:
algorithm
math
sieve-of-eratosthenes

4 ответа

6
Лучший ответ

Скомпилированный с gcc версии 4.4.7 (Ubuntu/Linaro 4.4.7-2ubuntu1), ваш код возвращает правильный результат. Вероятно, проблема связана с компилятором и с реализацией pow().

Вероятно, у вас есть наивная реализация pow которая вычисляет pow(x,y) как exp(y*log(x)). Это арифметика с плавающей запятой, и она страдает от общих проблем с плавающей точкой. Это означает, что результат pow(x,y) преобразованный в целое, будет усечен из-за двойного арифметического log(x)*y и экспоненциальности, который вернет двойное значение, немного меньшее, чем целое x*y.

Измените код на

for( j = i * i; j < 50; j += i)
    a[j] = 0;

Кроме того, мы можем выполнять итерацию только до sqrt (n), потому что второй цикл будет выполнен только тогда:

for( i = 2; i < sqrt(50); i++)
    if( a[i]) // if not marked
        /* mark starting from i*i because i*j for j<i
         * has been already marked when i was j */
        for( j = i * i; j < 50; j += i)
            a[j] = 0; 

связанная с этим проблема: функция блокировки блоков кода не работает в c

  • 1
    2*i уже был помечен как не простой, когда i было 2 . Аналогично для 3*i , 4*i и т. Д. Достаточно начать с i*i .
  • 0
    @bits_international Тем не менее, это не решение проблемы SO. На самом деле мы имеем дело с некоторыми другими проблемами, кроме алгоритмических.
Показать ещё 2 комментария
4

Как наблюдали другие, ошибка находится в функции pow. Я не могу воспроизвести вашу ошибку с кодом, который вы ppow, но когда я откатываю свою собственную функцию ppow:

double ppow(double a, double x)
{
    return exp(log(a) * x);
}

мой список соответствует вашим. Я думаю, что стандартно-совместимые реализации pow должны рассматривать целочисленные показатели как частный случай, который может принимать отрицательные основания, поэтому ваш pow кажется несоответствующим.

Вместо pow(i, 2) используйте i*i. Это должно быть быстрее, и вам не придется ссылаться на библиотеку математики.

  • 0
    Спасибо, использование i * i вместо pow (i, 2) решило мою проблему, но я до сих пор не могу понять, почему pow (i, 2) дает мне неправильный ответ.
  • 1
    pow работает с числами с плавающей точкой. Они не являются точными, тем более, когда они являются результатом вычисления, как в ppow выше реализации ppow . Для ppow(20, 2) я получаю 399.9999999999999, например, который при преобразовании в int станет 399. Возможно, вы могли бы избежать округления: ppow(i, 2) + 0.5 , но я рекомендую использовать простое умножение для целочисленных степеней особенно для простых, таких как квадраты.
Показать ещё 2 комментария
2

Я пытаюсь воспроизвести ваш результат, но я не могу.

Информация о ОС:

$ uname -a Linux 3.13.0-29-generiС# 53-Ubuntu SMP Wed Jun 4 21:00:20 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

Информация о компиляторе:

$ gcc --version gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2

Обобщение:

$ gcc sieve_of_eratosthenes.c -lm -o sieve_of_eratosthenes

Запуск:

$./sieve_of_eratosthenes

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

  • 0
    Должен быть комментарий, хотя.
  • 0
    Мой рейтинг не позволяет мне оставлять комментарии.
0

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

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

Вероятно, это относится к вашей системе, когда вы вызываете pow(i,2) когда i равно 5.

В качестве косвенных доказательств, подтверждающих эту гипотезу, обратите внимание, что каждое число (в указанном диапазоне [0-49]), которое кратно 5 и просто больше 5, появляется в вашем списке простых чисел.


Вот фрагмент кода для извлечения исключений, которые могли произойти в результате операции FP:

#include <fenv.h>
#include <stdio.h>

void print_fe_exceptions()
{
    printf("Exceptions raised:");
    if (fetestexcept(FE_DIVBYZERO)) printf(" FE_DIVBYZERO");
    if (fetestexcept(FE_INEXACT  )) printf(" FE_INEXACT  ");
    if (fetestexcept(FE_INVALID  )) printf(" FE_INVALID  ");
    if (fetestexcept(FE_OVERFLOW )) printf(" FE_OVERFLOW ");
    if (fetestexcept(FE_UNDERFLOW)) printf(" FE_UNDERFLOW");
    feclearexcept(FE_ALL_EXCEPT);
    printf("\n");
}

И вот описание каждого исключения:

FE_DIVBYZERO // Pole error occurred in an earlier floating-point operation
FE_INEXACT   // Inexact result: rounding was necessary to store the result of an earlier floating-point operation
FE_INVALID   // Domain error occurred in an earlier floating-point operation
FE_OVERFLOW  // The result of an earlier floating-point operation was too large to be representable
FE_UNDERFLOW // The result of an earlier floating-point operation was subnormal with a loss of precision

Ещё вопросы

Сообщество Overcoder
Наверх
Меню