将两个 Int32 组合成一个 Int64

Posted

技术标签:

【中文标题】将两个 Int32 组合成一个 Int64【英文标题】:Combine Two Int32 Into An Int64 【发布时间】:2012-04-01 17:40:53 【问题描述】:

拥有经常使用的字典 。我的意思是在大数据负载中运行数天的循环中。 Int64 来自两个 Int32。该字节恰好是许多非常长的列表中这两个 Int32 之间的距离(计数)。

在这个循环中我需要做的是

生成密钥 如果字典中不存在键,则插入键和值 如果键确实存在并且新值(字节)小于现有值,则将现有值替换为新值

现在我正在使用直接数学来生成密钥,我知道有更快的方法,但我无法弄清楚。我把 shift 作为一个标签,因为我认为这是如何优化它,但我无法弄清楚。

然后当循环完成后,我需要从 Int64 中提取两个 Int32 以将数据插入到数据库中。

谢谢

根据评论我用来 的数学

        Int64 BigInt;
        Debug.WriteLine(Int32.MaxValue);
        Int32 IntA = 0;
        Int32 IntB = 1;
        BigInt = ((Int64)IntA * Int32.MaxValue) + IntB;
        Debug.WriteLine(BigInt.ToString());
        IntA = 1;
        IntB = 0;
        BigInt = ((Int64)IntA * Int32.MaxValue) + IntB;
        Debug.WriteLine(BigInt.ToString());
        IntA = 1;
        IntB = 1;
        BigInt = ((Int64)IntA * Int32.MaxValue) + IntB;
        Debug.WriteLine(BigInt.ToString());

最好的密钥可能不是 Int64。我所拥有的是两个 Int32,它们共同构成一个密钥。和一个字节的值。我需要快速查找该复合键。字典很快,但它不支持复合键,所以我创建了一个实际上是复合键的单个键。在 SQL Int32A 中,Int32B 构成 PK。

我不使用复合键的原因是我想要 Dictionary 的查找速度,并且据我所知 Dictionary 不支持复合键。这是生产代码。在 SQL 表中实际上还有第三个键(Int32 sID、Int32 IntA、Int32 IntB)。在这个解析器中,我一次只处理一个 sID(并且 sID 是按顺序处理的)。我从对 SQL 的复合键查找开始(一次运行数十亿次)。当我将 IntA、IntB 拉出到 Dictionary 以处理单个 sID,然后在每个 sID 完成时加载到 SQL,我得到了 100:1 的性能提升。部分性能改进是插入,因为当我从字典中插入时,我可以按 PK 顺序插入。新的 IntA 和 IntB 不是由解析生成的,因此直接插入 SQL 会严重分割索引,我需要在运行结束时重建索引。

【问题讨论】:

你所说的“直接数学”是什么意思?请展示一些代码来说明两个 int32 和 int64 之间的关系。 @OliCharlesworth 我添加了我使用的直接数学的简单示例。 Int32.MaxValue 是 2^32-1。你确定这就是你想要的吗? @OliCharlesworth 请提出一种更好的方法来为 Dictionary 生成密钥,其中该密钥实际上是两个 Int32 的组合。然后从该键中提取两个 Int32。 @Blam:我的答案和 Bas 都以比您所拥有的更易于理解的方式结合了 2 个 Int32 值。我怀疑你是瞄准我们已经拥有的东西,但没有完全做到。你有什么反对只使用完全正交的两组 32 位吗? 【参考方案1】:

如果您想从 Int32 到 Int64 来回转换,您可以使用具有显式布局的结构:

//using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Explicit)]
struct Int64ToInt32

    [FieldOffset(0)]
    public Int64 Int64Value;
    [FieldOffset(0)]
    public Int32 LeftInt32;
    [FieldOffset(4)]
    public Int32 RightInt32;

只需从字段中设置/获取值。

【讨论】:

请注意,为了语言互操作性,.NET 命名约定建议将 LeftInt32RightInt32Int64ValueInt64ToInt32 作为名称。 仅供参考,OP 更新后的问题包含暗示它不仅仅是简单的位修改的代码...... 哦!这很漂亮!它只是让我快乐。谢谢! 这真是太好了,谢谢。一个问题:如果在构造函数中,我分配了LeftIntRightInt(来自构造函数参数)。有没有办法避免“在返回给调用者之前必须完全分配字段(在这种情况下为LongValue)”编译器错误消息? (除了将零分配给LongValue 之外的其他方式) @tigrou 我认为没有任何办法,但是如果您在字段初始化程序或构造函数中将 LongValue 设置为零,则应该不会影响性能,因为这是无论如何都要构造。【参考方案2】:

听起来你只是想要换班。就我个人而言,我发现在使用无符号类型而不是有符号类型时考虑移位更简单:

// Note: if you're in a checked context by default, you'll want to make this
// explicitly unchecked
uint u1 = (uint) int1;
uint u2 = (uint) int2;

ulong unsignedKey = (((ulong) u1) << 32) | u2;
long key = (long) unsignedKey;

然后反转:

ulong unsignedKey = (long) key;
uint lowBits = (uint) (unsignedKey & 0xffffffffUL);
uint highBits = (uint) (unsignedKey >> 32);
int i1 = (int) highBits;
int i2 = (int) lowBits;

您完全有可能不需要将所有这些转换为无符号类型。这比其他任何事情都更符合我的理智:)

请注意,您需要将 u1 转换为 ulong 以便在正确的空间中进行移位 - 将 uint 移位 32 位将无济于事。

请注意,这是将两个 32 位整数组合成一个 64 位整数的一种方法。无论如何,这不是唯一的方式。

(旁注:Bas 的解决方案效果很好 - 我总是对这种方法有些不舒服,没有具体原因。)

【讨论】:

仅供参考,OP 更新后的问题包括暗示它不仅仅是简单的位修改的代码...... @OliCharlesworth:我怀疑这更像是“这看起来可能有效”的人工制品,而不是深思熟虑的决定。已添加评论以进行检查。 @OliCharlesworth 这就是我今天使用的数学。我只是想让它更快。将查找从 SQL 转移到 Dictionary 极大地提高了性能,并希望优化 Dictionary 或者是否有更好的方法。 谢谢,在底部、顶部和中间进行了测试。请参阅我提出的外观修改。 @Blam:是的,没关系 - 抱歉弄错了 :)【参考方案3】:

您可以使用位移将两个 32 位值存储在一个 64 位变量中。

我举个小例子:

int a = 10;
int b = 5;
long c;

//To pack the two values in one variable
c = (long)a << 32;
c = c + (long)b;
//the 32 most significant bits now contain a, the 32 least significant bits contain b

//To retrieve the two values:
c >> 32 == a
c - ((c>>32)<<32) == b

编辑:我知道我参加聚会有点晚了,如果我没有弄错的话,我只是想签入 VS :)

【讨论】:

以上是关于将两个 Int32 组合成一个 Int64的主要内容,如果未能解决你的问题,请参考以下文章

将多个字典组合成一个[重复]

将 2 个连续字节转换为一个 int 值在 C# 中提高速度

C++ 将两个 int 数组连接成一个更大的数组

Scala Slick 将 Rep 子查询组合成一个 re

将 int 数组合并为单个 int

如何将字节拆分/组合成音频?