选项 1:保序映射
听起来您正在要求一张保留顺序的地图,这意味着,例如,如果x
and y
are ulong
s and x < y
, then MapUlongToLong(x) < MapUlongToLong(y)
.
具体做法如下:
地图来自ulong
to long
、投射并添加long.MinValue
。地图来自long
回到ulong
, 减去long.MinValue
并投射。无论哪种情况,请使用未经检查的上下文,以便忽略溢出条件。
public static long MapUlongToLong(ulong ulongValue)
{
return unchecked((long)ulongValue + long.MinValue);
}
public static ulong MapLongToUlong(long longValue)
{
return unchecked((ulong)(longValue - long.MinValue));
}
逻辑为uint
and int
完全是类似的。
(选项1是我在2016年写的原始答案。我在2021年添加了选项2,以及两者的比较。)
选项 2:非保序映射
我认为这不是您所要求的,但如果您不关心保留顺序,则转换会更容易。
这些函数的工作方式与上述函数相同,只是我们不费心进行加或减long.MinValue
.
public static long MapUlongToLong(ulong ulongValue)
{
return unchecked((long)ulongValue);
}
public static ulong MapLongToUlong(long longValue)
{
return unchecked((ulong)longValue);
}
哪个选项更好?
选项 1 保留顺序,而选项 2 则不保留,因此如果您需要保留顺序,请使用选项 1。
选项 1 中的函数执行需要多长时间?嗯,这些函数可能会被 JIT 编译器内联和优化,它们最终会要求 CPU 做一些非常非常简单的事情。我猜测每个函数调用将花费不到 1 纳秒的时间。
其中一条评论将这个不到一纳秒的执行时间描述为“相对较慢”。如果纳秒对您来说太慢,您可能需要使用选项 2。
选项 2 中的函数也可能会被 JIT 编译器内联和优化,事实证明,就 CPU 而言,这些函数确实字面上什么都没有。因此,不会为这些函数生成机器代码,因此每个函数调用根本不会花费任何时间,换句话说,0 纳秒。
阿伦的回答 https://stackoverflow.com/a/40903051/1108505与选项 2 做同样的事情,我猜它也会运行得同样快。