我试图对一个整数进行mod以获得一个数组位置,这样它就会循环。做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
我以前也这么做过,但不知为何,今天我的脑子都要融化了:(
mod函数有很多实现,我认为有必要列出所有实现——至少根据维基百科,我相信还有更多。
// Important to be able to use `MathF`.
using System;
public static class MathFUtils {
public static class Mod {
public static float Trunc(float a, float b) =>
a - b * ((int)(a / b));
public static float Round(float a, float b) =>
a - b * MathF.Round(a / b);
public static float Floor(float a, float b) =>
a - b * MathF.Floor(a / b);
public static float Ceil(float a, float b) =>
a - b * MathF.Ceiling(a / b);
public static float Euclidean(float a, float b) =>
a - MathF.Abs(b) * MathF.Floor(a / MathF.Abs(b));
}
}
根据维基百科(以及我的经验),坚持欧几里得。它在数学和概率性质方面是最有用的。如果您需要Trunc,那么我相信%可以做到这一点。
此外,对于那些可能对它们各自做什么以及如何做感到困惑的人,我强烈建议阅读维基百科的文章(即使很难)并查看每个表示的图像。
当然,这些不一定是性能最好的,但它们确实有效。如果你关心性能,我建议你找一个本地的c#之神,或者在他们经过我们的尘世时问他。
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);