c++ - 如何在一个 64 位整数中存储和使用两个 32 位带符号整数?
问题描述
首先,我想澄清一下,这个问题与问题不同:
这个问题是 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);
}
我正在尝试升级mg
和eg
从int16_t
到,int32_t
但我不知道该怎么做,当 ScoreA + ScoreB 破坏分数时,我总是遇到eg
麻烦mg
。
这是我尝试但失败的方法:
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);
}
推荐阅读
- c - 如何修复将 rlim_cur 设置为 7 后创建的无限子进程
- electron - 如何将动作的有效负载传递给 redux-observable 中的另一个 rxjs 运算符?
- javascript - 如何使节点 js 文件在 linux 中的某个时间在某个日期运行?
- javascript - 如何从 javascript 将变量发布到 Laravel 5 路由?
- php - 为什么我得到一个未定义的变量,只有 6 个变量中的 1 个,而其他所有变量都有效?
- web - 网页部署
- php - 我想用 PHP 自动重命名文件
- vhdl - 其他泛型参数使用的 vhdl 泛型参数(错误:泛型“参数”在此处不可见)
- javascript - 从下拉菜单选择填充文本字段
- python - 如何按名称从 Glue DynamicFrame 中检索字段值