四舍五入到给定数字数组中最接近的数字
Rounding to the closest number in a given array of numbers
在发布之前我查看了这两个答案:
C# Finding Nearest Number in Array
Round integer to nearest high number in array
虽然第一个对于其中一个答案中提到的扩展方法有点帮助,但我无法深入理解它,以至于我无法修改和实现它以适应我的具体情况,并且第二个不适合我的需要,因为它的数组长度很短,如果我要使用一个数组来存储所有以 2 为底的数字,最多 2.68 亿,它会有相对大量的条目。
基本上我在这里要做的是采用 RoundedSpeed(已使用 Math.Round
将其四舍五入为整数)并将其四舍五入到最接近的数字(它绝不能向下舍入,只能向上舍入)这是对 2 施加幂的结果。(示例数字包括 16384、32768、65536、131072 等)
对于这个特定的例子,我想要舍入到的数字是 32768。(虽然其他方法可能需要另一个数字,但这对我来说是一个问题,并且不在这个例子的范围内).
这是我现在拥有的代码:
double Speed = Math.Pow(2, ((-900 + Time) / -60)) - 1;
double RoundedSpeed = Math.Round(Speed);
最初我想用一个数组来存储要舍入的相关数字,但是有没有其他方法可以将 RoundedSpeed
舍入到最接近的以 2 为基数的整数?
我会使用循环:
double RoundedSpeed = Math.Round(Speed);
int maxAllowed = 100; // prevent infinite loop
for (int i=1; i < maxAllowed; i++)
{
double number = Math.Pow(2.0, (double)i);
if (number > RoundedSpeed)
return number;
}
如果您不在 return 的方法中,则不要使用 return 数字,而是使用数字做一些有用的事情,然后添加 "break;" 以停止循环。
您需要添加错误处理以确保您不会溢出最大整数值,并且如果您在到达 maxAllowed 时没有找到数字则可以做一些有用的事情。可能有更好的解决方案,但这是 "easy" 解决方案...
您可以使用按位运算非常有效地执行此操作。我在这里使用 ulong
作为输入和输出。这将 运行 很快。
ulong FancyRound(ulong value) {
value -= 1;
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
value |= value >> 32;
return value + 1;
}
你可以这样使用它:
for (ulong i = 1; i < 10; i++) {
Console.WriteLine("{0}: {1}", i, FancyRound(i));
}
输出:
1: 1
2: 2
3: 4
4: 4
5: 8
6: 8
7: 8
8: 8
9: 16
它的工作原理是 "cascading" 所有设置位向下,以便在所有 |
完成后,将设置所有低位,直到最重要的设置位。之后,将结果递增以获得 2 的整数次幂。
试试这个:
var x = 56;
var y = (int)Math.Pow(2.0, Math.Ceiling(Math.Log(x, 2.0)));
本例中的结果为 64。
实际上这是为 n
确定什么 2 ^ n = x
,但由于 n
可能是小数,因此它使用 Ceiling
将此数字带到最接近的整数(如果它已经是整数,则保留它)。所以n2 = Ceiling(n)
。然后它简单地计算 2 ^ n2
得到 y
.
的结果
我会这样做,我没有对它进行基准测试,所以我不会对速度做出任何声明:
long input = 32111;
long powerTwo = 1;
int count = 0;
int maxCount = 63; //You can't return 2^64 in a long so 63 should be the max here, as we start at 2^0!
while (input > powerTwo && count < maxCount) {
count++;
powerTwo <<= 1;
}
return powerTwo;
输出 32,768,之所以有效,是因为 long(或至少是下半部分)在内存中表示为 000000001(即 1),而 <<=
操作只是将位左移 1 并分配结果到 powerTwo
所以它在下一次迭代中变成 000000010(即 2),然后它只是计算出它比 input
.
大时得到的值
如果您知道它会在溢出 long 之前终止,那么您可以删除计数内容。
在发布之前我查看了这两个答案:
C# Finding Nearest Number in Array
Round integer to nearest high number in array
虽然第一个对于其中一个答案中提到的扩展方法有点帮助,但我无法深入理解它,以至于我无法修改和实现它以适应我的具体情况,并且第二个不适合我的需要,因为它的数组长度很短,如果我要使用一个数组来存储所有以 2 为底的数字,最多 2.68 亿,它会有相对大量的条目。
基本上我在这里要做的是采用 RoundedSpeed(已使用 Math.Round
将其四舍五入为整数)并将其四舍五入到最接近的数字(它绝不能向下舍入,只能向上舍入)这是对 2 施加幂的结果。(示例数字包括 16384、32768、65536、131072 等)
对于这个特定的例子,我想要舍入到的数字是 32768。(虽然其他方法可能需要另一个数字,但这对我来说是一个问题,并且不在这个例子的范围内).
这是我现在拥有的代码:
double Speed = Math.Pow(2, ((-900 + Time) / -60)) - 1;
double RoundedSpeed = Math.Round(Speed);
最初我想用一个数组来存储要舍入的相关数字,但是有没有其他方法可以将 RoundedSpeed
舍入到最接近的以 2 为基数的整数?
我会使用循环:
double RoundedSpeed = Math.Round(Speed);
int maxAllowed = 100; // prevent infinite loop
for (int i=1; i < maxAllowed; i++)
{
double number = Math.Pow(2.0, (double)i);
if (number > RoundedSpeed)
return number;
}
如果您不在 return 的方法中,则不要使用 return 数字,而是使用数字做一些有用的事情,然后添加 "break;" 以停止循环。
您需要添加错误处理以确保您不会溢出最大整数值,并且如果您在到达 maxAllowed 时没有找到数字则可以做一些有用的事情。可能有更好的解决方案,但这是 "easy" 解决方案...
您可以使用按位运算非常有效地执行此操作。我在这里使用 ulong
作为输入和输出。这将 运行 很快。
ulong FancyRound(ulong value) {
value -= 1;
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
value |= value >> 32;
return value + 1;
}
你可以这样使用它:
for (ulong i = 1; i < 10; i++) {
Console.WriteLine("{0}: {1}", i, FancyRound(i));
}
输出:
1: 1
2: 2
3: 4
4: 4
5: 8
6: 8
7: 8
8: 8
9: 16
它的工作原理是 "cascading" 所有设置位向下,以便在所有 |
完成后,将设置所有低位,直到最重要的设置位。之后,将结果递增以获得 2 的整数次幂。
试试这个:
var x = 56;
var y = (int)Math.Pow(2.0, Math.Ceiling(Math.Log(x, 2.0)));
本例中的结果为 64。
实际上这是为 n
确定什么 2 ^ n = x
,但由于 n
可能是小数,因此它使用 Ceiling
将此数字带到最接近的整数(如果它已经是整数,则保留它)。所以n2 = Ceiling(n)
。然后它简单地计算 2 ^ n2
得到 y
.
我会这样做,我没有对它进行基准测试,所以我不会对速度做出任何声明:
long input = 32111;
long powerTwo = 1;
int count = 0;
int maxCount = 63; //You can't return 2^64 in a long so 63 should be the max here, as we start at 2^0!
while (input > powerTwo && count < maxCount) {
count++;
powerTwo <<= 1;
}
return powerTwo;
输出 32,768,之所以有效,是因为 long(或至少是下半部分)在内存中表示为 000000001(即 1),而 <<=
操作只是将位左移 1 并分配结果到 powerTwo
所以它在下一次迭代中变成 000000010(即 2),然后它只是计算出它比 input
.
如果您知道它会在溢出 long 之前终止,那么您可以删除计数内容。