用单个数值表示前 10 名列表的方法
我有一个前 10 名列表,其中包含分数(最高分获胜)和时间戳。
时间戳用于平局得分的情况,在这种情况下,具有最低时间戳的平局得分获胜(第一个获得得分较高的人)。
排序数据集示例:
20 102906755
15 102910755
14 102890755
14 102890756
13 102890756
请注意得分 14 上的平局,时间戳较小的得分较高。
我需要以正确的顺序将分数和时间戳表示为单个 32 位值。
假设最高分是100万。
我通过减去第一个有效日期分数来减少时间戳值。
在 C 语言中如何实现这一点?
I have a top 10 list with a score (highest score wins) and a timestamp.
The timestamp is used in the case of a tie score, in which case the tied score with the lowest timestamp wins (first person to achieve the score places higher).
Sorted data set example:
20 102906755
15 102910755
14 102890755
14 102890756
13 102890756
Notice the tie on score 14, the one with the smaller timestamp is placed higher.
I need to represent with proper ordering both the score and timestamp as a single 32bit value.
Assume the maximum score is 1 million.
I have reduced the timestamp value by subtracting the first valid date score.
How might this be accomplished in C?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
首先,如果您需要表示超过 2^32 个不同的分数与时间戳组合,那么游戏就结束了 - 无法完成。
考虑到这一点:
如果其中任何一个的答案是好的,那么也许这是可能的。如果答案都很糟糕,那么根本不可能做你想做的事。
[编辑:考虑到下面的评论,你的新问题的答案是:
容易得多。一直到公元 2242 年都很好。
假设您的实现上的 double 是 64 位,这几乎是通用的。]
First thing is that if there are more than 2^32 different combinations of score with timestamp that you need to represent then it's game over - can't be done.
With that in mind:
If the answers to any of those are good, then perhaps it's possible. If the answers are all bad, then it's simply not possible to do what you want.
[Edit: the answer to your new question, taking into account the comment below, is:
Much easier. It's good until 2242AD.
This assuming
double
is 64 bits on your implementation, which is almost universal.]假设您要使用无符号值,并且您的最大分数是 31。
您可以使用前 5 位作为分数,使用较低的 27 位作为时间戳。
请注意,这限制了两个值的限制,因此您必须考虑可能的值以及如果尝试使用该范围之外的值时将采取的措施。
存储...
并稍后获取值:
请注意,您需要在使用分数和时间戳之前检查它们,并且可能应用掩码以确保值不会重叠。
编辑
Riderchap 提出了一个很好的观点。作为示例给出的时间戳太大,无法与 32 位整数一起使用。我的回答更多的是演示原则上如何做到这一点。
Let's say you were going to use unsigned values, and your maximum score was 31.
You could use the top 5 bits for the score, and the lower 27 for the timestamp.
Note that this constrains the limits of both values, so you must consider the possible values and what you will do if you try to use values outside of that range.
To store...
And to later get the values:
Please note though that you want to check the score and timestamp before using them, and probably apply masks to be sure the values do not overlap.
Edit
Riderchap makes a good point. The timestamps you give as an example would be too large to use with a 32 bit integer. My answer is more of a demonstration of how to do this in principle.
尽管您随后表示实际上有一个 double 可以用来存储信息,但我想我仍然可以分享一些关于使用 32 位整数执行此操作的想法。
首先,为了让这些数字按照分数顺序第一、时间顺序第二排序,您希望分数占据较高值的位置,而时间戳占据较低值的位置。为了将分数放在较高值的位置,我们必须选择将其乘以某个常数因子。无符号 32 位整数可以表示的最大数字是 4,294,967,295 ,我们的分数范围是 0 到 1,000,000。这给我们带来了 4,294 的乘数。
然后,我们就得到了时间戳占据的较低值位置 - 只需将其添加进去。这给了我们:
反向转换为:
但是,请注意,
TIMESTAMP
允许的范围是 0 到4293 含。任何更高的值都会溢出到N
中被SCORE
占据的部分。如果TIMESTAMP
只是一个秒数(从最早的分数从 4293 开始倒计时),这只能给我们从最早的分数到最新的分数的最大时间,刚刚超过 71 分钟 - 可能不够。这只是对您可以用 32 位整数表示的不同存储桶数量的限制 - 为了能够使用此模型表示更多不同的时间戳,您需要减少可以表示的不同分数的数量。
但是,请注意,我们并不真正希望将时间戳作为时间戳 - 我们只是希望它作为分数的单调排序。作为替代方案,我们可以保留一个计数器。将计数器初始化为 4293。当新的分数出现时,将计数器的当前值存储为“时间戳”,然后递减计数器。这将允许在计数器用完之前存储 4294 个不同的高分。
作为进一步的细化,我们可以注意到我们只关心同一
SCORE
值内的排序。这提出了另一种选择:当出现新的高分时,找到该分数当前最低的 TIMESTAMP 值。将其减 1,并将其用作新分数的“时间戳”(如果这是第一次提交此SCORE
,则使用 4293 作为时间戳)。这将允许每个个人得分值有 4294 个高分。Although you've subsquently said that you actually have a
double
available to store the information, I thought I might still share some thoughts on doing this with a 32 bit integer.Firstly, in order to have these numbers sort in score order first and time order second, you want the score to occupy the higher value places and the timestamp to occupy the lower. To place the score in the higher value places, we must pick a multiply it by some constant factor. The largest number that can be represented by an unsigned 32 bit integer is 4,294,967,295 , and we we have a score range of 0 to 1,000,000. This gives us a multiplier of 4,294.
We then have the lower-value positions occupied by the timestamp - just need to add that in. This gives us:
The reverse conversions are:
However, note that the range this allows for the
TIMESTAMP
is 0 to 4293 inclusive. Anything higher would overflow into the parts ofN
occupied by theSCORE
. IfTIMESTAMP
is simply a number of seconds (starting at 4293 for the earliest score and counting down), this only gives us a maximum time of just over 71 minutes from the earliest score to the latest - probably insufficient.This is simply a limit on the number of different buckets you can represent with a 32 bit integer - to be able to represent more distinct timestamps with this model, you need to reduce the number of distinct scores you can represent.
However, note that we don't really want the timestamp as a timestamp - we just want it as a monotonic ordering on the scores. As an alternative, we can keep a counter. Initialise the counter to 4293. When a new score comes in, store it with the current value of the counter as its "timestamp", then decrement the counter. This will allow 4294 distinct highscores to be stored before the counter runs out.
As a further refinement, we can note that we only care about the ordering within the same
SCORE
value. This suggests another alternative: when a new high score comes in, find the current lowest TIMESTAMP value for that score. Decrement it by 1, and use that for the "timestamp" of the new score (if this is the first time that thisSCORE
has been submitted, use 4293 as the timestamp). This will allow 4294 high scores per individual score value.根据高分,您需要切换要移位的位数。假设最大分数为 255,这使我们移位 8 位。
无符号整数组合 = ~(分数 << 32-8) | (time & 0x0FFF);
这可能会切断时间的 MSB,但除非您期望有几年差异的平局,否则就没问题。它将分数反转并放置在前 8 位中,然后将其与后 24 位中的时间相结合。最小值将是最高分数(反转的最高分数 = 最低分数和最低时间戳)。
Depending upon the high score, you would need to switch the number of bits to shift. Lets assume a max score of 255, which gives us a shift of 8 bits.
unsigned int combined = ~(score << 32-8) | (time & 0x0FFF);
That might cut off the MSB of time, but unless you're expecting a tie with a few years difference, you'll be fine. It inverts the score and places it in the top 8 bits, then it combines it with the time in the lower 24. The smallest value will be the top score (inverted high score=lowest score and lowest timestamp).