我有一个前十名的成绩(得分最高)和时间戳。
时间戳用于平局分数,在这种情况下,带有最低时间戳的并列分数获胜(第一个获得分数的人更高)。
排序数据集示例:
20 102906755
15 102910755
14 102890755
14 102890756
13 102890756
注意得分14上的平局,时间戳较小的那个位置较高。
我需要将得分和时间戳正确排序为单个32位值。
假设最高分为100万。
我通过减去第一个有效日期分数来减少时间戳值。
如何在C中实现这一目标?
答案 0 :(得分:2)
首先,如果有超过2 ^ 32个不同的得分组合,你需要表示时间戳,那么游戏就结束了 - 无法完成。
考虑到这一点:
如果其中任何一个的答案都很好,那么也许这是可能的。如果答案都很糟糕,那就根本不可能做你想做的事。
[编辑:考虑到以下评论,您的新问题的答案是:
double value = (double) score - ((double)timestamp) / (((long long)1) << 33);
更容易。直到2242年才好。
这假设double
在您的实现中是64位,几乎是通用的。]
答案 1 :(得分:1)
假设你要使用无符号值,你的最高分为31。
您可以使用前5位作为分数,将较低的27位作为时间戳。
请注意,这会限制两个值的限制,因此您必须考虑可能的值以及尝试使用该范围之外的值时将执行的操作。
存储......
composite = ~(score << 27) | timestamp;
以后获取值:
#define TIMESTAMP_BITS ((1 << 27) - 1)
score = composite >> 27;
timestamp = composite & TIMESTAMP_BITS;
请注意,虽然您想在使用它们之前检查分数和时间戳,并且可能应用遮罩以确保值不重叠。
修改强>
Riderchap提出了一个很好的观点。作为示例,您提供的时间戳太大,无法与32位整数一起使用。我的答案更多的是原则上如何做到这一点的示范。
答案 2 :(得分:1)
虽然您经常说您实际上有double
可用于存储信息,但我认为我仍然可能会分享一些使用32位整数执行此操作的想法。
首先,为了让这些数字按照得分顺序排序,时间顺序排在第二位,您希望得分占据较高值的位置,时间戳占据较低值。要将得分放在较高值的位置,我们必须选择乘以某个常数因子。可以用无符号32位整数表示的最大数字是4,294,967,295,我们的得分范围是0到1,000,000。这给了我们4,294的乘数。
然后我们有时间戳占用的低值位置 - 只需要添加它。这给了我们:
N = SCORE * 4294 + TIMESTAMP;
反向转换为:
SCORE = N / 4294;
TIMESTAMP = N % 4294;
但请注意,TIMESTAMP
允许的范围为0到4293(含)。任何更高的内容都会溢出N
所占据的SCORE
部分。如果TIMESTAMP
只是几秒钟(从最早的分数开始于4293并且倒计时),这只会给我们从最早的分数到最新分数的最长时间超过71分钟 - 可能不够。
这只是对可以使用32位整数表示的不同存储桶数量的限制 - 为了能够使用此模型表示更多不同的时间戳,您需要减少可以表示的不同分数。
但是,请注意,我们并不是真的希望将时间戳作为时间戳 - 我们只是希望它作为分数的单调排序。作为替代方案,我们可以保留一个柜台。将计数器初始化为4293.当新分数进入时,将其与计数器的当前值一起存储为其“时间戳”,然后递减计数器。这将允许在计数器用完之前存储4294个不同的高分。
作为进一步的改进,我们可以注意到,我们只关心相同SCORE
值中的排序。这表明另一种选择:当新的高分进入时,找到该分数的当前最低TIMESTAMP值。将其减1,并将其用于新分数的“时间戳”(如果这是第一次提交此SCORE
,请使用4293作为时间戳)。这将使每个人得分值达到4294分。
答案 3 :(得分:0)
根据高分,您需要切换要移位的位数。假设最大分数为255,这给我们一个8位的移位。
unsigned int combined = ~(score << 32-8) | (time & 0x0FFF);
这可能会缩短MSB的时间,但除非你期望与几年的差异打成平手,否则你会没事的。它将分数反转并将其置于前8位,然后将其与较低的24中的时间相结合。最小值将是最高分(倒置的高分=最低分和最低时间戳)。