【问题标题】:Can not flip sign不能翻转标志
【发布时间】:2018-08-12 07:36:03
【问题描述】:

当我尝试翻转数字 -9223372036854775808 的符号时,我发现了一个奇怪的错误,它根本没有任何作用。 我得到了相同的数字,或者至少这是调试器显示给我的。 有没有办法在不分支的情况下解决这个问题?

#define I64_MAX  9223372036854775807LL
#define I64_MIN  (-I64_MAX-1) 
// -9223372036854775808 (can not be a constant in code as it will turn to ull)

using i64 = long long int;

int main()
{
 i64 i = I64_MIN;
 i = -i;
 printf("%lld",i);
 return 0;
}

对 i32,i16,i8 做同样的事情。


编辑:
当前修复:
// use template??
c8* szi32(i32 num,c8* in)
{
    u32 number = S(u32,num);
    if(num < 0)
    {
        in[0] = '-';
        return SerializeU32(number,&in[1]);
    }
    else
    {
        return SerializeU32(number,in);
    }
} 

【问题讨论】:

  • 好吧,你在那里导致了未定义的行为。 -I64_MIN 不能由您的 long long int 代表。你希望结果是什么?
  • 我知道您希望答案是肯定的,但您希望它是什么数值?
  • 您是否尝试过使用转换器?您很快就会发现 9223372036854775808 是一个 65 位(有符号)数字,您希望它如何适应 64 位?
  • @MikeBorkland using 是 C++。用与 OP 使用的语言不同的语言对其进行标记有什么意义?
  • @MikeBorkland OP 正在使用 C++,他对此有疑问。完全不同的语言恰好在这里具有相同的行为这一事实完全无关紧要。为什么应该使用错误语言的 OP 标签?

标签: c++ macos numbers int signed


【解决方案1】:

您无法以完全可移植的方式进行操作。让我们考虑int8_t,而不是处理int64_t。原理几乎完全相同,但数字更容易处理。 I8_MAX 将是 127,I8_MIN 将是 -128。否定 I8_MIN 将得到 128,并且无法将其存储在 int8_t 中。

除非你有强有力的证据证明这是一个瓶颈,那么正确的答案是:

constexpr int8_t negate(int8_t i) {
    return (i==I8_MIN) ? I8_MAX : -i;
}

如果您确实有这样的证据,那么您将需要调查一些依赖于平台的代码 - 可能是某种编译器内在函数,也可能是一些避免条件跳转的巧妙操作。


编辑:可能的无分支位旋转

constexpr int8_t negate(int8_t i) {
    const auto ui = static_cast<uint8_t>(i); 
    // This will calculate the two's complement negative of ui.
    const uint8_t minus_ui = ~ui+1;
    // This will have the top bit set if, and only if, i was I8_MIN
    const uint8_t top_bit = ui & minus_ui;
    // Need to get top_bit into the 1 bit.  Either use a compiler intrinsic rotate:
    const int8_t bottom_bit = static_cast<int8_t>(rotate_left(top_bit)) & 1;
    // -or- hope that your implementation does something sensible when you
    // shift a negative number (most do).
    const int8_t arithmetic_shifted = static_cast<int8_t>(top_bit) >> 7;
    const int8_t bottom_bit = arithmetic_shifted & 1;
    // Either way, at this point, bottom_bit is 1 if and only if i was
    // I8_MIN, otherwise it is zero.
    return -(i+bottom_bit);
}

您需要进行分析以确定这是否实际上更快。另一种选择是将top_bit 移入进位位,并使用add-with-carry(添加一个常数零),或将其写入汇编程序,并使用适当的条件执行指令。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-23
    • 1970-01-01
    • 2013-09-06
    • 1970-01-01
    • 2011-03-22
    • 2011-03-23
    • 1970-01-01
    相关资源
    最近更新 更多