web-dev-qa-db-ja.com

負の数の奇妙なObjective-C Modの動作

だから私は、modedが正の空間に置かれるべきであるとき、負の数を考えました...これをObjective-Cで発生させることはできません

私はこれを期待します:

-1 % 3 = 2
 0 % 3 = 0
 1 % 3 = 1
 2 % 3 = 2

しかし、これを入手

-1 % 3 = -1
 0 % 3 = 0
 1 % 3 = 1
 2 % 3 = 2

これはなぜですか、回避策はありますか?

42
coneybeare
result = n % 3;
if( result < 0 ) result += 3;

他の回答で提案されているように、追加のmod操作を実行しないでください。それらは非常に高価で不必要です。

53
UncleO

CおよびObjective-Cでは、除算演算子と係数演算子はゼロに向かって切り捨てを実行します。 _a / b_は、_a / b > 0_の場合はfloor(a / b)です。それ以外の場合は、_a / b < 0_の場合はceiling(a / b)です。もちろんbが0でない限り、常にa == (a / b) * b + (a % b)が当てはまります。結果として、_positive % positive == positive_、_positive % negative == positive_、_negative % positive == negative_、および_negative % negative == negative_(少しトリッキーですが、4つのケースすべてのロジックを計算できます)。

14
Adam Rosenfield

Nの範囲が制限されている場合、最小値の絶対値よりも大きい既知の3の定数倍を追加するだけで、必要な結果を得ることができます。

たとえば、nが-1000..2000に制限されている場合は、次の式を使用できます。

result = (n+1002) % 3;

最大値と定数が加算されたときにオーバーフローしないことを確認してください。

8
Peter N Lewis

言語の問題があります:

 math-er-says:この数値とその数値を加算したmod other-number 
 code-er-hears:2つの数値を加算し、結果をother-number [.____。で割ります。 ] code-er-says:負の数はどうですか?
 math-er-says:WHAT?フィールドmod other-numberには負の数の概念はありませんか?
 code-er-says:field what? ... 
  • この会話の数学者は、円形の数直線で数学をすることについて話している。下から差し引くと、上に折り返されます。
  • コード担当者は、剰余を計算する演算子について話している。

この場合、数学者のmod演算子が必要で、残りの関数は自由に使用できます。減算を行うたびに底から落ちたかどうかを確認することで、剰余演算子を数学者のmod演算子に変換できます。

7
Arthur Ulfeldt

私は正の数も期待していましたが、ISO/IEC 14882:2003からこれを見つけました:プログラミング言語-C++、5.6.4(モジュラス演算に関する Wikipediaの記事にあります ):

バイナリ%演算子は、最初の式を2番目の式で除算した余りを生成します。 ....両方のオペランドが負でない場合、残りは負ではありません。そうでない場合、残りの符号は実装定義です

4
e.James

これが振る舞いであり、振る舞うことがわかっている場合は、_m % n = r_の場合は_r = n + r_を使用します。ここで何が起こるかわからない場合は、_r = r % n_を使用してください。

編集:要約するには、r = ( n + ( m % n ) ) % nを使用します

4
maxwellb

JavaScriptもこれを行います。私はこれに2、3回捕まえられました。それは継続ではなく、ゼロの周りの反射と考えてください。

1
Nosredna

UncleOの答えはおそらくより堅牢ですが、1行で実行する場合、負の値がmodの1回の反復よりもmore negativeにならないことが確実な場合(たとえば、常に最大でmod値を減算するだけです)、単一の式に単純化できます。

int result = (n + 3) % 3;

とにかくmodを実行しているので、初期値に3を追加しても効果はありませんnless nが負(ただし-3以上)の場合、結果は期待される正の係数になります。

1
devios1

理由:C規格でmod演算子が指定されている方法だからです(Objective-CはCの拡張であることを思い出してください)。それは意外であり、あなたはそれを覚えておく必要があるため、私が知っているほとんどの人(私のように)を混乱させます。

回避策については、私はuncleoを使用します。

1
Tobias

Javaスクリプトだけでなく、ほとんどすべての言語で間違った答えが表示されます」conneybeareの発言は正しいです。モードがあると、残りを取得する必要があります。正の整数でなければなりません...

数直線を確認すると分かります

私もVBで同じ問題に直面しており、結果が負であるかどうかのように追加のチェックを強制的に追加する必要がありました。結果に除数を追加する必要があります。

0
Anish Chandran

残りには2つの選択肢があり、記号は言語によって異なります。 ANSI Cは、配当の符号を選択​​します。これが、Objective-Cもそうしている理由だと思います。 ウィキペディアのエントリも参照してください

0
user122376

_a%b_の代わりに

使用:a-b*floor((float)a/(float)b)

剰余を期待し、moduloを使用しています。数学ではそれらは同じものであり、Cでは異なります。 GNU-CにはRem()とMod()があり、objective-cにはmod()しかないので、上記のコードを使用してrem関数をシミュレートする必要があります(数学の世界ではmodと同じですが、プログラミングでは違います)世界[少なくともほとんどの言語の場合])


また、このために使いやすいマクロを定義できることに注意してください。

#define rem(a,b) ((int)(a-b*floor((float)a/(float)b)))

次に、コードでrem(-1,3)を使用するだけで問題なく動作します。

0
Albert Renshaw