尤拉素數篩選與命令列傳參啟動C程式

Exboot發表於2020-12-02

尤拉素數篩選與命令列傳參啟動C程式


不出所料,期末考試我選的就是素數篩選這道題
寫了一下午,邊學邊寫,現把成果發出來
有些邏輯還不是很好,不過就這樣吧不改了

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>
#include <time.h>

#define MaxArray 100000001
extern char *optarg;
int Prime[MaxArray], PrimeCounter = 0;
bool Composite[MaxArray] = {false};

void eulerSieve (int N)
{
    for (int NumCounter = 2; NumCounter <= N; NumCounter++)
    {
        if (Composite[NumCounter] == false)
            Prime[PrimeCounter++] = NumCounter;
        
        for (int Poller = 0; Poller < PrimeCounter; Poller++)
        {
            if (NumCounter * Prime[Poller] > N)
                break;

            Composite[NumCounter * Prime[Poller]] = true;

            if (NumCounter % Prime[Poller] == 0)
                break;
        }
    }
}

int primeSieve (int start, int end)
{
    int s, e;
    double Times;
    clock_t st, et;

    if (start > end)
    {
        s = end;
        e = start;
    }
    else if (start == end)
    {
        printf ("The start and end cannot be the same number.\n");
        return -1;
    }
    else
    {
        s = start;
        e = end;
    }
    
    st = clock();
    eulerSieve (e);
    et = clock();
    Times = (double)(et-st)/CLOCKS_PER_SEC;

    for (int Num = 0, Row = 0; Num < PrimeCounter; Num++)
    {
        if (Prime[Num] > s)
        {
            printf ("%d\t", Prime[Num]);
            Row++;

            if (Row %10 == 0)
                printf ("\n");
        }
        else continue;
    }

    printf ("\n\nIt took %.06f seconds to filter all prime numbers from %d to %d.\n"
    "Written by Aloento, Bye.\n\n", Times, s, e);

    return 0;
}

int isdigitstr (char *str)
{
    if (strspn(str, " 0123456789") == strlen(str))
        return atoi (str);
    else
    {
        printf ("Please enter a Positive Integer.\n");
        exit (-1);
    }
}

int help (char *name)
{
    printf ("usage: %s [-h] [-s] [-e]\n"
    "\n-h: Help to use Prime Sieve."
    "\n-s: The starting number for filtering, optional, default is 0."
    "\n-e: The number where the filtering ends, required.\n"
    "\nFor example: "
    "\n./%s -s 100 -e 200\n"
    "\nWritten by Aloento\n", name, name);

    return 1;
}

int menu (int argc, char *argv[])
{
    int opt = 0, start = 0, end = -1;

    while (EOF != (opt = getopt(argc, argv, "hs:e:")))
    {
        switch (opt)
        {
        case 's':
            start = isdigitstr (optarg);
            break;

        case 'e':
            end = isdigitstr (optarg);        
            return primeSieve (start, end);
            break;

        case '?':
            printf ("Unsupported parameters, Please check your input.\n");
        case 'h':
        default:
            return help (basename(argv[0]));
            break;
        }
    }

    return help(basename(argv[0]));
}

int main (int argc, char *argv[])
{
    return menu (argc, argv);
}

//Written by Aloento.

關於為什麼main函式只有一行
因為我們老師的要求是main函式不得超過5行
我不是很能理解他的腦回路
所以我就嘗試著讓他也不能理解我的腦回路(?

關於尤拉篩的註釋都在上一篇文章了,這裡就不重複放了
這個演算法有個大問題就是每次都要從0算起,無論你要求的起始點在哪
但是看在它線性時間複雜度的面子上就不再造輪子了
算一億位只要半秒我個人覺得還行
再大的數字在Windows上會崩潰,得在Linux上跑
那個判斷起始點的if段寫的也不好,不過我就不拿空間換時間了
反正看的是篩選效率又不是列印效率(ε=ε=ε=┏(゜ロ゜;)┛

主要的知識點除了尤拉篩以外還有:
getopt傳參啟動,atoi把char轉int等
getopt的optarg很神奇,它會判斷你是第幾次請求
每請求一次就會指向下一個argv
我這裡最開始被坑了一下

atoi等一系列操作在失敗的時候只會返回0
這一點不是很好,得在最開始的時候判斷一下是否是數字
關於為什麼" 0123456789"裡面零的前面有個空格
那是因為optarg傳回的引數就帶個空格在前面
但是如果你在後面加個空格,比如 -e 10 100
那個100就是下一個argv,所以不用擔心出問題
要讀取100,再請求一次optarg就好了

後面要是還想起啥就下一篇再說吧
最近在玩命學JavaFX,寫這玩意的時候老是在想
我現在要是在寫Java的話這個就簡單了那個也輕鬆了(而且還下意識的打了sysout

相關文章