C++ 将多个int值存储到一个变量中-C++;

C++ 将多个int值存储到一个变量中-C++;,c++,bit-shift,C++,Bit Shift,我正在做一个算法竞赛,我正在尝试优化我的代码。也许我想做的是愚蠢和不可能的,但我想知道 我有这些要求: 可包含4种不同类型项目的库存。此库存不能包含超过10个项目(包括所有类型)。有效库存示例:1/1/1/0。无效库存示例:11/0/0/0或5/5/5/0 我有一些收据,用来消费或将物品添加到我的库存中。这个 由于库存不足,recepe无法添加或合并超过10个项目 不能有超过10个项目。有效收据示例:-1/-2/3/ 0无效接收器示例:-6/-6/+12/0 现在,我将清单和recepe存储

我正在做一个算法竞赛,我正在尝试优化我的代码。也许我想做的是愚蠢和不可能的,但我想知道

我有这些要求:

  • 可包含4种不同类型项目的库存。此库存不能包含超过10个项目(包括所有类型)。有效库存示例:1/1/1/0。无效库存示例:11/0/0/0或5/5/5/0
  • 我有一些收据,用来消费或将物品添加到我的库存中。这个 由于库存不足,recepe无法添加或合并超过10个项目 不能有超过10个项目。有效收据示例:-1/-2/3/ 0无效接收器示例:-6/-6/+12/0
现在,我将清单和recepe存储为4个整数。然后我可以执行一些操作,如:

if ((inv >> 4) & 0b1111 >= (rec >> 4) & 0b1111)
  • 应用接收:库存(1/1/1/0)。应用(接收(-1/1/0/0))=库存(0/2/1/0)
  • 鸭翼:Iventory(1/1/0/0)。鸭翼(Recepe(-2/1/0/0))=False
我想知道是否有可能(如果有,如何)将库存/收货的4个值存储到一个整数中,并对其执行以前的操作,这比我现在所做的比较/添加4个整数要快

我想到了类似这样的清单:

int32:XXXX(第一类项目数量)-YYYY(第二类项目数量)-ZZZ(第三类项目数量)-WWW(第四类项目数量)

但我有两个问题:

  • 我不知道如何处理可能的负值
  • 在我看来,这似乎比仅仅添加4个整数慢得多,因为我必须对库存和接收进行位移位,以获得我想要的值,然后继续进行加法

  • <>特别是如果你正在学习,尝试实现你自己的帮助类并不是一个坏的机会,因此加深你对C++中数据的理解,即使你的用例可能不符合该技术。 您想要利用的洞察是,如果考虑到令人讨厌的进位和标牌效应(例如,2的补码),算术运算似乎对位移位保持不变。但正是由于这些后一种因素,正如@Botje所建议的那样,使用一些标准化的底层类型,如
    int8\u t[]
    ,要好得多

    首先,实现以下功能。(我的C++是生锈的,考虑这个伪代码)

    还考虑到:

    • 您希望如何处理溢出和下溢?让他们这样做,并要求开发商谨慎行事?还是抛出异常
    • 也许您希望确定阵列的大小,避免处理动态大小\u t
    • 也许你会想到重载操作符
    这样一个练习的最终结果,但经过概括和修饰,是这样的。但是你会从一个完全不同的层面来理解它,首先你自己做这个练习。此外,如果到目前为止所有这些都是有意义的,那么您现在可以看看——在某些情况下,甚至编译器也可以为您进行矢量化

    @Botje提到的Bitpacking是这方面的又一步。您甚至不会像int8\u t或int4\u t那样拥有整数类型的安全性和方便性。这还意味着您编写的代码可能不再是平台独立的。我建议在深入研究此问题之前,至少完成矢量化练习

    将多个int值存储到一个变量中

    这里有两种选择:

    数组。这样做的好处是您可以迭代元素:

    int variable[] {
        1,
        1,
        1,
        0,
    };
    
    或者一个班级。这样做的好处是能够命名成员:

    struct {
        int X;
        int Y;
        int Z;
        int W;
    } variable {
        1,
        1,
        1,
        0,
    };
    

    然后我可以执行一些操作,如:

    if ((inv >> 4) & 0b1111 >= (rec >> 4) & 0b1111)
    
    这些看起来像SIMD向量操作(单指令多数据)。在这种情况下,数组就是解决方法。由于操作数的数量在您的描述中看起来是恒定的且很小,因此在CPU 1上执行这些操作的有效方法是向量操作

    <>在C++中没有标准的直接使用SIMD操作的方法。为使编译器有最佳机会使用它们,需要遵循以下步骤:

    • 确保您使用的CPU支持您需要的操作。AVX-2指令集及其扩展广泛支持整数向量运算
    • 确保您告诉编译器程序应该针对该体系结构进行优化
    • 确保告诉编译器执行矢量化优化
    • 确保整数按照操作要求充分对齐。这可以通过
      alignas
      实现
    • 确保编译时已知整数的数量

    如果依赖优化程序的前景令您担忧,那么您可能更喜欢使用编译器提供的向量扩展。语言扩展的使用自然会以其他编译器的可移植性为代价。以下是GCC的一个示例:

    constexpr int count = 4;
    using v4si = int __attribute__ ((vector_size (sizeof(int) * count)));
    
    #include <iostream>
    
    int main()
    {
        v4si inventory { 1, 1, 1, 0};
        v4si recepe    {-1, 1, 0, 0};
    
        v4si applied = inventory + recepe;
    
        for (int i = 0; i < count; i++) {
            std::cout << applied[i] << ", ";
        }
    }
    
    constexpr int count=4;
    使用v4si=int uu属性(向量大小(sizeof(int)*计数));
    #包括
    int main()
    {
    v4si清单{1,1,1,0};
    v4si recepe{-1,1,0,0};
    v4si应用=存货+收据;
    for(int i=0;i
    为简单起见,假设配方只能从库存中删除,并且只能包含正值(可以使用2的补码表示负数,但这将需要更多位,并增加使用位压缩数的复杂性)

    然后,一个项目有11个可能的值,因此每个项目需要4位。四个项目可以在一个uint16中表示

    那么,假设你有一个包含10,4,6,9项的库存;这将是
    uint
    
    if (inv & 0b0000000011110000 >= rec & 0b0000000011110000)