【问题标题】:Best Algorithm to calculate maximum value of unsigned int without limits.h无限制计算无符号整数最大值的最佳算法.h
【发布时间】:2019-11-13 21:19:10
【问题描述】:

有没有办法在不使用limits.h 的情况下计算unsigned int 可表示的最大值 (所以没有UINT_MAX)或不使用

unsigned int z = 0;
z = z - 1;

【问题讨论】:

  • 不清楚你想要什么。 static_cast<unsigned int>(-1) 给出了一个编译时常量。还有什么比这更好的呢?..
  • 解释起来很复杂,因为对我来说这是最好的方法,但我的老师不接受它......我知道该怎么做......他说:算法是根据你不接受的假设制定的'不知道变量......我知道这意味着什么
  • 你的意思是无符号整数可以存储的最大数吗?
  • ~0u 物超所值。
  • @Jason,我不了解 C,但在 C++ 中它是完美定义的。无符号类型已经是 2 的补码,有符号的类型在 C++20 中将是 2 的补码。

标签: c


【解决方案1】:

执行此操作的最简单方法是将 -1 分配给 unsigned int。你也可以给它分配~0u

如果这是不可接受的,虽然效率低,你可以这样做:

unsigned int i = 0;
while (i+1 > 0) 
  i++;
printf("i=%u\n", i);

【讨论】:

  • 根据this,这个sn-p 永远不会终止吗?
  • @Fureeish 它确实终止了。无符号整数类型会环绕,所以最终i+1 将是 0。
  • 没错,我的疏忽。
  • 我会接受这个答案,我知道这不是最好的解决方案,但这可以满足我的要求(我的老师正在寻找)。
  • -1 绝对比~0 好。该标准保证-1 在转换为无符号类型时将始终给出最大可能值。 ~0 不提供这样的保证。事实上,它只有在 ~0 恰好产生 -1(作为有符号数)时才有效,然后转换为无符号类型的最大值。
【解决方案2】:

您的z = z - 1 在运行时以算术方式确定值。它可以被确定为编译时间常数,无需隐式或显式转换:

unsigned int z = ~0u ;

如果他有任何可信度,那将是你的导师所寻找的。​​p>

否则,如果你真的必须提供一个“算法”来在明显有缺陷的作业中获得分数,那么;

unsigned z = 1 ;
for( unsigned b = 1; 
     b != 0; 
     z = (z << 1) | 1, b <<= 1 ) ; 

printf( "z = %u\n", z ) ;

这是一种有点简洁的写作方式:

unsigned z = 1 ;       // Initial set LSB of max-int to 1
for( unsigned b = 1;   // "Walk" a 1 through each bit of an unsigned
     b != 0;           // until the 1 falls of the end
     b <<= 1 )         // move the 1 right
{
     z = (z << 1) | 1 ; // shift max-int right and set LSB to 1
} 

另一种选择:

unsigned z = 1 ;
unsigned p = 0 ;
while( z != p )
{
    z = (z << 1) | 1 ;
    p = (p << 1) | 1 ;
}

在此解决方案中,pz 少一位,直到它们相等时都为“全一”。

这些循环方法唯一可能的优点是通过添加一个计数器可以同时确定最大值和位宽:

unsigned z = 1 ;
unsigned bits = 0 ;
for( unsigned b = 1; 
     b != 0; 
     z = (z << 1) | 1, b <<= 1, bits++ ) ; 

printf( "z = %u %u-bits\n", z, bits ) ;

【讨论】:

  • 你能解释一下吗
  • 有趣,我以为我已经编辑过了。现在更正了。 &lt;&lt;=shift-right-and-assignb &lt;&lt;= 1b = b &lt;&lt; 1 相同。它将所有位右移 1。z = (z &lt;&lt; 1) | 1 将 s 右移 1,然后将空出的 LSB 设置为 1 - 一次用 1 的一位填充 z。逗号运算符只是一种组合几个独立子表达式的方法,其中只有一个表达式有效。这是故意简洁的代码。我将添加一个简化的扩展。
  • 注意@JerryCoffin 对~0(unsigned)-1 的评论。前者假定一个 2 的补码系统(只有几乎普遍正确 - 但对于您可能曾经在 C 上编码的任何硬件可能都是正确的)。也就是说,位移方法做出了相同的假设,但至少它会在合理的时间内完成!
【解决方案3】:

(unsigned int)(-1)static_cast&lt;unsigned int&gt;(-1) 保证提供unsigned int 可表示的最大值。这些是编译时常量。

【讨论】:

  • @Singh,那么你应该澄清你的问题。
【解决方案4】:

我猜这是一个学术问题,基于不了解程序将在其上运行的计算机的底层架构。例如。在 80 年代,我们有 8 位计算机,然后转移到 16 位,然后是 32 位,现在是 64 位。 (认为​​可能有 128 位)。

下面的公式计算最大值

int max = pow(2, 分配给数据类型的位数) — 1;

例如对于 8 位,你得到 2^8 - 1 = 255

要获取可用于 unsigned int 类型的字节数,请使用 sizeof。 sizeof 是 c 核心语言的一部分,所以不需要limits.h

【讨论】:

    【解决方案5】:

    所以这很容易,C 和 C++ 都有函数sizeof。这将返回此类型变量所需的字节数。所以例如在我的系统上

    sizeof(int) 将返回 4。因此需要 4 个字节来存储 int 值。

    现在要计算可以适合此变量的最大数字,您首先需要确定该变量是signed 还是unsigned

    为什么?有符号变量(意味着它也可以存储负值)使用其内存的第一位来指示它是正数还是负数。

    顾名思义,unsigned int 就是unsigned。因此,您的计算将如下所示: 2^(sizeof(unsigned int) * 8) - 1

    为什么? sizeof 返回变量需要的字节数,但此计算仅适用于位。因为1 Byte = 8 Bit 你必须乘以 8。 为什么-1?您的计算机从 0 开始计数,而不是从 1 开始计数。

    如果您想计算可存储在有符号变量中的最大数字,您可以这样计算: 2^(sizeof(int) * 8 - 1) - 1

    但这只是一半,您的签名变量存储来自-some amount to +some amount 对吗?所以2^(sizeof(int) * 8 - 1) - 1 是你的上限,-2^(sizeof(int) * 8 - 1) + 1 是你的下限。

    【讨论】:

    • sizeof 不会告诉您unsigned int 中有多少值位,因为可能有填充位,并且一个字节中可能有超过八位。
    • 真的吗?一个字节超过八位?不寻常的事情存在并不意味着没有一般情况!
    • 试过了,但没用,也许我做错了什么... unsigned int j = 0 ; j = 2^(sizeof(unsigned int)*8)-1; printf("j = %u\n",j);
    • @user11914177 哦,我忘了啊哈,反正我很糟糕,谢谢
    • 是的,真的。这是一个学术问题——这就是限制不使用&lt;limits.h&gt; 的原因,并且评论证实它是由老师提出的。这意味着答案应该基于 C 标准的属性,而不是常见的实现,因此您不应假设缺少填充位或字节中的位数。
    猜你喜欢
    • 2011-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多