繁体   English   中英

如何在一个 64 位整数中存储和使用两个 32 位带符号整数?

[英]How to store and use two 32-bit signed int in one 64-bit int?

首先,我想澄清一下,这个问题与问题不同:

这个问题是 store and use ,这意味着我可以做到这一点

int64_t score = make_score(-15, 15);
score += make_score(-5, 5); //I can use (add, subtract) the score
int32_t a = get_a(score);
assert(a == -20); //-15 -5 = -20
int32_t b = get_b(score);
assert(b == 20);//15 + 5= 20

这对于一个 32 位 int 中的两个 16 位 int 是可以实现的( Stockfish 做到了这一点):

/// Score enum stores a middlegame and an endgame value in a single integer (enum).
/// The least significant 16 bits are used to store the middlegame value and the
/// upper 16 bits are used to store the endgame value. We have to take care to
/// avoid left-shifting a signed int to avoid undefined behavior.
enum Score : int { SCORE_ZERO };

constexpr Score make_score(int mg, int eg) {
  return Score((int)((unsigned int)eg << 16) + mg);
}

/// Extracting the signed lower and upper 16 bits is not so trivial because
/// according to the standard a simple cast to short is implementation defined
/// and so is a right shift of a signed integer.
inline Value eg_value(Score s) {
  union { uint16_t u; int16_t s; } eg = { uint16_t(unsigned(s + 0x8000) >> 16) };
  return Value(eg.s);
}

inline Value mg_value(Score s) {
  union { uint16_t u; int16_t s; } mg = { uint16_t(unsigned(s)) };
  return Value(mg.s);
}

我正在尝试将mgegint16_t升级到int32_t但我不知道该怎么做,当 ScoreA + ScoreB 破坏分数内的egmg时,我总是遇到麻烦。

这是我尝试但失败的方法:

enum Score : int64_t { SCORE_ZERO };

constexpr Score make_score(int mg, int eg) {
  return Score((int)((uint64_t)eg << 32) + mg);
}

inline Value eg_value(Score s) {
  union { uint32_t u; int32_t s; } eg = { uint32_t(unsigned(s + 0x80000000) >> 32) };
  return Value(eg.s);
}

inline Value mg_value(Score s) {
  union { uint32_t u; int32_t s; } mg = { uint32_t(unsigned(s)) };
  return Value(mg.s);
}

使用memcpy

正如原始解决方案中的评论指出的那样,这种位操作是潜在未定义行为的雷区。 memcpy允许您摆脱这些,并且现代编译器很好理解,因此它仍然会产生高效的机器代码。

enum Score : int64_t { SCORE_ZERO };

enum Value : int32_t { FORTYTWO };

inline Score make_score(int32_t mg, int32_t eg) {
    int64_t combined;
    std::memcpy(&combined, &eg, 4);
    std::memcpy(reinterpret_cast<char*>(&combined) + 4, &mg, 4);
    return Score(combined);
}

inline Value eg_value(Score s) {
    int32_t eg;
    std::memcpy(&eg, &s, 4);
    return Value(eg);
}

inline Value mg_value(Score s) {
    int32_t mg;
    std::memcpy(&mg, reinterpret_cast<char*>(&s) + 4, 4);
    return Value(mg);
}

在godbolt上试试

问题是您仍然有一些“int”和“unsigned”关键字仍然可以转换为 32 位版本。 因此,将每个“int”替换为“int64_t”,将每个“unsigned”替换为“uint64_t”,它应该可以按预期工作。

对于这个问题,这可能是不同的方法

#include<iostream>
#include<cstdint>
#include<bitset>
using namespace std;
int main()
{
    bitset<32> bit32[2] ={ 45 ,-415152545 };
    bitset<64> bit64;
    
    // store in 64 bit varibale
    int index=0;
    int position=0;
    for(int i=0;i<64;i++)
    {
       bit64[i] =bit32[index][i-position];
       if(i==31)
         {   index = 1; position=32; }
    }
    
    // reset 32 bit container ,index and position 
       bit32[2] ={0};
       index=0;
       position=0;
    
    
   // fetching data in 32 bit container from 64 bit and assign it into a and b .
     int32_t a;
     int32_t b;
    for(int i=0;i<64;i++)
    {
       bit32[index][i-position] = bit64[i];
       if(i==31)
         {   index = 1; position=32; }
    }
    
  
    a = bit32[0].to_ulong();
    b = bit32[1].to_ulong();
    cout<<a<<" "<<b;
 
}

您也可以使用联合:

#include <stdint.h>
#include <iostream>


union Score {
    int64_t    u64;
    int32_t    u32[2];

    Score() : u64(0) {}
    Score(int64_t v) : u64(v) {}
    Score(int32_t a, int32_t b): u32{a, b} {}

    Score & operator=(Score const & original) { if(&original != this) { u64 = original.u64; } return *this; }

    int32_t get_a() {return u32[0];}
    int32_t get_b() {return u32[1];}
    int64_t get() {return u64;}

    Score operator+(Score const & other) {
            return Score(u32[0] + other.u32[0], u32[1] + other.u32[1]);
        }

    Score & operator+=(Score const & other) {
            u32[0] += other.u32[0];
            u32[1] += other.u32[1];
            return *this;
        }
};


int main() {

    Score v(-15, 15);

    std::cout << "The size is: " << sizeof(Score) << " Bytes" << std::endl;
    std::cout << "A is: " << v.get_a() << std::endl;
    std::cout << "B is: " << v.get_b() << std::endl;

    std::cout << "adding -5, +5" << std::endl;
    Score v1 = v + Score(-5, 5);
    std::cout << "A is: " << v1.get_a() << std::endl;
    std::cout << "B is: " << v1.get_b() << std::endl;

    std::cout << "adding -10, +10" << std::endl;
    v += Score(-10, 10);
    std::cout << "A is: " << v.get_a() << std::endl;
    std::cout << "B is: " << v.get_b() << std::endl;


    return 0;
}

Output:

The size is: 8 Bytes
A is: -15
B is: 15
adding -5, +5
A is: -20
B is: 20
adding -10, +10
A is: -25
B is: 25

这很简单。

int64_t value;
int32_t* value1 = (int32_t*)&value;
int32_t* value2 = (int32_t*)&value + 1;

例子:

#include <cstdint>


int main() {
    int64_t value;
    int32_t* value1 = (int32_t*)&value;
    int32_t* value2 = (int32_t*)&value + 1;

    *value1 = 10; // Example
    *value2 = 20;

    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM