循环整数
Circulating integer
我需要写一个 "circulates" 介于最小值和最大值之间的整数。如果达到最大值并加 1,它会跳到最小值。如果从最小值中减去 1,就会达到最大值。
示例:
最小值 = 2;
最大值 = 10;
导致:... 2,3,4,...9,10,2,3,...
我想通了加法算法,但我被减法卡住了。
添加看起来像这样:
public static circularInt operator +(circularInt a, int b)
{
int sum = a.value + b;
int circularValue = ((sum - a.minValue) % (a.maxValue + 1 - a.minValue)) + a.minValue;
return new circularInt(circularValue, a.minValue, a.maxValue);
}
基本上算法可以分解为"newValue % range"。所有的+- minValue只是为了从计算中剔除它,稍后再添加它。
是否有已知的算法?如果没有,您是否知道减法算法可能是什么样子?
正在替换
int sum = a.value + b;
和
int sum = (a.value - b + ( (b / range) * range) );
哪里
int range = a.maxValue + 1 - a.minValue;
应该没问题!
首先将模数应用于 b
,然后从 a.value
中减去最小值
int range = a.maxValue + 1 - a.minValue;
b %= range;
int value = a.value - a.minValue;
允许负值,b
现在将大于 -range
且小于 range
。
对于加法,将 b
和 range
添加到 value
,然后应用模数。当b
为负数时,需要加上range
。加一个负数和减一个正数是一样的。
int result = (value+range+b) % range;
对于减法,在减去 b
之前将 range
添加到 value
,然后应用模数。这是可行的,因为 (value+range) % range == value
所以添加范围不会改变最终结果,但它确实可以防止中间结果变为负值。
int result = (value+range-b) % range;
通过将最小值加回
完成
int circularValue = result + a.minValue;
这是最终代码,由 @Meister der Magie
提供
加法:
public static circularInt operator +(circularInt a, int b)
{
int range = (a.maxValue + 1 - a.minValue);
b %= range;
int value = a.value - a.minValue;
int additionResult = (value+range+b) % range;
int circularValue = additionResult + a.minValue;
return new circularInt(circularValue, a.minValue, a.maxValue);
}
减法:
public static circularInt operator -(circularInt a, int b)
{
int range = (a.maxValue + 1 - a.minValue);
b %= range;
int value = a.value - a.minValue;
int subtractionResult = (value+range-b) % range;
int circularValue = subtractionResult + a.minValue;
return new circularInt(circularValue, a.minValue, a.maxValue);
}
这应该让您对公式有所了解:
private const int MinValue = 2;
private const int MaxValue = 10;
public static int AddCircular(int a, int b)
{
int modulo = MaxValue - MinValue + 1;
int sum = (a - MinValue + b) % modulo + MinValue;
if (sum < MinValue) sum += modulo;
return sum;
}
输出:
AddCircular(2,-1);
10
AddCircular(10,1);
2
我需要写一个 "circulates" 介于最小值和最大值之间的整数。如果达到最大值并加 1,它会跳到最小值。如果从最小值中减去 1,就会达到最大值。
示例:
最小值 = 2;
最大值 = 10;
导致:... 2,3,4,...9,10,2,3,...
我想通了加法算法,但我被减法卡住了。 添加看起来像这样:
public static circularInt operator +(circularInt a, int b)
{
int sum = a.value + b;
int circularValue = ((sum - a.minValue) % (a.maxValue + 1 - a.minValue)) + a.minValue;
return new circularInt(circularValue, a.minValue, a.maxValue);
}
基本上算法可以分解为"newValue % range"。所有的+- minValue只是为了从计算中剔除它,稍后再添加它。
是否有已知的算法?如果没有,您是否知道减法算法可能是什么样子?
正在替换
int sum = a.value + b;
和
int sum = (a.value - b + ( (b / range) * range) );
哪里
int range = a.maxValue + 1 - a.minValue;
应该没问题!
首先将模数应用于 b
,然后从 a.value
int range = a.maxValue + 1 - a.minValue;
b %= range;
int value = a.value - a.minValue;
允许负值,b
现在将大于 -range
且小于 range
。
对于加法,将 b
和 range
添加到 value
,然后应用模数。当b
为负数时,需要加上range
。加一个负数和减一个正数是一样的。
int result = (value+range+b) % range;
对于减法,在减去 b
之前将 range
添加到 value
,然后应用模数。这是可行的,因为 (value+range) % range == value
所以添加范围不会改变最终结果,但它确实可以防止中间结果变为负值。
int result = (value+range-b) % range;
通过将最小值加回
完成int circularValue = result + a.minValue;
这是最终代码,由 @Meister der Magie
提供加法:
public static circularInt operator +(circularInt a, int b)
{
int range = (a.maxValue + 1 - a.minValue);
b %= range;
int value = a.value - a.minValue;
int additionResult = (value+range+b) % range;
int circularValue = additionResult + a.minValue;
return new circularInt(circularValue, a.minValue, a.maxValue);
}
减法:
public static circularInt operator -(circularInt a, int b)
{
int range = (a.maxValue + 1 - a.minValue);
b %= range;
int value = a.value - a.minValue;
int subtractionResult = (value+range-b) % range;
int circularValue = subtractionResult + a.minValue;
return new circularInt(circularValue, a.minValue, a.maxValue);
}
这应该让您对公式有所了解:
private const int MinValue = 2;
private const int MaxValue = 10;
public static int AddCircular(int a, int b)
{
int modulo = MaxValue - MinValue + 1;
int sum = (a - MinValue + b) % modulo + MinValue;
if (sum < MinValue) sum += modulo;
return sum;
}
输出:
AddCircular(2,-1);
10
AddCircular(10,1);
2