アプリ版:「スタンプのみでお礼する」機能のリリースについて

最大値と最小値の間を循環する変数

最大値と最小値(ゼロ)の間を循環する変数counterを考えています。
以下が私が考えたコードです。

if (plus) {
counter++;
if (counter > MAX)
counter = MIN;
} else if (minus) {
counter--;
if (counter < MIN)
counter = MAX;
} else {
;
}

これで一応動くのですが、いかにもダサイので、もっと上手い方法が無いかと悩んでいます。
例えば、counter %= (MAX + 1) とでもすれば、加算の場合は上手くいく(?)のですが、減算の場合は上手くいきません。
何か良い方法は無いでしょうか。

A 回答 (6件)

MIN≦counter≦MAXで循環させるのに、Xで割った余りを使いたいのなら、 0~X-1の範囲になるように変形する必要があります。



全辺から MINを引くと
0≦counter-MIN≦MAX-MIN
なので、 counter - MIN を MAX-MIN +1で割った余りを使うことになります。
引いたMINは改めて足せば元の範囲になります。

加算
counter = MIN + ( ( counter - MIN ) +1 ) % (MAX - MIN + 1) ;

減算:負の%演算はややこしいので、1周期分加えて正の値にする
counter = MIN + ( ( counter - MIN ) - 1 + (MAX - MIN + 1)) % (MAX - MIN + 1) ;


自分で書いといてなんですが、正直、わかりずらいです。
それに、整数演算の中では、割り算はもっとも時間のかかるものです。その意味ではこの方法は効率的とは言えません。
値の変化が任意(+50とか*15とかする)なら、割り算を使うのが効果的かもしれませんが。

私が作るなら、この質問にあるようなif文を使うか、三項演算子を使うか、ですね。

加算
counter = (counter == MAX) ? MIN : (counter + 1) ;
減算
counter = (counter == MIN) ? MAX : (counter - 1) ;
    • good
    • 0
この回答へのお礼

御回答ありがとうございます。

なるほど、三項演算子という手段がありましたか。
これが総合的に見て一番優れている気がします。
割り算を使用する方法も、適用するかどうかは別として、自力で考えつく位にはなりたいものです。

お礼日時:2010/10/27 13:20

とりあえず、最後のelseは不要ですよね。


それと、plus と minus はそれぞれ個別でbool定義されて
いますが、それは必須でしょうか? 無駄なような気が……?

既に色々な手法が提案されていますので、自分は「その他案」を。
例えばint型配列にて{ 1, -1} を定義すれば、以下の形が可能です。
c が 0 ならインクリメント、1 ならデクリメントされるという事ですね。

counter += tbl[c];
if (counter < MIN) counter = MAX;
if (counter > MAX) counter = MIN;

判り易いので自分はこんな風に書く時もあるのですが、これを
人にオススメしていいのかは判りません……(^^;
    • good
    • 0
この回答へのお礼

御回答ありがとうございます。

質問の本筋以外は、例を示す為に適当に書いたものなので、深く突っ込まないで頂けるとありがたいです。
この方法も面白いですね。
ややトリッキーな感じなので、個人で書くプログラム以外では使用しづらいですが、知識として蓄えておきます。

お礼日時:2010/10/27 13:26

FIFO(循環バッファ)のようなものであれば



バッファの大きさを2の階乗にすると

char buffer[256];
unsigned char read_p, write_p;

//書き込み
buffer[write_p++] = data;

//読み込み
if (read_p != write_p)
 data = buffer[read_p++];

と書けます。バッファが128バイトであれば

char buffer[2^7];
unsigned int read_p, write_p;

//書き込み
buffer[write_p++] = data;
write_p &= (sizeof(buffer) - 1);

//読み込み
if (read_p != write_p) {
 data = buffer[read_p++];
 read_p &= (sizeof(buffer) - 1);
}

となり、if文が省略できて高速です。

またCPUによっては、バッファのサイズが256でもインデックスをunsigned intにして128と同様に記述した方が速い場合があります。

バッファの定義をアセンブラで記述して、アライメントを2の階乗に揃えた場合、インデックスではなくてポインターが使用できるのでより高速になります。
    • good
    • 0
この回答へのお礼

御回答ありがとうございます。
想定した回答よりも随分高度なものですが、参考にさせて頂きます。

お礼日時:2010/10/27 13:15

正直なところ, 今のコードのままでいいんじゃないの? 無駄に凝るよりシンプルでいいと思うんだけどなぁ.... まあ「全ての実行パスで所要クロック数を統一したい」というならそれはそれでいいけど, かえって面倒な感じしかしない.


ちなみに「MAX 以上 MIN 以下の間を動く」んだったら, counter %= MAX+1; じゃダメだよね.
    • good
    • 0
この回答へのお礼

御回答ありがとうございます。

確かに、実際の現場では、わかりやすさを優先してこのように書くかもしれません。
ただ、知っているのと知らないのとでは大違いなので、質問自体は意義があると思いたです。

お礼日時:2010/10/27 13:12

plus


minus
MAX
MIN

の意味がわかりませんので、一応動くといわれましても
にわかに信じがたいです。

この回答への補足

御回答ありがとうございます。
質問とは直接関係ない部分だと思ったので、質問をシンプルにするつもりで省略してしまいました。

plus・minusには特に意味はなく、単に真になったらインクリメントもしくはデクリメントするといった程度の意味です。

MINとMAXは最小値と最大値で、counterを0~9の間で循環させたいなら、MINは0でMAXは9になります。
適当なところでdefineされているイメージです。

以上、捕捉になっているでしょうか。

補足日時:2010/10/26 00:41
    • good
    • 0

増やす場合…


counter = (counter + 1) % MAX;
減らす場合…
counter = (counter + (MAX - 1)) % MAX;
ってコトですか?
    • good
    • 0
この回答へのお礼

御回答ありがとうございます。

この方法ならば、大分すっきり書けます。
実際のcounterの最大値は(MAX-1)になるのですよね?
ただし、それはどうとでも対処できそうです。

お礼日時:2010/10/26 00:34

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!