web-dev-qa-db-ja.com

数値が10の倍数であるか、特定の範囲内にあるかを判断する

プログラムで必要なループがいくつかあります。擬似コードを書き出すことはできますが、論理的にどのように書くかは完全にはわかりません。

私は欲しい -

_if (num is a multiple of 10) { do this }

if (num is within 11-20, 31-40, 51-60, 71-80, 91-100) { do this }
else { do this } //this part is for 1-10, 21-30, 41-50, 61-70, 81-90
_

これは、私の質問にもっと意味があれば、ヘビとはしごのボードゲーム用です。

モジュラスを使用する必要がある最初のifステートメントを想像すると、if (num == 100%10)は正しいでしょうか?

二つ目は私にはわからない。 if (num > 10 && num is < 21 || etc)のように記述できますが、それよりももっとスマートなものが必要です。

104
user3419168

最初の例では、数値が使用の倍数であるかどうかを確認します。

if (num % 10 == 0) // its divisible by 10

2番目の場合:

if(((num - 1) / 10) % 2 == 1 && num <= 100)

しかし、それはかなり高密度です。オプションを明示的にリストするだけの方が良いかもしれません。


   int getRow(int num) {
      return (num - 1) / 10;   
   }

   if (getRow(num) % 2 == 0) {
   }

同じロジックですが、関数を使用することで、その意味がより明確になります。

86
Winston Ewert

if(numは10の倍数){これを行う}

if (num % 10 == 0) {
  // Do something
}

if(numは11-20、31-40、51-60、71-80、91-100の範囲内){これを行う}

ここでのコツは、範囲間のある種の共通性を探すことです。もちろん、常に「ブルートフォース」方式を使用できます:

if ((num > 10 && num <= 20) ||
    (num > 30 && num <= 40) ||
    (num > 50 && num <= 60) ||
    (num > 70 && num <= 80) ||
    (num > 90 && num <= 100)) {
  // Do something
}

しかし、あなたは、numから1を引くと、範囲があることに気付くかもしれません:

10-19, 30-39, 50-59, 70-79, 90-99

つまり、最初の桁が奇数であるすべての2桁の数字。次に、これを表現する式を考え出す必要があります。 10で除算することで最初の桁を取得でき、2で除算するときに1の剰余をチェックすることで奇数であることをテストできます。すべてをまとめると:

if ((num > 0) && (num <= 100) && (((num - 1) / 10) % 2 == 1)) {
  // Do something
}

長いが保守可能なコードと短い「賢い」コードの間のトレードオフを考えると、私は毎回より長く明確に選ぶでしょう。少なくとも、賢くしようとするなら、あなたが達成しようとしていることを正確に説明するコメントを含めてください。

コードで作業する次の開発者が武装しており、どこに住んでいるかを知っていると想定すると役立ちます。 :-)

40
Adam Liss

GCCまたは Case Ranges をサポートするコンパイラを使用している場合、これを行うことができますが、コードはポータブルではありません

switch(num)
{
case 11 ... 20:
case 31 ... 40:
case 51 ... 60:
case 71 ... 80:
case 91 ... 100:
    // do something
    break;
default:
    // do something else
    break;
}
30
Bryan Chen

これは初心者よりも将来の訪問者向けです。より一般的なアルゴリズムのような解決策として、開始値と終了値のリストを取得し、渡された値がそれらのいずれかに含まれているかどうかを確認できます。

template<typename It, typename Elem>
bool in_any_interval(It first, It last, const Elem &val) {
    return std::any_of(first, last, [&val](const auto &p) {
        return p.first <= val && val <= p.second;
    });
}

簡単にするために、明示的なpair引数の代わりにポリモーフィックラムダ(C++ 14)を使用しました。これはおそらく<および==は標準アルゴリズムと一貫性がありますが、Elem<=に定義されています。とにかく、次のように使用できます。

std::pair<int, int> intervals[]{
    {11, 20}, {31, 40}, {51, 60}, {71, 80}, {91, 100}
};

const int num = 15;
std::cout << in_any_interval(std::begin(intervals), std::end(intervals), num);

実例があります here

15
chris

コードにいくつかの良いコメントがあれば、非常に簡潔かつ読みやすく書けます。

// Check if it's a multiple of 10
if (num % 10 == 0) { ... }

// Check for whether tens digit is zero or even (1-10, 21-30, ...)
if ((num / 10) % 2 == 0) { ... }
else { ... }
5
La-comadreja

最初の方法は簡単です。モジュロ演算子をnum値に適用するだけです。

if ( ( num % 10 ) == 0)

SInce c ++は0以外のすべての数値をtrueとして評価していますが、次のように書くこともできます。

if ( ! ( num % 10 ) )  //does not have a residue when devided by 10

2番目の場合、これは理解しやすいと思います。

パターンは20ごとに繰り返されるため、20を法として計算できます。20で割り切れる要素を除き、必要なすべての要素が1行になります。

これらも取得するには、負の数を処理しないように、num-1以上のnum + 19を使用します。

if ( ( ( num + 19 ) % 20 ) > 9 )

これは、パターンが永久に繰り返されることを前提としているため、111-120の場合は再び適用されます。それ以外の場合は、数値を100に制限する必要があります。

if ( ( ( ( num + 19 ) % 20 ) > 9 ) && ( num <= 100 ) )
5
kasimir

基本的には自分で答えを説明しましたが、念のためコードを示します。

if((x % 10) == 0) {
  //do this
}
if((x > 10 && x < 21) || (x > 30 && x < 41) || (x > 50 && x < 61) || (x > 70 && x < 81) || (x > 90 && x < 101)) {
  //do this
}
4
Henry Harris

あなたはこれを考え過ぎているかもしれません。

_if (x % 10)
{
   .. code for 1..9 ..
} else
{
   .. code for 0, 10, 20 etc.
}
_

最初の行if (x % 10)は、(a)10の倍数である値が「0」として計算され、他の数値は残りのままになるため、(b)ifの値0 falseと見なされ、他の値はtrueです。

編集:

20代で前後に切り替えるには、同じトリックを使用します。今回は、ピボット番号は_10_です。

_if (((x-1)/10) & 1)
{
  .. code for 10, 30, ..
} else
{
   .. code for 20, 40, etc.
}
_

_x/10_は、0から9までの任意の数を_0_として、10から19までを_1_などとして返します。偶数または奇数(_& 1_)でテストすると、偶数か奇数かがわかります。実際の範囲は「11〜20」なので、テストする前に1を引きます。

3
usr2564301

最初の場合:

if (x % 10 == 0)

適用対象:

10, 20, 30, .. 100 .. 1000 ...

2番目の場合:

if (((x-1) / 10) % 2 == 1)

に適用されます:

11-20, 31-40, 51-60, ..

基本的に、最初にx-1を実行して以下を取得します。

10-19, 30-39, 50-59, ..

次に、それらを10で除算して取得します。

1, 3, 5, ..

したがって、この結果が奇数であるかどうかを確認します。

1
Khaled.K

読みやすさを求める

すでにいくつかの良い答えがありますが、将来の読者がコードを読みやすくするプログラミング手法をお勧めします。6か月以内に、同僚がコードレビューの実行を依頼し、後継者になります。 。

これは、「巧妙な」ステートメントを、その名前で正確に実行していることを示す関数にラップすることです。パフォーマンスへの影響はごくわずかですが(「関数呼び出しのオーバーヘッド」から)、これはこのようなゲーム状況では本当に無視できます。

途中で入力をサニタイズできます-たとえば、「不正な」値をテストします。したがって、あなたはこのようなコードで終わるかもしれません-それがどれほど読みやすいか見てください? 「ヘルパー関数」はどこかに隠しておくことができます(メインモジュールにある必要はありません。名前から明らかなことです)。

#include <stdio.h>

enum {NO, YES, WINNER};
enum {OUT_OF_RANGE=-1, ODD, EVEN};

int notInRange(int square) {
  return(square < 1 || square > 100)?YES:NO;
}

int isEndOfRow(int square) {
  if (notInRange(square)) return OUT_OF_RANGE;
  if (square == 100) return WINNER; // I am making this up...
  return (square % 10 == 0)? YES:NO;
}

int rowType(unsigned int square) {
  // return 1 if square is in odd row (going to the right)
  // and 0 if square is in even row (going to the left)
  if (notInRange(square)) return OUT_OF_RANGE; // trap this error
  int rowNum = (square - 1) / 10;
  return (rowNum % 2 == 0) ? ODD:EVEN; // return 0 (ODD) for 1-10, 21-30 etc.
                                       // and 1 (EVEN) for 11-20, 31-40, ...
}

int main(void) {
  int a = 12;
  int rt;
  rt = rowType(a); // this replaces your obscure if statement

  // and here is how you handle the possible return values:
  switch(rt) {
  case ODD:
    printf("It is an odd row\n");
    break;
  case EVEN:
    printf("It is an even row\n");
    break;
  case OUT_OF_RANGE:
    printf("It is out of range\n");
    break;
  default:
    printf("Unexpected return value from rowType!\n");
  }

  if(isEndOfRow(10)==YES) printf("10 is at the end of a row\n");
  if(isEndOfRow(100)==WINNER) printf("We have a winner!\n");
}
1
Floris

以下を試すことができます:

        // multiple of 10
        if ((num % 10) == 0)
        {
           // Do something
        }
        else if (((num / 10) % 2) != 0)
        {
            //11-20, 31-40, 51-60, 71-80, 91-100
        }
         else
        {
            //other case
        }
1
ShalakaV

他の人が指摘しているように、条件をより簡潔にすることはコンパイルや実行の速度を上げることにはならず、読みやすさにも必ずしも役立ちません。

後で6 x 6ボードの幼児向けゲームや40 xの上級バージョン(一晩中プレイできるゲーム)が必要だと判断した場合に備えて、プログラムの柔軟性を高めるのに役立ちます。 50ボード。

したがって、次のようにコーディングします。

// What is the size of the game board?
#define ROWS            10
#define COLUMNS         10

// The numbers of the squares go from 1 (bottom-left) to (ROWS * COLUMNS)
// (top-left if ROWS is even, or top-right if ROWS is odd)
#define firstSquare     1
#define lastSquare      (ROWS * COLUMNS)
// We haven't started until we roll the die and move onto the first square,
// so there is an imaginary 'square zero'
#define notStarted(num) (num == 0)
// and we only win when we land exactly on the last square
#define finished(num)   (num == lastSquare)
#define overShot(num)   (num > lastSquare)

// We will number our rows from 1 to ROWS, and our columns from 1 to COLUMNS
// (apologies to C fanatics who believe the world should be zero-based, which would
//  have simplified these expressions)
#define getRow(num)   (((num - 1) / COLUMNS) + 1)
#define getCol(num)   (((num - 1) % COLUMNS) + 1)

// What direction are we moving in?
// On rows 1, 3, 5, etc. we go from left to right
#define isLeftToRightRow(num)    ((getRow(num) % 2) == 1)
// On rows 2, 4, 6, etc. we go from right to left
#define isRightToLeftRow(num)    ((getRow(num) % 2) == 0)

// Are we on the last square in the row?
#define isLastInRow(num)    (getCol(num) == COLUMNS)

// And finally we can get onto the code

if (notStarted(mySquare))
{
  // Some code for when we haven't got our piece on the board yet
}
else
{
  if (isLastInRow(mySquare))
  {
    // Some code for when we're on the last square in a row
  }


  if (isRightToLeftRow(mySquare))
  {
    // Some code for when we're travelling from right to left
  }
  else
  {
    // Some code for when we're travelling from left to right
  }
}

はい、それは冗長ですが、ゲームボードで何が起こっているかを正確に明確にします。

携帯電話またはタブレットで表示するこのゲームを開発している場合、定数の代わりにROWSおよびCOLUMNS変数を作成して、画面サイズと方向に合わせて(ゲームの開始時に)動的に設定できるようにします。また、ゲームの途中で画面の向きをいつでも変更できるようにします-必要なのは、ROWSとCOLUMNSの値を切り替えながら、他のすべて(各プレーヤーがオンになっている現在の平方数、すべての蛇と梯子の開始/終了の正方形)は変更されていません。次に、ボードをきれいに描画し、アニメーションのコードを記述する必要があります(それがifステートメントの目的だったと思います)...

0

この質問にはたくさんの答えがあることはわかっていますが、とにかくここに投げます... Steve McConnellのCode Complete 2nd Editionから抜粋:「階段アクセステーブル:
さらに別の種類のテーブルアクセスは、階段状の方法です。このアクセス方法は、インデックス構造ほど直接的ではありませんが、データ領域を無駄にしません。図18-5に示されている階段構造の一般的な考え方は、テーブル内のエントリが個別のデータポイントではなくデータの範囲に対して有効であることです。 enter image description here

図18-5階段状アプローチは、「階段」に到達するレベルを決定することにより、各エントリを分類します。ヒットする「ステップ」がそのカテゴリを決定します。

たとえば、採点プログラムを作成している場合、「B」の入力範囲は75パーセントから90パーセントです。いつかプログラムしなければならないグレードの範囲は次のとおりです。 enter image description here

階段状の方法を使用するには、各範囲の上端をテーブルに入れてから、ループを記述して、各範囲の上端に対してスコアをチェックします。スコアが最初に範囲の上限を超えるポイントを見つけると、成績がわかります。階段状の手法では、範囲のエンドポイントを適切に処理するように注意する必要があります。この例に基づいて生徒のグループに評点を割り当てるVisual Basicのコードは次のとおりです。

enter image description here

これは簡単な例ですが、簡単に一般化して、複数の学生、複数の採点スキーム(たとえば、異なる割り当ての異なるポイントレベルの異なるグレード)、および採点スキームの変更を処理できます。

Code Complete 2nd Edition pages 426-428(Chapter 18)。これがお役に立てば幸いです。c++でコードを変換しなかったのでごめんなさい。しかし、あなたはその古い中国のsaying言を知っています。 :)

0
lauCosma