229

ループするように整数を変更して配列位置を取得しようとしています。正i % arrayLengthの数の場合は問題なく動作しますが、負の数の場合はすべてうまくいきません。

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

だから私はの実装が必要です

int GetArrayIndex(int i, int arrayLength)

そのような

GetArrayIndex( 4, 3) == 1
GetArrayIndex( 3, 3) == 0
GetArrayIndex( 2, 3) == 2
GetArrayIndex( 1, 3) == 1
GetArrayIndex( 0, 3) == 0
GetArrayIndex(-1, 3) == 2
GetArrayIndex(-2, 3) == 1
GetArrayIndex(-3, 3) == 0
GetArrayIndex(-4, 3) == 2

私は前にこれをやったことがありますが、何らかの理由で今日は私の脳が溶けています:(

4

14 に答える 14

333

私は常に自分のmod関数を使用します。

int mod(int x, int m) {
    return (x%m + m)%m;
}

もちろん、モジュラス演算を2回呼び出す必要がある場合は、次のように記述できます。

int mod(int x, int m) {
    int r = x%m;
    return r<0 ? r+m : r;
}

またはその変形。

それが機能する理由は、「x%m」が常に[-m + 1、m-1]の範囲にあるためです。したがって、負の値である場合は、mを加算すると、mを法として値を変更せずに正の範囲になります。

于 2009-07-04T20:35:50.110 に答える
98

C# と C++ の % 演算子は実際にはモジュロではなく、剰余であることに注意してください。あなたの場合、必要なモジュロの式は次のとおりです。

float nfmod(float a,float b)
{
    return a - b * floor(a / b);
}

これを C# (または C++) で再コーディングする必要がありますが、これが剰余ではなくモジュロを取得する方法です。

于 2011-06-19T04:07:56.347 に答える
21

一度だけ使用する単一行の実装%:

int mod(int k, int n) {  return ((k %= n) < 0) ? k+n : k;  }
于 2014-04-22T08:27:50.500 に答える
4

モジュラス(arrayLength)を%の負の結果に追加するだけで、問題はありません。

于 2009-07-04T20:31:52.147 に答える
3

このスレッドで Peter N Lewis が提示したトリックが気に入っています。最小。"

したがって、度単位の値dがあり、取得したい場合

d % 180f

dが負の場合の問題を回避したい場合は、代わりに次のようにします。

(d + 720f) % 180f

これは、dが負になる可能性がありますが、-720 よりも負になることは決してないことがわかっていることを前提としています。

于 2013-04-15T19:12:25.617 に答える
3

いくつかの理解を追加します。

ユークリッドの定義により、mod の結果は常に正でなければなりません。

元:

 int n = 5;
 int x = -3;

 int mod(int n, int x)
 {
     return ((n%x)+x)%x;
 }

出力:

 -1
于 2013-10-29T10:32:24.290 に答える
3

よりパフォーマンスを重視する開発者向け

uint wrap(int k, int n) ((uint)k)%n

ちょっとした性能比較

Modulo: 00:00:07.2661827 ((n%x)+x)%x)
Cast:   00:00:03.2202334 ((uint)k)%n
If:     00:00:13.5378989 ((k %= n) < 0) ? k+n : k

uint へのキャストのパフォーマンス コストについては、こちらをご覧ください

于 2015-07-31T00:29:20.377 に答える
3

C# の % 演算子の文書化された動作とは反対の動作を期待しています。おそらく、慣れ親しんだ別の言語で動作するように動作することを期待しているためです。C#の状態に関するドキュメント(強調鉱山):

整数型のオペランドの場合、a % b の結果は、a - (a / b) * b によって生成される値です。ゼロ以外の剰余の符号は、左側のオペランドの符号と同じです

必要な値は、1 つの追加ステップで計算できます。

int GetArrayIndex(int i, int arrayLength){
    int mod = i % arrayLength;
    return (mod>=0) : mod ? mod + arrayLength;
}
于 2020-01-23T14:32:04.370 に答える
0

dcastroの回答の単一行実装(他の言語に最も準拠):

int Mod(int a, int n)
{
    return (((a %= n) < 0) && n > 0) || (a > 0 && n < 0) ? a + n : a;
}

演算子の使用を維持したい場合%(C# でネイティブ演算子をオーバーロードすることはできません):

public class IntM
{
    private int _value;

    private IntM(int value)
    {
        _value = value;
    }

    private static int Mod(int a, int n)
    {
        return (((a %= n) < 0) && n > 0) || (a > 0 && n < 0) ? a + n : a;
    }

    public static implicit operator int(IntM i) => i._value;
    public static implicit operator IntM(int i) => new IntM(i);
    public static int operator %(IntM a, int n) => Mod(a, n);
    public static int operator %(int a, IntM n) => Mod(a, n);
}

ユースケース、両方が機能します:

int r = (IntM)a % n;

// Or
int r = a % n(IntM);
于 2020-04-30T13:26:22.887 に答える