ほとんど判読できない素数計算機

これは私の最初の適度に大きいC#プログラムです。私のコードがesolangで書かれているように見えることを考えると、私はある時点で何か間違ったことをしたと思います。私の主な優先事項は読みやすさですが、スピードもプラスです。

using System;

public class PrimeSearcher {
    public static string Stringilate (int[] iterable) {
        string returnable="";
        foreach(int i in iterable){
            returnable+=i.ToString()+" ";
        };
        return returnable;
    }
    public static bool isPrime (int[] iterable,float target) {
        foreach(int i in iterable){
            if(target%i==0){
                return false;
            }
            if(i==0){ return true; }
            //reached the "end" (last discovered prime) of the array, hurray!
        }
        return true; //will only do anything for the last element
    }
    static public void Main() {
        int[] primes=new int[1000];
        float j=2; //float because I think it's the smallest datatype that can return a non-zero number when divided, correct me if I'm wrong
        while(primes[primes.Length-1]==0){
            if(isPrime(primes,j)){
                primes[Array.IndexOf(primes,0)]=(int)j;
            }
            j++;
        }
        Console.WriteLine(Stringilate(primes)); 
        //I don't *think* ToString worked when I tried it.
    }
}
14

5 答え

  • By starting with j = 3 and incrementing j by 2 you could skip a lot of unneeded computations because it will skip even values.

  • Instead of using a float I would go with int. Both are 32-Bit and you won't need the floating point values.

  • You should let your variables have some space to breathe.

    Consider

    while(primes[primes.Length-1]==0){
        if(isPrime(primes,j)){
            primes[Array.IndexOf(primes,0)]=(int)j;
        }
        j++;
    }  
    

    versus

    while (primes[primes.Length - 1] == 0)
    {
        if (isPrime(primes, j))
        {
            primes[Array.IndexOf(primes, 0)] = (int)j;
        }
        j += 2;
    }  
    

    where the later is much more readable. It uses the bracing style most C# developer use as well.

  • Stringilate() could be improved as well by using string.Join() which would look like so

    public static string Stringilate(int[] iterable)
    {
        return string.Join(" ", iterable);
    }  
    

    and as a side note, if you need to concatenate strings in a loop its much better to use a StringBuilder instead.

  • You should be consitent in your coding style (public static vs. static public).

  • You are using braces although they might be optional. Good choice !

  • Instead of a concrete type you could use var instead

18
追加された
@BenRivers "人間が読めるコード"他にもありますか?コンパイラは空白を気にしませんが、あなたが書いたコードはいつか人間に読まれることになります。運が悪ければ、その人間があなたになるでしょう。
追加された 著者 David Richerby,
スペースのスタイルは少し説明しておく価値があると思います。キーワード( ifwhile など)の間にスペースが入り、識別子(関数名)の間には開きません。かっこを開きます。私が初めてこのスペーシングスタイルに遭遇したとき、誰もその規則を説明しなかったし、私はどこにスペースを追加するか対して混同しなかった。
追加された 著者 Hasan Tareque,
@Benインデントツールを使用してコードを再フォーマットすることができます。こうすることで、理論的にはスタイルを自分のスタイルで記述して、公開前に自動的に変更することができます。そのようなツールの1つにGNU indent がありますが、それがC#をサポートしているかどうかはわかりません。
追加された 著者 rotemk55,
本当にありがとう!私は本当にC#についてもっとよく知る必要があります。角かっこに関しては、私は他の言語での経験から foo(){に慣れていますが、人間が読めるコードを書く必要があるときはそれを頭に入れておきます。
追加された 著者 tuesprem,

iterable の名前を変更します。それが反復可能であるという事実は型情報であり、それは既に実際の型宣言 int [] に記録されています。名前を divisors に変更すると、その目的が明確になります。

11
追加された
これは良い点です。 vote ++; 私はPythonのような弱い型付けの言語に慣れているので、これらの慣習のいくつかには慣れていません。
追加された 著者 tuesprem,

この繰り返しはかなり奇妙で非効率的です。

int[] primes=new int[1000];
float j=2; //float because I think it's the smallest datatype that can return a non-zero number when divided, correct me if I'm wrong
while(primes[primes.Length-1]==0){
  if(isPrime(primes,j)){
    primes[Array.IndexOf(primes,0)]=(int)j;
  }
  j++;
}

代わりに、もっと簡単な方法があります。

int count = 1000;
int[] primes = new int[count];
primes[0] = 2;
float j = 3;
for (int i = 1; i < count; i++)
{
  if (isPrime(primes, j))
  {
    primes[i] = (int)j;
  }
  j += 2;
}

isPrime()では、ターゲットのsqrtまで含めて反復するだけで十分です。

foreach(int i in iterable.TakeWhile(x => x != 0 && x <= Math.Sqrt(target))){
            if(target%i==0){
                return false;
            }...
11
追加された

文字列は不変であるため、これはあまり効率的ではありません。

<���������������������������������������������������������������������

�ぜ彼らは<�コード> iterable </コード>を渡す必要があるのですか?あなたはあなたが持っている値を使うべきです。

<���������������������

����ード>main</コード> in that class does NOT work in my environment. Is that supposed to be the ctor? Not sure that is working コード.

クラスとしては意味がありません。クラスから結果を公開することすらありません。

すべての点で打つことなく、これは私がこれに取り組む方法です:

テスト

<������������������������������������

����ド

<����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
3
追加された
        foreach(int i in iterable){
            if(target%i==0){
                return false;
            }
            if(i==0){ return true; }
            //reached the "end" (last discovered prime) of the array, hurray!
        }

        ...

        float j=2; //float because I think it's the smallest datatype that can return a non-zero number when divided, correct me if I'm wrong

私がループを見たときの私の最初の本能は、コードがバグがあるに違いないということでした。 targetfloat なので、 target%iNaN になります(これは比較できません)。 0 と同じ)

つまり、 targetfloat であることにかかっている唯一のことだと思います。なぜなら、実際には分割をどこでも使用していないからです。そのため、ループ内のコメントの欠如(//targetはfloatなので、0で除算しても例外は発生しません)と j のコメントはどちらも誤解を招きます。

もちろん、最善の解決策はフロートを捨てて整数で動作することです。

1
追加された