【问题标题】:How does c++ represent negative valuec++如何表示负值
【发布时间】:2015-07-13 17:57:43
【问题描述】:

据我所知,signed int 的二进制等价物是 11111111111111111111111111111111
并基于此,我试图在不使用limits.h 头文件的情况下为我的程序设置Maximum 和Minimum int 值。运行下面的代码后,我得到最小值为 -2147483648,最大值为 0。下面是我的代码:

int MaxInt(){
      int MAX = -1;
      MAX = 0 << ((sizeof(int)*8)-1);

     return MAX;
}


int MinInt(){
      int MIN = 0;
      MIN  = 1 << ((sizeof(int)*8)-1);

     return MIN;
}

我的实现有什么问题。

【问题讨论】:

  • limits 有什么问题?你为什么要重新实现它?
  • "signed int 的二进制等价物是 11111111111111111111111111111111" - 这是什么意思?你想说“签名它有 32 位”吗?
  • 是的,这是 32 位有符号整数 @anatolyg
  • 不,这个:11111111111111111111111111111111 不是有符号整数,除非你声明它是(它也可能是无符号整数!),即使那样它也是有符号整数 表示对于单个特定值 - 通常不是 有符号整数

标签: c++ bit-manipulation


【解决方案1】:

你的实现有几个错误:

首先,您的 -1 表示假定 int 具有二进制补码 32 位表示。 int 无法保证这一点。 (这是给std::int32_t的。)

其次,您假设int 具有sizeof(int)*8 位。这一点也不能保证。

在所有这些假设下,您的实现仍然存在错误:

0 << ((sizeof(int)*8)-1);

可以写成(数学上,而不是 C++):

0 * 2**((sizeof(int)*8)-1)

现在,如您所知,将某物与0 相乘得到0

假设给出二进制补码,下面的简单实现应该可以工作:

MIN = -1 << ((sizeof(int)*8)-1);
MAX = ~MIN;

【讨论】:

  • MAX = ~MIN 不正确(几乎正确); 1 &lt;&lt; ((sizeof(int)*8)-1) 调用未定义的行为(int 溢出);几乎总是可以工作,但不能保证 - 最好使用 -1 而不是 1
  • @anatolyg 请实际阅读详细说明 OP 假设有多么错误的答案。 Given the assumptions of the OP, the program is correct.
  • 抱歉,MAX = ~MIN 部分我错了 - 绝对没问题。尽管如此,不应该依赖int 溢出的结果,尤其是如果它很容易修复(另外,如果答案被编辑,只能删除反对票)。
【解决方案2】:

在函数中

int MaxInt(){
      int MAX = -1;
      MAX = 0 << ((sizeof(int)*8)-1);

     return MAX;
}

您首先将 -1 分配给 MAX,然后覆盖了它的值。所以这个任务没有意义。

此外,如果向左移动 0,那么您将再次获得 0,这取决于您将 0 移动多长时间。:)

对于 2 的补码内部表示,获取 int 类型对象的最大值的最简单方法如下

int MaxInt()
{
    int MAX = -1u >> 1;
    return MAX;
}

或者你可以简单地写

int MaxInt()
{
    return -1u >> 1;
}

这是一个演示程序

#include <iostream>

constexpr int MaxInt()
{
    return -1u >> 1;
}

constexpr int MinInt()
{
    return ~( -1u >> 1 );
}

int main()
{
    std::cout << MaxInt() << std::endl;
    std::cout << MinInt() << std::endl;
} 

程序输出可能看起来像

2147483647
-2147483648   

【讨论】:

  • 我如何将 0 设为 MSB?
  • @Maruf 对不起,我没有理解这个问题。至于我在帖子中展示的函数,当 -1u 右移一位时,符号位将填充为零。
  • 对于负数,MSB位确定天气一个数字是正数还是负数,在二进制表示中-1相当于所有位都是1包括MSB,我尝试将MSB位设置为0,所以这个数字是正数
  • @Maruf 我在我的帖子中向您展示了如何做到这一点。有什么问题?
  • 我了解您的实施,我刚刚澄清了我的问题。
【解决方案3】:

我的实现有什么问题

MAX = 0 << ((sizeof(int)*8)-1);

将零移任意量将始终为零。

【讨论】:

  • 你也可以通过移动一定数量来调用UB。
【解决方案4】:

这不是特定于 C++ 的,而是关于 2 的补码形式。在 2 的补码中,最高有效位不仅仅表示符号(该值为负),而是 2 的幂(即,对于 8 位 2 的补码,最高有效位将表示 - 2^7)。

要制作最负数,只需设置最高有效位。

  // Disclaimer: this should work for *most* devices, but it
  // is device-specific in that I am assuming 2's complement
  // and I am also assuming that a char is 8-bits. In theory,
  // you might find a custom chip where this isn't true,
  // but any popular chip will probably have this behavior:

  int number_of_digits_in_int = sizeof(int) * 8;
  int most_significant_digit_index = number_of_digits_in_int - 1;
  int most_negative_int = 1 << most_significant_digit_index;

为了得到最大的正数,应该设置所有的正数:

  // The complement of 0 has all bits set. This value, by the way
  // is the same as "-1" in 2s complement form, but writing it
  // this way for clarity as to its meaning.
  int all_bits_set = ~(static_cast<int>(0));

  // Using an XOR with the most negative integer clears the
  // most-signficant sign bit, leaving only positive bits.
  int largest_positive_int = all_bits_set ^ most_negative_int;

或者,更简单地说:

  // Since the most negative integer has only the negative bit set,
  // its complement has only the positive bits set.
  int largest_positive_int = ~most_negative_int;

不过,正如其他人所说,您应该只使用std::numeric_limits。这也将使您的代码具有可移植性,甚至可以在不使用 2s 补码的非常奇怪的设备上工作,更不用说您自己编写的代码越少,您所犯的错误就越少。

【讨论】:

  • 而不是all_bits_set ^ whatever,使用~whatever - 这样更清楚。另外,(int)0 有点尴尬(选角没用)。
猜你喜欢
  • 1970-01-01
  • 2011-10-02
  • 1970-01-01
  • 2011-04-26
  • 2020-10-13
  • 2016-02-20
  • 1970-01-01
  • 2015-05-26
  • 2014-10-06
相关资源
最近更新 更多