如何携带找出min(INT_MAX,abs(INT_MIN))?

时间:2015-04-22 20:42:37

标签: c++ c math limits

我怎样才能找到最小的INT_MAX和abs(INT_MIN)? (这是INT_MIN的数学绝对值,而不是对abs函数的调用。)

在大多数系统中,它应该与INT_MAX相同,但我正在寻找一种更便携的方式。

6 个答案:

答案 0 :(得分:23)

虽然INT_MIN典型值为-2147483648,INT_MAX典型值为2147483647,但不保证标准。 TL; DR:在符合要求的实现中,您要搜索的值为INT_MAX。但计算 min(INT_MAX, abs(INT_MIN))并非便携。

INT_MININT_MAX

的可能值

INT_MININT_MAX由附件E(实施限制)1定义(C标准,C ++继承此内容):

  

标题的内容如下所示,按字母顺序排列   订购。显示的最小幅度应替换为   具有相同符号的实现定义的量值。价值观   都是适用于#if预处理的常量表达式   指令。这些组件在5.2.4.2.1中进一步描述。

     

[...]

     

#define INT_MAX +32767

     

#define INT_MIN -32767

     

[...]

标准要求类型int是一个整数类型,可以表示范围[INT_MIN, INT_MAX](第5.2.4.2.1节)。

然后,6.2.6.2。 (整数类型,也是C标准的一部分)发挥作用,并进一步将其限制为我们所知道的两个或一个'补体

  

对于有符号整数类型,对象表示的位应分为三个   groups:值位,填充位和符号位。不需要任何填充位;   signed char不应有任何填充位。应该只有一个符号位。   作为值位的每个位应具有与对象中相同位相同的值   相应无符号类型的表示(如果有符号中有M个值位)   无符号类型中的类型和N,则M≤N)。如果符号位为零,则不应影响结果值。如果符号位为1,则应在其中一个中修改该值   以下方式:

     

- 符号位0的相应值被否定(符号和幅度);

     

- 符号位的值为 - (2M)(二进制补码);

     

- 符号位的值为 - (2M - 1)(补码)。

第6.2.6.2节。将有符号整数类型的值表示与其无符号兄弟的值表示相关联也非常重要。

这意味着,您可以获得范围[-(2^n - 1), (2^n - 1)][-2^n, (2^n - 1)],其中n 通常 15或31。

对有符号整数类型的操作

现在第二件事:对有符号整数类型的操作,导致值不在[INT_MIN, INT_MAX]范围内,行为未定义。这在第5/4段的C ++中明确规定:

  

如果在评估表达式期间,结果未在数学上定义或不在范围内   其类型的可表示值,行为未定义。

对于C,6.5 / 5提供了一个非常相似的段落:

  

如果在评估表达式期间发生异常情况(即,如果出现异常情况)   结果不是数学定义的,也不是在其可表示值的范围内   类型),行为未定义。

那么如果INT_MIN的值恰好小于INT_MAX的负值(例如分别为-32768和32767),会发生什么?计算-(INT_MIN)将是未定义的,与INT_MAX + 1相同。

因此,我们需要避免计算可能不在[INT_MIN, INT_MAX]范围内的值。幸运的是,INT_MAX + INT_MIN始终在该范围内,因为INT_MAX是严格正值而INT_MIN是严格负值。因此INT_MIN < INT_MAX + INT_MIN < INT_MAX

现在我们可以检查INT_MAX + INT_MIN是否等于,小于或大于0.

`INT_MAX + INT_MIN`  |  value of -INT_MIN    | value of -INT_MAX 
------------------------------------------------------------------
         < 0         |  undefined            | -INT_MAX
         = 0         |  INT_MAX = -INT_MIN   | -INT_MAX = INT_MIN
         > 0         |  cannot occur according to 6.2.6.2. of the C standard

因此,要确定INT_MAX-INT_MIN的最小值(在数学意义上),以下代码就足够了:

if ( INT_MAX + INT_MIN == 0 )
{
    return INT_MAX; // or -INT_MIN, it doesn't matter
}
else if ( INT_MAX + INT_MIN < 0 )
{
    return INT_MAX; // INT_MAX is smaller, -INT_MIN cannot be represented.
}
else // ( INT_MAX + INT_MIN > 0 )
{
    return -INT_MIN; // -INT_MIN is actually smaller than INT_MAX, may not occur in a conforming implementation.
}

或者,为了简化:

return (INT_MAX + INT_MIN <= 0) ? INT_MAX : -INT_MIN;

只有在必要时才会评估三元运算符中的值。因此,-INT_MIN要么未被评估(因此不能产生UB),要么是一个明确定义的值。

或者,如果你想要一个断言:

assert(INT_MAX + INT_MIN <= 0);
return INT_MAX;

或者,如果你想在编译时那样:

static_assert(INT_MAX + INT_MIN <= 0, "non-conforming implementation");
return INT_MAX;

正确地进行整数运算(即正确性是否重要)

如果您对安全整数算术感兴趣,请查看我的implementation of safe integer operations。如果要查看哪些操作失败并且成功的模式(而不是这个冗长的文本输出),请选择this demo

根据体系结构的不同,可能还有其他选项可以确保正确性,例如gcc的选项-ftrapv

答案 1 :(得分:10)

-INT_MIN

已编辑添加说明:当然,如果abs(INT_MIN)太大而无法放入{-INT_MIN,则intINT_MAX + INT_MIN < 0将被定义为难度1}}。所以我们需要一些方法来检查是否是这种情况。条件-INT_MIN会测试INT_MAX是否大于INT_MAX。如果是,那么INT_MAX是两个绝对值中较小的一个。如果没有,那么-INT_MIN是两个绝对值中较大的一个,而height: 0; border-width: 0 0 100px 1000px; border-color: transparent red red transparent; border-style: solid; 是正确答案。

答案 2 :(得分:7)

在C99及以上版本中,INT_MAX

规范:

  

对于有符号整数类型,对象表示的位应分为三个   groups:值位,填充位和符号位。不需要任何填充位;   signed char不应有任何填充位。应该只有一个符号位。   作为值位的每个位应具有与对象中相同位相同的值   相应无符号类型的表示(如果有符号中有M个值位)   无符号类型中的类型和N,则M≤N)。如果符号位为零,则不会影响   结果值。如果符号位为1,则应在其中一个中修改该值   以下方式:

     
      
  • 符号位0的对应值被否定(符号和幅度);
  •   
  • 符号位的值为 - (2 ^ M)(二进制补码);
  •   
  • 符号位的值为 - (2 ^ M - 1)(1'补码)。
  •   

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf的第6.2.6.2节)

答案 3 :(得分:1)

据我所知,

-INT_MAX在所有C和C ++方言中都可以表示为int。因此:

-INT_MAX <= INT_MIN ? -INT_MIN : INT_MAX

答案 4 :(得分:0)

在大多数系统上,未定义abs(INT_MIN)。例如,在典型的32位机器上,INT_MAX = 2 ^ 31-1,INT_MIN = - 2 ^ 31,而abs(INT_MIN)不能是2 ^ 31。

答案 5 :(得分:0)

abs(INT_MIN)将调用未定义的行为。标准说

7.22.6.1 abslabsllabs函数:

  

abslabsllabs函数计算整数j的绝对值。如果无法表示结果,则行为未定义。

请尝试这样做:
INT_MIN转换为unsignrd int。由于-ve数字不能表示为unsigned intINT_MAX将转换为UINT_MAX + 1 + INT_MIN

#include <stdio.h>
#include <stdlib.h>

unsigned min(unsigned a, unsigned b)
{
    return a < b ? a : b;
}

int main(void)
{
    printf("%u\n", min(INT_MAX, INT_MIN));
}