Есть ли функция в С#, которая принимает два 32-битных целых числа (int) и возвращает один 64-битный (длинный)?
Похоже, что должен быть простой способ сделать это, но я не смог найти решение.
Есть ли функция в С#, которая принимает два 32-битных целых числа (int) и возвращает один 64-битный (длинный)?
Похоже, что должен быть простой способ сделать это, но я не смог найти решение.
Попробуйте выполнить
public long MakeLong(int left, int right) {
//implicit conversion of left to a long
long res = left;
//shift the bits creating an empty space on the right
// ex: 0x0000CFFF becomes 0xCFFF0000
res = (res << 32);
//combine the bits on the right with the previous value
// ex: 0xCFFF0000 | 0x0000ABCD becomes 0xCFFFABCD
res = res | (long)(uint)right; //uint first to prevent loss of signed bit
//return the combined result
return res;
}
Просто для ясности... Хотя принятый ответ действительно работает правильно. Все представленные в одном вкладыше не дают точных результатов.
Вот один лайнер, который работает:
long correct = (long)left << 32 | (long)(uint)right;
Вот какой код, чтобы вы могли проверить его самостоятельно:
long original = 1979205471486323557L;
int left = (int)(original >> 32);
int right = (int)(original & 0xffffffffL);
long correct = (long)left << 32 | (long)(uint)right;
long incorrect1 = (long)(((long)left << 32) | (long)right);
long incorrect2 = ((Int64)left << 32 | right);
long incorrect3 = (long)(left * uint.MaxValue) + right;
long incorrect4 = (long)(left * 0x100000000) + right;
Console.WriteLine(original == correct);
Console.WriteLine(original == incorrect1);
Console.WriteLine(original == incorrect2);
Console.WriteLine(original == incorrect3);
Console.WriteLine(original == incorrect4);
Try
(long)(((long)i1 << 32) | (long)i2)
это сдвигает первый int слева на 32 бита (длина int), затем ors во втором int, так что вы заканчиваете с двумя ints, соединенными вместе длинным.
Это должно сделать трюк
((Int64) a << 32 | b)
Где a
и b
- Int32. Хотя вы можете проверить, что происходит с самыми высокими битами. Или просто поместите его в блок "unchecked
{...}".
Обязательно будьте осторожны с подобным битом, хотя вы будете иметь проблемы с маленькими машинами endian/big endian (на платформах Mono не всегда мало endian). Кроме того, вам приходится иметь дело с расширением знака. Математически следующее одно и то же, но имеет дело с расширением знака и является агностиком платформы.
return (long)( high * uint.MaxValue ) + low;
При запуске во время выполнения это приведет к тому, что производительность будет похожа на бит. Это одна из приятных вещей о интерпретируемых языках.
Будьте осторожны с битом знака. Вот быстрое решение ulong, которое также не переносимо с прямым порядком байтов:
var a = 123;
var b = -123;
unsafe
{
ulong result = *(uint*)&a;
result <<= 32;
result |= *(uint*)&b;
}
Существует проблема, когда i2 <0 - будут установлены старшие 32 бита (0xFFFFFFFF, 1xxx... двоичный) - цикл был неверным
Лучше было бы что-то вроде (Int64) (((UInt64) i1 << 32) | (UInt32) i2)
Или просто C++
public static unsafe UInt64 MakeLong(UInt32 low, UInt32 high)
{
UInt64 retVal;
UInt32* ptr = (UInt32*)&retVal;
*ptr++ = low;
*ptr = high;
return retVal;
}
UInt64 retVal;
unsafe
{
UInt32* ptr = (UInt32*)&retVal;
*ptr++ = low;
*ptr = high;
}
Но лучшее решение, найденное тогда здесь ;-)
[StructLayout (LayoutKind.Explicit)]
[FieldOffset()]
fooobar.com/info/459733/...
(даже без небезопасных). В любом случае FieldOffset работает для каждого элемента, поэтому вы должны указать положение каждой половины отдельно и помнить, что отрицательные числа # являются нулевыми дополнениями, поэтому ex. низкий <0 и высокий> 0 не будут иметь смысла - например, -1, 0 даст Int64 как 4294967295, вероятно.