整数が偶数か奇数かを確認するにはどうすればよいですか?[閉まっている]


193

Cで特定の数値が偶数か奇数かを確認するにはどうすればよいですか?


5
ビットごとの(&)を使用するバージョンは、モジュロ(%)バージョンよりもはるかに効率的です。正解として選択したものを変更する必要があります。
Stefan Rusek、2008年

6
問題になることはほとんどありません-引数は定数です。オプティマイザにとって簡単
MSalters 2008年

2
読みやすさもこれに含まれます。
Brian G

2
組み込みアプリケーション(私がプログラミング時間の大部分を費やしている世界)では、一部のプロセッサは非常にプリミティブな演算ユニットを備えており、除算/モジュラス演算を簡単に実行できません。このため、通常は代わりにビット単位AND法を使用します。ただし、最新のデスクトップのCPUでは、これは当てはまりません。
bta

3
モジュラス演算が理解しやすいとは思いませんでした。最初に偶数か奇数かを判断する必要があったとき、最初に頭に浮かんだのはビット単位のマスクでした。これを手作業で行う傾向があるのは、最下位の桁を見て、それが{0 2 4 6 8}または{1 3 5 7 9}のどちらにあるかを確認することです。つまり、0または1だかどうかを確認するために、最下位ビットを見に直接変換する
Pパパ

回答:


449

モジュロ(%)演算子を使用して、2で除算するときに余りがあるかどうかを確認します。

if (x % 2) { /* x is odd */ }

x&1を使用する方が「より高速」または「より効率的」であると述べた上で、数人の人が私の答えを批判しました。私はこれが事実であるとは思わない。

好奇心から、2つの簡単なテストケースプログラムを作成しました。

/* modulo.c */
#include <stdio.h>

int main(void)
{
    int x;
    for (x = 0; x < 10; x++)
        if (x % 2)
            printf("%d is odd\n", x);
    return 0;
}

/* and.c */
#include <stdio.h>

int main(void)
{
    int x;
    for (x = 0; x < 10; x++)
        if (x & 1)
            printf("%d is odd\n", x);
    return 0;
}

次に、マシンの1つでgcc 4.1.3を使用してこれらを5回コンパイルしました。

  • 最適化フラグなし。
  • -O付き
  • -O付き
  • -O2あり
  • -O3を使用

(gcc -Sを使用して)各コンパイルのアセンブリ出力を調べたところ、それぞれの場合で、and.cとmodulo.cの出力は同じでした(両方ともandl $ 1、%eax命令を使用しました)。これは「新しい」機能ではないかと思いますが、古いバージョンに遡ると思われます。また、商用(オープンソース)の(過去20年間に作成された)非難解なコンパイラーがそのような最適化を欠いていることも疑います。他のコンパイラでテストしますが、現時点では利用できません。

他の誰かが他のコンパイラやプラットフォームターゲットをテストしたいと思っていて、異なる結果が得られた場合、私は知りたいと非常に興味があります。

最後に、モジュロバージョンは、符号付き整数の実装の表現に関係なく、整数が正、負、またはゼロのいずれであっても機能することが規格によって保証されています。ビット単位のバージョンではありません。はい、私は2の補数がいくぶん遍在していることを理解していますので、これは実際には問題ではありません。


11
質問ではCでそれを行う方法を具体的に尋ねたので、Javaでそれを行う方法を理解できないとchustarが言及したにもかかわらず、私はCで答えました。私はこれがJavaの答えであると主張したり、示唆したりしませんでした。Javaを知りません。最初の反対票を獲得したばかりで、その理由について混乱しています。しかたがない。
Chris Young

33
(x%2!= 0){/ * xは奇数* /}なら、誰が知っているでしょう。Javaも知らない。
オイゲンスク2008年

9
カルマが投票に費やす必要なしに、ビットワイズ演算子のモロンと区別するために多くの賛成票を得ています。
wnoise

13
私はすべてに同意しますが、1つを除いて、概念的には整数と真理値を別々にしたいので、「if(x%2 == 1)」と書くことを好みます。コンパイラにとっても同じですが、おそらく人間にとっては少しわかりやすいでしょう。さらに、ゼロ以外をtrueと解釈しない言語で同じコードを使用できます。
Thomas Padron-McCarthy

46
私のベンチマーク?どのベンチマーク?ベンチマークはしませんでした。生成されたアセンブリ言語を調べました。これは、printfとはまったく関係ありません。
クリスヤング

207

君たちは効率が良すぎる あなたが本当に欲しいのは:

public boolean isOdd(int num) {
  int i = 0;
  boolean odd = false;

  while (i != num) {
    odd = !odd;
    i = i + 1;
  }

  return odd;
}

について繰り返しisEvenます。

もちろん、それは負の数に対しては機能しません。しかし、輝きには犠牲が伴います...


17
負の値で引数の例外をスローし、ドキュメントでこの関数がO(N)であると指摘した場合は、これで問題ありません。
Jeffrey L Whitledge、2008年

7
エンタープライズバージョンではXMLを使用する必要があります。もちろん、今日、あなたが照会できることをウェブサービスだろう
マーティンベケット

58
これをルックアップテーブルで最適化する必要があります。
Weeble

1
私はそのような僧侶よ、新しい千年紀に1あなたの6999の担当者に持っていた
エランメダン

7
これは素晴らしいです!上司から、エンタープライズライセンスでは標準ライセンス以外の何も提供されていないと感じていたため、怒っているクライアントがいると言われました。プログラムにこの関数を追加しました。実行速度が遅いため、彼のソフトウェアはより多くの作業をしていると思います!!!
Phil

97

ビット演算を使用します。

if((x & 1) == 0)
    printf("EVEN!\n");
else
    printf("ODD!\n");

これは、除算または係数を使用するよりも高速です。


43
除算や係数を使用するよりも速いと言っても不公平ではありません。C標準では、演算子のパフォーマンスについては何も述べられていません。まともなコンパイラーでも、どちらの場合でも高速なコードが生成されます。私は自分の意図を伝えるイディオムを個人的に選択し、ここでは%がより適切に思われます
Chris Young

21
私は(x&1)の方が好きです。なぜなら、数値が偶数と同じかどうかをチェックするからです。最後の桁が偶数か奇数かを確認します。私の意見では、モジュロ法よりもその意図を伝えています。(それほど重要ではありません。)
ジェレミー・ルテン

2
そうですね、主観的なものだと思います。「偶数」の通常の定義は「2で割り切れる整数」であり、「0、2、4、6、または8で終わる整数」ではありません。:-)
クリスヤング

4
@TraumaPony-ANSI標準Cおよび初期Javaの場合、コンピューターシステムに依存します。符号付き数値に使用される表現は指定されていません。2の補数、1の補数、グレイコードなどです。ただし、係数は常に係数です
Aaron

9
負の数に対しては普遍的に機能しません。詳細については、この回答を確認してください:詳細については、stackoverflow.com / questions / 160930 / をご覧ください。
Andrew Edgecombe

36

[冗談モード= "オン"]

public enum Evenness
{
  Unknown = 0,
  Even = 1,
  Odd = 2
}

public static Evenness AnalyzeEvenness(object o)
{

  if (o == null)
    return Evenness.Unknown;

  string foo = o.ToString();

  if (String.IsNullOrEmpty(foo))
    return Evenness.Unknown;

  char bar = foo[foo.Length - 1];

  switch (bar)
  {
     case '0':
     case '2':
     case '4':
     case '6':
     case '8':
       return Evenness.Even;
     case '1':
     case '3':
     case '5':
     case '7':
     case '9':
       return Evenness.Odd;
     default:
       return Evenness.Unknown;
  }
}

[冗談モード= "オフ"]

編集:enumに紛らわしい値を追加しました。


2
うわー...これはSCdFの解決策よりも気が遠いです!賞賛!賛成投票はできませんが、これはお勧めできません。しかし、面白いことに感謝します!
ウェスP

1
このアプローチの利点は、数値だけでなくそれ以上でも機能することです。また、次の行を置き換えた場合:char bar = foo [foo.Length-1]; これで:double bar = Char.GetNumericValue(foo [foo.Length-1]); 次に、任意の数値システムで機能します。
Jeffrey L Whitledge、2008年

5
バグレポート:不明なはずの14.65が奇数と報告されています。
TheSoftwareJedi 2008年

4
ソフトウェアジェダイ、それは「機能」です。;)
Sklivvz 2008年

31
TheSoftwareJedi:14.65は、私が今まで見た中で最も奇妙な整数の1つです。
Bruce Alderman、

16

ffpfへの対応 -私は数年前に同僚とまったく同じ議論をしましたが、答えは「いいえ」で、負の数では機能しません。

C規格では、負の数は3つの方法で表すことができると規定されています。

  • 2の補数
  • 1の補数
  • 符号と大きさ

このようにチェックする:

isEven = (x & 1);

2の補数と符号と大きさの表現では機能しますが、1の補数では機能しません。

しかし、私は以下がすべての場合にうまくいくと信じています:

isEven = (x & 1) ^ ((-1 & 1) | ((x < 0) ? 0 : 1)));

テキストボックスが私の小なり文字の後にすべてを食べていたことを指摘してくれたffpfに感謝します。


2番目のコード例にはテキストが不足していると思います。
ジェフイエーツ

3
それらの数を褒めましょう!
thejh 2013年

14

いいのは:

/*forward declaration, C compiles in one pass*/
bool isOdd(unsigned int n);

bool isEven(unsigned int n)
{
  if (n == 0) 
    return true ;  // I know 0 is even
  else
    return isOdd(n-1) ; // n is even if n-1 is odd
}

bool isOdd(unsigned int n)
{
  if (n == 0)
    return false ;
  else
    return isEven(n-1) ; // n is odd if n-1 is even
}

このメソッドは、2つの関数を含む末尾再帰を使用することに注意してください。コンパイラがSchemeコンパイラのように末尾再帰をサポートしている場合は、効率的に実装できます(while / untilのようなループに変わります)。この場合、スタックはオーバーフローしないはずです。


1
これはisOdd(0)をうまく処理しません。
スティーブマクロード

1
偶数の値を持つisOdd()または奇数の値を持つisEven()の無限ループ(末尾再帰あり)またはスタックオーバーフロー(末尾再帰なし)があると思います。trueで終了するだけです。それは、繰り返し止まる問題です。
Jeffrey L Whitledge、2008年

7
ああ、確かに、コメントなしで修正して、私をバカのように見せてください。それはいいです。
Jeffrey L Whitledge、2008年

1
これで、コンパイルエラーが発生します。isEvenでは、すべてのコードパスが値を返すわけではありません。いいえ、実際にこのコードを試したことはありません。頭の中でコンパイラが文句を言っています。
Jeffrey L Whitledge、2008年

5
コンパイルエラー:すべてのパスはあなたのサンプルコードのバグなコメントを砲撃する価値の憎しみを返しますが、あなたはISEVEN(5)を呼び出したときに何が起こるかではない
ケビン・

11

2で割ったときの余りが0の場合、数値は偶数です。2で割ったときの余りが1の場合、数値は奇数です。

// Java
public static boolean isOdd(int num){
    return num % 2 != 0;
}

/* C */
int isOdd(int num){
    return num % 2;
}

メソッドは素晴らしいです!


負の奇数のnum%2 == -1のため、Javaメソッドが壊れています。
WMR

あなたが私に反対票を投じたのはそのためですか?
jjnguy 2008年

3
Cの関数では、入力する文字数が入力する文字数よりも多いので、これに反対しました。IE num%Iは、スペースを含む7文字ですIsOdd(I)は8文字です。単に操作を行うよりも長い関数を作成するのはなぜですか?
ケビン

13
私の意見コードの@Kevinは、文字数ではなく、考える+デバッグ時間を含めて、それを書くのにかかる時間によって測定されます。num%2は、isOddよりも1ミリ秒かかります。今度は世界的に数字を追加し、あなたは集合的な年を失った。また、isOddをテストし、検証して、最終的にバグのない認定(たとえば、負の数の処理)を行うことができます。ただし、num%2-一部の開発者は、常に疑問を抱いて実験を行います。良いコードは、あなたが書いていないコードで、再利用してください...ちょうど私の2セントです。
エランメダン

2
@EranMedan、同じロジックがi ++をIncrementByOne(i)で置き換える場合にも適用されます。開発者がnum%2が何をするのか疑問がある場合、私は彼または彼女を私のコードの近くに置きたくありません。
ケビン


7

私はそれを2で割るだけだと思います。残りが0の場合は偶数で、それ以外の場合は奇数です。

係数(%)を使用すると、これが簡単になります。

例えば。4%2 = 0したがって4は偶数5%2 = 1したがって5は奇数


6

問題のもう1つの解決策
(子供は投票できます)

bool isEven(unsigned int x)
{
  unsigned int half1 = 0, half2 = 0;
  while (x)
  {
     if (x) { half1++; x--; }
     if (x) { half2++; x--; }

  }
  return half1 == half2;
}

いいえ、あなたは私が頼りにしたような子供ではありません:)
eugensk

私はこれに賛成するつもりでしたが、負の数では少し遅いです。:)
クリス・ヤング

3
すべての数値は明るくて正です。または、あなたはいくつかに対して偏見を持っていますか?:))
ユーゲンスク2008年

3
コンピュータでは、すべての数値が負になると、最終的に正になります。私たちはそれを幸福のロールオーバーと呼びます(BIGNUMS、YMMYには該当せず、すべての州で有効ではありません)。
Hartung氏、

@WillHartung「幸福のロールオーバー」は素晴らしいです!:D
thejh 2013年

6

私は整数のパリティー(奇数の場合は1、奇数の場合は0)のテーブルを作成します(そのため、ルックアップを行うことができます:D)。しかし、gccでは、そのようなサイズの配列を作成できません。

typedef unsigned int uint;

char parity_uint [UINT_MAX];
char parity_sint_shifted [((uint) INT_MAX) + ((uint) abs (INT_MIN))];
char* parity_sint = parity_sint_shifted - INT_MIN;

void build_parity_tables () {
    char parity = 0;
    unsigned int ui;
    for (ui = 1; ui <= UINT_MAX; ++ui) {
        parity_uint [ui - 1] = parity;
        parity = !parity;
    }
    parity = 0;
    int si;
    for (si = 1; si <= INT_MAX; ++si) {
        parity_sint [si - 1] = parity;
        parity = !parity;
    }
    parity = 1;
    for (si = -1; si >= INT_MIN; --si) {
        parity_sint [si] = parity;
        parity = !parity;
    }
}

char uparity (unsigned int n) {
    if (n == 0) {
        return 0;
    }
    return parity_uint [n - 1];
}

char sparity (int n) {
    if (n == 0) {
        return 0;
    }
    if (n < 0) {
        ++n;
    }
    return parity_sint [n - 1];
}

代わりに、偶数と奇数の数学的定義に代わりましょう。

整数nは、n = 2kのような整数kが存在する場合でも同じです。

n = 2k + 1であるような整数kが存在する場合、整数nは奇数です。

そのコードは次のとおりです。

char even (int n) {
    int k;
    for (k = INT_MIN; k <= INT_MAX; ++k) {
        if (n == 2 * k) {
            return 1;
        }
    }
    return 0;
}

char odd (int n) {
    int k;
    for (k = INT_MIN; k <= INT_MAX; ++k) {
        if (n == 2 * k + 1) {
            return 1;
        }
    }
    return 0;
}

Cの整数intが、特定のCコンパイルでの可能な値を示すとしましょう。(C整数は整数のサブセットであることに注意してください。)

ここで、C整数の特定のnに対して、対応する整数kがC整数内に存在しない可能性があることを心配するかもしれません。しかし、少し証明すれば、すべての整数nに対して| n |であることを示すことができます。<= | 2n | (*)、| n | 「nが正の場合はn、それ以外の場合は-n」です。言い換えると、整数のすべてのnについて、次の少なくとも1つが当てはまります(実際にはケース(1および2)またはケース(3および4)ですが、ここでは証明しません)。

ケース1:n <= 2n。

ケース2:-n <= -2n。

ケース3:-n <= 2n。

ケース4:n <= -2n。

ここで2k = nを取ります。(nが偶数の場合、このようなakは存在しますが、ここでは証明しません。nが偶数でない場合、ループインevenはいずれにしても早く戻ることができないため、問題ありません。)しかし、これは、n <n (*)による0ではなく、すべてのmについて、整数2m = zのzは、mが0でない場合、zがmに等しくないことを意味します。nが0の場合、2 * 0 = 0したがって、0は完了です(n = 0の場合、nは関数のC整数であるevenため、0はC整数です。したがって、k = 0はC整数です)。したがって、nが偶数の場合、C整数のそのようなakはC整数のnに対して存在します。

同様の議論は、nが奇数の場合、n = 2k + 1のようなC整数にkが存在することを示しています。

したがって、ここevenodd紹介する関数は、すべてのC整数に対して適切に機能します。


1
私は攻撃を意味するのではありませんが、この答えの意味は何ですか?i % 2はるかに小さく、おそらくより効率的です。
GManNickG 2010

2
@GMan:しかし、これはもっと確定的です!これにより、すべてのエッジケースが正しく検出されます。
Pダディ

1
...そして(!!!)それは正しいです!!!
Thomas Eding、

冗談を言っているのかどうかわからない。:X %2はすべての整数に対して機能します。
GManNickG 2010

1
+1:「良い答え」と言うつもりでしたが、「興味深い答え」の方が適切だと思います。
James Webster

5
// C#
bool isEven = ((i % 2) == 0);

2
何?それはC#ではありません!それは純粋なCです。:-P
asterite

8
WinFormをその周りに投げて、純粋なC#にします...
Michael Petrotta

@mateusza:あなたがCでいくつかの大文字またはその他で「ブール値」を参照してくださいするとき通常、それはだtypedefか、#defineまたは何か。
David Thornley、2010

2
@mateusza @デビッドソーンリーでC99ブール値は、標準的な特徴である(en.wikipedia.org/wiki/Stdbool.h
FORTRAN

1
非常に冗長な括弧について話します...
Thomas Eding 2012

4

これがJavaの答えです:

public static boolean isEven (Integer Number) {
    Pattern number = Pattern.compile("^.*?(?:[02]|8|(?:6|4))$");
    String num = Number.toString(Number);
    Boolean numbr = new Boolean(number.matcher(num).matches());
    return numbr.booleanValue();
}

4

これを試して: return (((a>>1)<<1) == a)

例:

a     =  10101011
-----------------
a>>1 --> 01010101
a<<1 --> 10101010

b     =  10011100
-----------------
b>>1 --> 01001110
b<<1 --> 10011100

これについて説明していただけますか?私はビット単位の演算子に慣れていません
Abdul

右にシフトしてから左にシフトすると、最後のビットがゼロになります(最も右のビット)。新しい番号が元の番号と同じである場合、これは元の番号の最後のビットが0だったことを意味します。つまり、偶数です。私の更新された答えを見てください。
Kiril Aleksandrov

おかげで、私は今それを手に入れました
Abdul

どちらの方法が速いかわかりません。私はそれらのベンチマークを試みていません。
キリルアレクサンドロフ

これもあなたの最も重要な部分をゼロにしませんか?一部の言語では符号なし整数、ほとんどの言語では負の整数の問題...
Troyseph

4

このかなり面白い議論を読んで、私はメインループ内で奇数と偶数をテストする実際の時間に敏感な関数があることを思い出しました。これは整数のべき関数であり、次のようにStackOverflowの他の場所に投稿されています。ベンチマークは驚くべきものでした。少なくともこの実際の関数でモジュロはより遅く、大幅に遅くなります勝者は、大差で、moduloの時間の67%を必要とし、or(|)アプローチであり、このページの他の場所にはありません。

static dbl  IntPow(dbl st0, int x)  {
    UINT OrMask = UINT_MAX -1;
    dbl  st1=1.0;
    if(0==x) return (dbl)1.0;

    while(1 != x)   {
        if (UINT_MAX == (x|OrMask)) {     //  if LSB is 1...    
        //if(x & 1) {
        //if(x % 2) {
            st1 *= st0;
        }    
        x = x >> 1;  // shift x right 1 bit...  
        st0 *= st0;
    }
    return st1 * st0;
}

3億ループの場合、ベンチマークのタイミングは次のとおりです。

3.962 そしてマスクアプローチ

4.851&アプローチ

5.850%アプローチ

理論、またはアセンブリ言語のリストがこれらのような議論を解決することを考える人にとって、これは注意すべき物語です。天と地、ホレイショには、あなたの哲学で夢に見た以上のものが存在します。


1
の場合は、実装定義の動作をそのまま使用することunsigned xをお勧めします。理由は不明で、タイプも異なります。テストを使用して書き直すのに十分なほど単純です。x = x >> 1;x < 0xOrMaskwhile(x)
chux-モニカを2016年

2
ほとんどのコンパイラは% 2bitwiseを使用してケースをコンパイルするのに十分スマートである必要があるため、これをベンチマークに使用したコンパイラは何でしょうか&。私はこれをテストしましたが、結果はまったく同じです(VS2015、x86とx64の両方のすべての最適化を含むリリースビルド)。受け入れられた回答は、GCCについても述べています(2008年に作成)。
Lou

2
この投稿の問題は、ビットプラットフォームのor方が、andプラットフォームやコンパイラーではありそうもないよりも速いという前提があることです。そのような奇妙なプラットフォームとコンパイラの組み合わせがあったとしても(そして、ベンチマークを実行するために使用されるコードもコードも投稿していない場合)、同じように動作する他のコンパイラに依存することは、最適化策としては不十分です。したがって、私が書いたように、これがどのプラットフォーム/コンパイラでテストされたのかと思います。正確に測定されなかったことがほぼ確実だからです。
ルー、

2
あなたをうそつきとは呼びません。正確に測定しなかったと確信を持って主張します。まだトラックの運転手に電話する必要はありません。元のコメントを読んでください。私ベンチマークを作成しました。予想どおり、3つのケースすべてで結果はまったく同じでした(各テストを500.000で10回実行した後、確実性は約3シグマ)。 .000反復)。本当に輝かしいキャリアを積んでいるのなら、一歩下がって主張が理にかなっていると考えたら、ベンチマークに使用した実際のコードを投稿してください。そうでなければ、投稿は私が信じていることであり、単なる測定の誤りです。
2016年


4

これは彼の回答に関する@RocketRoyとの議論のフォローアップですが、これらの結果を比較したい人にとっては役立つかもしれません。

tl; dr私が見てきたことから、Royのアプローチ((0xFFFFFFFF == (x | 0xFFFFFFFE))はアプローチx & 1として完全に最適化されていませんmodが、実際には、実行時間はすべてのケースで等しくなるはずです。

そこで、まず、コンパイラエクスプローラを使用して、コンパイルされた出力を比較しました。

テストされた機能:

int isOdd_mod(unsigned x) {
    return (x % 2);
}

int isOdd_and(unsigned x) {
    return (x & 1);
}

int isOdd_or(unsigned x) {
    return (0xFFFFFFFF == (x | 0xFFFFFFFE));
}   

CLang 3.9.0と-O3:

isOdd_mod(unsigned int):                          # @isOdd_mod(unsigned int)
        and     edi, 1
        mov     eax, edi
        ret

isOdd_and(unsigned int):                          # @isOdd_and(unsigned int)
        and     edi, 1
        mov     eax, edi
        ret

isOdd_or(unsigned int):                           # @isOdd_or(unsigned int)
        and     edi, 1
        mov     eax, edi
        ret

-O3を使用したGCC 6.2:

isOdd_mod(unsigned int):
        mov     eax, edi
        and     eax, 1
        ret

isOdd_and(unsigned int):
        mov     eax, edi
        and     eax, 1
        ret

isOdd_or(unsigned int):
        or      edi, -2
        xor     eax, eax
        cmp     edi, -1
        sete    al
        ret

CLangに帽子をかぶると、3つのケースすべてが機能的に等しいことがわかりました。ただし、RoyのアプローチはGCCでは最適化されていないため、YMMVです。

Visual Studioと同様です。これらの3つの機能について逆アセンブリリリースx64(VS2015)を調べると、比較部分が「mod」と「and」の場合は等しく、Royの「or」の場合は少し大きいことがわかりました。

// x % 2
test bl,1  
je (some address) 

// x & 1
test bl,1  
je (some address) 

// Roy's bitwise or
mov eax,ebx  
or eax,0FFFFFFFEh  
cmp eax,0FFFFFFFFh  
jne (some address)

ただし、これらの3つのオプション(プレーンmod、ビットごと、またはビットごと)を比較するための実際のベンチマークを実行した後、結果は完全に同じでした(Visual Studio 2005 x86 / x64、リリースビルド、デバッガーは接続されていません)。

リリースアセンブリはとのケースのtest指示を使用しますがandmodロイのケースはcmp eax,0FFFFFFFFhアプローチを使用しますが、展開が大きく最適化されているため、実際に違いはありません。

20回実行した後の結果(i7 3610QM、Windows 10電源プランを高パフォーマンスに設定):

[テスト:プレーンmod 2]平均時間:689.29 ms(相対差分:+ 0.000%)
[テスト:ビット単位または]平均時間:689.63ミリ秒(相対差分:+ 0.048%)
[テスト:ビット単位および]平均時間:687.80 ms(相対差分:-0.217%)

これらのオプションの差は0.3%未満なので、すべてのケースでアセンブリが等しいことは明らかです。

誰かが試したい場合のコードは次のとおりです。ただし、Windowsでのみテストしたことに注意してください(定義の#if LINUX条件を確認し、get_time必要に応じて、この回答から取得して実装しています)。

#include <stdio.h>

#if LINUX
#include <sys/time.h>
#include <sys/resource.h>
double get_time()
{
    struct timeval t;
    struct timezone tzp;
    gettimeofday(&t, &tzp);
    return t.tv_sec + t.tv_usec*1e-6;
}
#else
#include <windows.h>
double get_time()
{
    LARGE_INTEGER t, f;
    QueryPerformanceCounter(&t);
    QueryPerformanceFrequency(&f);
    return (double)t.QuadPart / (double)f.QuadPart * 1000.0;
}
#endif

#define NUM_ITERATIONS (1000 * 1000 * 1000)

// using a macro to avoid function call overhead
#define Benchmark(accumulator, name, operation) { \
    double startTime = get_time(); \
    double dummySum = 0.0, elapsed; \
    int x; \
    for (x = 0; x < NUM_ITERATIONS; x++) { \
        if (operation) dummySum += x; \
    } \
    elapsed = get_time() - startTime; \
    accumulator += elapsed; \
    if (dummySum > 2000) \
        printf("[Test: %-12s] %0.2f ms\r\n", name, elapsed); \
}

void DumpAverage(char *test, double totalTime, double reference)
{
    printf("[Test: %-12s] AVERAGE TIME: %0.2f ms (Relative diff.: %+6.3f%%)\r\n",
        test, totalTime, (totalTime - reference) / reference * 100.0);
}

int main(void)
{
    int repeats = 20;
    double runningTimes[3] = { 0 };
    int k;

    for (k = 0; k < repeats; k++) {
        printf("Run %d of %d...\r\n", k + 1, repeats);
        Benchmark(runningTimes[0], "Plain mod 2", (x % 2));
        Benchmark(runningTimes[1], "Bitwise or", (0xFFFFFFFF == (x | 0xFFFFFFFE)));
        Benchmark(runningTimes[2], "Bitwise and", (x & 1));
    }

    {
        double reference = runningTimes[0] / repeats;
        printf("\r\n");
        DumpAverage("Plain mod 2", runningTimes[0] / repeats, reference);
        DumpAverage("Bitwise or", runningTimes[1] / repeats, reference);
        DumpAverage("Bitwise and", runningTimes[2] / repeats, reference);
    }

    getchar();

    return 0;
}

私はあなたがベンチマークの罪を犯したと信じています。非常に具体的なものを作成しても、実際の環境を表すものではありません。アセンブリ言語を見て、使用しているレジスタの数に注意してください。努力に対する高い評価ですが、これらの結果は実際の処理では維持できません。

@RocketRoy:すべての出力は3つのケースすべてでまったく同じです(まあ、1つのケースではプログラムが少し悪い)ので、レジスターがいくつ使用されたかは気にしません。しかし、繰り返しになりますが、このようなサンプルプログラム/環境を自由に作成して投稿してください。これにより、いずれかの場合にコンパイラがより最適化されたアセンブリを作成するのを混乱させ、他のすべての条件は同じになります。
Lou

私はいつも生意気なプログラマーが好きです。プログラマーにとって良い特性ですが、より複雑な実際のプログラムでは、コンパイラーが問題を解決して命令を(Intelアーキテクチャーで)オーバーラップさせてより良い結果を生成する方法が多いため、私の方法はあなたの方法よりもパフォーマンスが良くなります。 。ベンチマークの経験が豊富なベテランプログラマーは、ベンチマークを好む人はほとんどいませんが、良い仕事を続け、新しいチップのリリースが出たらベンチマークを再実行することを忘れないでください。物事は時間とともに変化します。

3

私はこれが構文糖であり、.netにのみ適用できることを知っていますが、拡張メソッドについてはどうですか...

public static class RudiGroblerExtensions
{
    public static bool IsOdd(this int i)
    {
        return ((i % 2) != 0);
    }
}

今、あなたは次のことができます

int i = 5;
if (i.IsOdd())
{
    // Do something...
}

1
素敵なコード。2は奇数で3は奇数でないと主張するのは残念だ。
アンソニー

おっと、ごめんなさい...私の論理は間違っています...
rudigrobler 2008年

3

「創造的だが紛らわしいカテゴリー」で私は提供します:

int isOdd(int n) { return n ^ n * n ? isOdd(n * n) : n; }

Microsoft C ++に固有のこのテーマのバリアント:

__declspec(naked) bool __fastcall isOdd(const int x)
{
    __asm
    {
        mov eax,ecx
        mul eax
        mul eax
        mul eax
        mul eax
        mul eax
        mul eax
        ret
    }
}

2

ビットごとの方法は、整数の内部表現に依存します。Moduloは、modulo演算子があればどこでも機能します。たとえば、一部のシステムは実際にタグ付けに低レベルのビットを使用しているため(動的言語など)、その場合、生のxおよび1は実際には機能しません。


2

IsOdd(int x){trueを返す; }

正当性の証明-すべての正の整数のセットを検討し、奇数ではない空でない整数のセットがあるとします。正の整数は順序が正しいため、奇数ではない最小の数が存在しますが、それ自体はかなり奇数なので、明らかにその数はセットに含めることができません。したがって、このセットを空にすることはできません。奇数ではなく最大のものを探す以外は、負の整数について繰り返します。


2

ポータブル:

i % 2 ? odd : even;

持ち運び不可:

i & 1 ? odd : even;

i << (BITS_PER_INT - 1) ? odd : even;

2

一部の人々が投稿したように、これを行うには多くの方法があります。このウェブサイトによると、最速の方法はモジュラス演算子です:

if (x % 2 == 0)
               total += 1; //even number
        else
               total -= 1; //odd number

ただし、ここでは、上記の一般的なモジュラス演算よりも実行速度が遅い、作者によってベンチマークされた他のいくつかのコードを示します。

if ((x & 1) == 0)
               total += 1; //even number
        else
               total -= 1; //odd number

System.Math.DivRem((long)x, (long)2, out outvalue);
        if ( outvalue == 0)
               total += 1; //even number
        else
               total -= 1; //odd number

if (((x / 2) * 2) == x)
               total += 1; //even number
        else
               total -= 1; //odd number

if (((x >> 1) << 1) == x)
               total += 1; //even number
        else
               total -= 1; //odd number

        while (index > 1)
               index -= 2;
        if (index == 0)
               total += 1; //even number
        else
               total -= 1; //odd number

tempstr = x.ToString();
        index = tempstr.Length - 1;
        //this assumes base 10
        if (tempstr[index] == '0' || tempstr[index] == '2' || tempstr[index] == '4' || tempstr[index] == '6' || tempstr[index] == '8')
               total += 1; //even number
        else
               total -= 1; //odd number

Math.System.DivRemメソッドを知っている人は何人か、またはなぜそれを使用するのでしょうか?



1

私たちの研究中にブール代数をあまり実行しなかった私たちのためにビットごとの演算子法についてさらに詳しく説明するために、ここに説明があります。おそらくOPにはあまり役に立ちませんが、NUMBER&1が機能する理由を明確にしたいと思いました。

上で誰かが答えたように、負の数が表現される方法はこの方法が機能しなくなる可能性があることに注意してください。実際、各言語は負のオペランドの扱い方が異なる場合があるため、モジュロ演算子法も破ることができます。

ただし、NUMBERが常に正であることがわかっている場合、これはうまく機能します。

上記のTooonyが指摘したように、重要なのはバイナリ(および拒否)の最後の桁のみです。

ブール論理ANDゲートは、1が返されるためには両方の入力が1(または高電圧)でなければならないことを指示します。

1&0 = 0。

0&1 = 0。

0&0 = 0。

1&1 = 1。

バイナリとして数値を表す場合(ここでは8ビット表現を使用しました)、奇数の最後には1があり、偶数には0があります。

例えば:

1 = 00000001

2 = 00000010

3 = 00000011

4 = 00000100

任意の数値を取り、ビットごとのAND(Javaでは&)を使用すると、1で00000001、= 1のいずれかが返され、数値が奇数であることを意味します。または00000000 = 0は、数値が偶数であることを意味します。

例えば

変ですか?

1&1 =

00000001&

00000001 =

00000001 <—奇数

2&1 =

00000010&

00000001 =

00000000 <—偶数

54&1 =

00000001&

00110110 =

00000000 <—偶数

これがこれが機能する理由です:

if(number & 1){

   //Number is odd

} else {

   //Number is even
}

これが冗長な場合は申し訳ありません。


1

ゼロパリティ| ゼロhttp://tinyurl.com/oexhr3k

Pythonコードシーケンス。

# defining function for number parity check
def parity(number):
    """Parity check function"""
    # if number is 0 (zero) return 'Zero neither ODD nor EVEN',
    # otherwise number&1, checking last bit, if 0, then EVEN, 
    # if 1, then ODD.
    return (number == 0 and 'Zero neither ODD nor EVEN') \
            or (number&1 and 'ODD' or 'EVEN')

# cycle trough numbers from 0 to 13 
for number in range(0, 14):
    print "{0:>4} : {0:08b} : {1:}".format(number, parity(number))

出力:

   0 : 00000000 : Zero neither ODD nor EVEN
   1 : 00000001 : ODD
   2 : 00000010 : EVEN
   3 : 00000011 : ODD
   4 : 00000100 : EVEN
   5 : 00000101 : ODD
   6 : 00000110 : EVEN
   7 : 00000111 : ODD
   8 : 00001000 : EVEN
   9 : 00001001 : ODD
  10 : 00001010 : EVEN
  11 : 00001011 : ODD
  12 : 00001100 : EVEN
  13 : 00001101 : ODD

@ el.pescado、ありがとう。ゼロが偶数の場合、ペアはいくつありますか?

@ el.pescado、OK、私はあなたに同意します。では、少し考えてみれば、なぜ2に割り切れるのでしょうか。2つに分割するときに知りたいことは何ですか?3、5、などに割り切らないのはなぜですか?

@ el.pescadoこのウィキペディアの記事「ゼロのパリティ」は間違っています。多くの人がこの記事にだまされました。ウィンクの前に考えます。

1
あなたが正しい。他の回答を読んだので、あなたの回答が最も包括的であると思いました:)
el.pescado

@ el.pescado。ありがとうございました。:)今、あなたはゼロの親友です。(抱擁)

1
I execute this code for ODD & EVEN:

#include <stdio.h>
int main()
{
    int number;
    printf("Enter an integer: ");
    scanf("%d", &number);

    if(number % 2 == 0)
        printf("%d is even.", number);
    else
        printf("%d is odd.", number);
}

0

議論のために...

あなたはそれが偶数であるか奇数であるかを確認するために与えられた数の最後の数字を見る必要があるだけです。署名済み、署名なし、ポジティブ、ネガティブ-これに関してはすべて同じです。だからこれはすべてのラウンドで動作するはずです:-

void tellMeIfItIsAnOddNumberPlease(int iToTest){
  int iLastDigit;
  iLastDigit = iToTest - (iToTest / 10 * 10);
  if (iLastDigit % 2 == 0){
    printf("The number %d is even!\n", iToTest);
  } else {
    printf("The number %d is odd!\n", iToTest);
  }
}

ここで重要なのはコードの3行目です。除算演算子は整数除算を実行するため、結果の小数部分が欠落しています。したがって、たとえば222/10は結果として22になります。次に、10を再度掛けると、220になります。元の222からそれを引くと、最終的に2になります。これは、元の番号の最後の数字と同じ数です。;-)括弧は、計算が行われた順序を思い出させるためにあります。最初に除算と乗算を行ってから、元の数値から結果を減算します。除算よりも除算や乗算の方が優先度が高いため、省略してもかまいませんが、これにより「読みやすく」なるコードが得られます。

必要に応じて、すべてを完全に読み取り不可能にすることができます。それは現代のコンパイラーにはまったく違いがありません:-

printf("%d%s\n",iToTest,0==(iToTest-iToTest/10*10)%2?" is even":" is odd");

しかし、それはコードを将来的に維持することをより困難にするでしょう。奇数のテキストを「等しくない」に変更するとします。次に、後で他の誰かがあなたが行った変更を見つけて、svn diffまたは同様のものを実行したいと考えています...

移植性については心配せず、速度について心配している場合は、最下位ビットを確認できます。そのビットが1に設定されている場合は奇数、0の場合は偶数です。Intelのx86アーキテクチャのようなリトルエンディアンシステムでは、次のようになります。-

if (iToTest & 1) {
  // Even
} else {
  // Odd
}

ちょうどiToTest%2 == 0にした場合の正確な問題は何ですか?あなたは最後の数字を抽出する除算を浪費しているので、あなたのそれは必要な2倍遅いです。
空き領域08/10/03

@freespace:私はそれ以上を無駄にしますね。:-)乗算と減算も。しかし、私が敢えて言わない2つのソリューションの中で最も効率的なものは何ですか。これが最速の解決策であると主張したことはありません。私の投稿の最初の行をもう一度読んだ場合は、まったく逆になります。
2008年

@Tooony、ああ、私のユーモアの帽子が落ちた。それは正式に戻ってきました:Dそれについて申し訳ありません:)
freespace

0

あなたが効率的になりたい場合は、使用のビット演算子(x & 1)、しかし、あなたは読めるの使用法2(になりたい場合x % 2


-1:効率を高めたい場合は、どちらかを使用します。ポータブルにしたい場合は、を使用してください%。読みやすくしたい場合は、を使用してください%。うーん、ここに柄が見えます。
トーマス・エディング

@trinithis、パターンはなく、このソリューションはあなたのものよりはるかに優れています。
潜水

0

偶数または奇数のチェックは簡単な作業です。

2で割り切れる数は偶数であり、それ以外は奇数であることがわかっています。

任意の数の可分性をチェックするだけでよく、可算性をチェックするために%演算子を使用します

ifを使用して奇数をチェックする

if(num%2 ==0)  
{
    printf("Even");
}
else
{
    printf("Odd");
}

他の場合に使用して偶数または奇数をチェックするCプログラム

条件付き/三項演算子の使用

(num%2 ==0) printf("Even") : printf("Odd");

条件演算子を使用して偶数または奇数をチェックするCプログラム

ビット演算子の使用

if(num & 1)  
{
    printf("Odd");
}
else 
{
    printf("Even");
}

そして、正確に三項演算子はどこですか?
Beyondo 2018

0

+ 66%高速>!(i%2) / i%2 == 0

int isOdd(int n)
{
    return n & 1;
}

1の場合、コードは整数の最後のビットをチェックしますバイナリで

説明

Binary  :   Decimal
-------------------
0000    =   0
0001    =   1
0010    =   2
0011    =   3
0100    =   4
0101    =   5
0110    =   6
0111    =   7
1000    =   8
1001    =   9
and so on...

注意してください右端のビットは常に1である奇数の番号。

ビット単位のAND演算子をチェックし、私たちの右端のビットのリターンラインは、それが1だ場合

それを真と偽と考えてください

n1と比較すると0001、2進数であることを意味します(ゼロの数は関係ありません)。
次に、整数nがあると想像してみましょう、サイズが1バイトのとします。

それは、8ビット/ 8進数で表されます。

int n7であり、それを1と比較すると、

7 (1-byte int)|    0  0  0  0    0  1  1  1
       &
1 (1-byte int)|    0  0  0  0    0  0  0  1
********************************************
Result        |    F  F  F  F    F  F  F  T

これはFが虚偽との略T真のために。

これは、比較し、彼らは両方とも真ならのみ右端のビットを。つまり、自動的7 & 1T rueです。

一番右側のビットを確認したい場合はどうすればよいですか?

2が表すものに変更n & 1するだけですn & 20010バイナリにしてそうで。

ビット演算の初心者の場合は、16進表記を使用することをお勧めします
return n & 1;>> return n & 0x01;

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.