我有一些无符号的int类型(比方说)k比特,它可以存储0到0但不包括N(= 2 k )的值。使用两个这样的uint,我想表示这些值的任何连续范围,其中范围在概念上是偏移和长度,具有不同偏移的空范围被认为是不同的。例如,我希望能够使用两个uint8来表示[0, 255]
的任何子范围。
一个自然表示是元组(offset, count)
。但是,这不能表示[0, N-1]
的整个范围,因为那时计数需要为N.另一个表示是半开区间[start, end)
,但这不能表示包含N的范围1,因为结尾不包括在内。
但是两个缺点就足够了,这是一个证据。我们有两个uint,每个uint可以表示N个值,它们一起可以表示N 2 值。有N个长度为1的范围,长度为2的N-1范围等,长度为N的1个范围。我们还有N个长度为0的范围。求和,我们有N*(N+1)/2 + N
个总范围。当N> 1时,这可以重写为N*(N/2 + 3/2)
,小于N 2 。因此,两个因素给出了比范围更具代表性的值。
那么使用两个uint表示范围的最自然(即方便)的方法是什么,没有任何不可代表的"漏洞"?
感谢您的任何想法!
答案 0 :(得分:3)
以下作品,虽然最后一个条款不是最自然的:
1)[a,b]
适用于[0,1,...2^(N-1)]
的普通子区间a <= b
2)[a, a-1]
表示从a
开始的空间隔,a > 0
3)[2^(N-1), 0]
表示从0
开始的空间隔
关键是,当您查看元组(a,b)
时,您会进行比较a<=b
。如果计算结果为true,则将元组解释为给出闭合间隔的端点。如果为false,则将其解释为空间隔。显然,您对空子区间的编码方式有一定的灵活性,因此可以很容易地调整第2点和第3点。
答案 1 :(得分:1)
任何表示都会有一些不自然的现象,因为有N + 1个范围从0开始,并且因为表示不能推广到N <= 2。也就是说,我们可以尽量减少特殊情况。
如果我们将表示基于(base, number of elements)
,那么除了[0, N-1]
之外,我们对每个范围都有自然表示。我们可以选择任何未使用的元组来表示此范围,例如(N-1, N-1)
,其中N> 2不是其他范围的表示。
如果我们将表示基于(first element, last element)
,我们就可以自然地表示所有非空范围。不幸的是,我们有N个空范围需要编码,而像(N-1, base)
这样的表示只编码N-1个空范围,因为已经使用了(N-1, N-1)
。我们最终需要两种形式的特殊情况表示。
如果我们将表示基于(first element, last element + 1)
,我们可以自然地表示所有不以N-1结尾的范围。不幸的是,我们最终还需要两种形式的特殊情况表示,因为很难将所有256个剩余范围拟合成一种表示形式。
(base, number of elements)
以[0, N-1]
为特例表示最为自然。
答案 2 :(得分:1)
如果你想获得数学,你可以用基数N对三角形数字进行编码。在这种情况下,我们需要所有的位来表示更高的数字。 JavaScript示例:
char test[]={'A'};
char testt[]={'a'};
string testtt= test[0]+testt[0];
输出:
function f(n,N){
var a = Math.floor((Math.sqrt(1 + 8 * n) - 1) / 2);
var b = n - a * (a + 1) / 2;
return [N - a, N - b];
}
答案 3 :(得分:0)
我认为最自然的方式是使用包容性范围,即(a,b)所有x | a&lt; = x&lt; = b。
如果我真的需要存储零长度范围,那么(1,0)
我从未遇到现实生活中的情况,我实际上必须区分零长度范围。
这种表示法让你可以编写一个相当不错的循环而不使用更宽泛的类型:
for (uint i = range.start; i <= range.end; )
{
...
if (!++i)
break;
}