乘为负值的正整数 我通过阅读Stroustrup的“C++原理与实践”来学习C++。
在关于前置和后置条件的部分中,有以下函数示例:乘为负值的正整数 我通过阅读Stroustrup的“C++原理与实践”来学习C++。,c++,integer,C++,Integer,在关于前置和后置条件的部分中,有以下函数示例: int area(int length, int width) // calculate area of a rectangle; // pre-conditions: length and width are positive // post-condition: returns a positive value that is the area { if (length<=0 || width <=0) e
int area(int length, int width)
// calculate area of a rectangle;
// pre-conditions: length and width are positive
// post-condition: returns a positive value that is the area
{
if (length<=0 || width <=0)
error("area() pre-condition");
int a = length*width;
if (a<=0)
error("area() post-condition");
return a;
}
int区域(int长度、int宽度)
//计算矩形的面积;
//前提条件:长度和宽度为正
//post条件:返回一个正的值,该值表示面积
{
如果(长度)
整数是否存在这样的可能值,即前置条件可以,而后置条件不能
是的,有许多输入值,可能导致post条件失败
int a = length*width;
溢出正的int
范围(std::numeric\u limits::max()
),编译器实现在这种情况下产生负值
正如其他人在回答中指出的那样,length*width
超出]0-std::numeric_limits::max()[
的范围实际上是未定义的行为,post条件仅仅是无用的,因为a
可能需要任何值
解决这一问题的关键点是在年代,前提条件需要改进
作为比亚恩·斯特劳斯图普给出该示例的理由:
我想他想指出,这种未定义的行为可能会导致post条件中出现意外的负值,并导致使用前置条件检查的天真假设的意外结果。我想到的是有符号溢出。这是未定义的行为,但可能会产生负值。
尝试std::numeric\u limits::max()<代码> > 2 > <代码> .< /p> < p>不,没有任何值,在标准C++的定义行为范围内,违反了后条件。但是,仍然有一些函数会使函数行为不正确,即值太大,以致于它们的产品不适合于一个整数。尝试通过200和15。
<> P>由于大多数编译器实现C++,您可能会看到后条件被违反,但是实际上观察到的是由于整数溢出而导致的未定义行为。如果您使用的是16位计算机,那么INT/2P>YES,那么INT= 2B MAX值+ 32767,因此在下面的
{
length = 500, width = 100;
if (length<=0 || width <=0) error("area() pre-condition");
int a = length*width; // a = 500 * 100 = 50000
if (a<=0) error("area() post-condition");
return a;
}
{
长度=500,宽度=100;
如果(长度用于所有符合要求的编译器的长度和宽度,则不能满足post条件
有人可能会说,由于标准保证INT\u MAX
>=32767,那么INT\u MAX*INT\u MAX
将始终大于INT\u MAX
,因此不能表示为INT
,而INT
定义为能够保持INT\u MAX
的最大值
这是一个很好的参数,实际上它是最经常发生的情况,大多数编译器都会出现溢出
但为了涵盖所有基础,我们需要意识到,各州:
3.4.3
1未定义的行为
使用不可移植或错误的程序结构或错误的数据时的行为,本国际标准对此不作要求
2注:可能的未定义行为范围从完全忽略具有不可预测结果的情况,到在翻译或程序执行期间以环境特有的记录方式进行行为
(无论是否发出诊断消息),终止转换或执行(发出诊断消息)
3示例未定义行为的一个示例是整数溢出行为
因此,这比没有获得正确的区域值要严重一些。当长度和宽度都使用INT_MAX
时(或任何其他组合,其结果无法表示)无法保证编译后的程序会做什么。任何事情都可能发生,从可能发生的溢出或崩溃到不可能发生的磁盘格式。答案是他的前提条件检查不完整。尽管它限制太多。
他未能包括一项检查,以确保产品能够代表,而不是导致UB:
int area(int length, int width) {
// calculate area of a rectangle
assert(length >= 0 && width >= 0 && (!width
|| std::numeric_limits<int>::max() / width >= length));
int a = length * width;
assert(a >= 0); // Not strictly neccessary - the math is easy enough
return a;
}
int区域(int长度、int宽度){
//计算矩形的面积
断言(长度>=0&&width>=0&&width
||std::numeric_limits::max()/width>=length));
int a=长度*宽度;
assert(a>=0);//严格来说这不是必需的-数学很简单
返回a;
}
值类型的位表示溢出的值的乘法未定义,因为溢出的位数可能超过1。因此,您可能会得到正号或负号位,并且丢失的位数是可变的
示例1:INT_MAX*2
:结果是正确的,但由于高位代表符号位,因此未针对其类型进行更正
示例2:INT_MAX*4
:1位因溢出而丢失,符号位不正确,如前一示例所示
示例3:(INT_MAX+1)*2=0
:由于所有设置位溢出,但符号正确
我正在使用8位二进制表示,以使其更易于阅读,从而说明为什么会发生这种情况
0111 1111 // Max positive signed value
+1
1000 0000 // Sign bit set but binary value is correct
*2
0000 0000 // Upper bit is lost due to overflow
在这种情况下,既有软溢出,没有丢失信息,但表示不正确,也有硬溢出,即结果中不再存在位
溢出的不同之处在于如何检测溢出。通常硬件会检测到硬溢出,软件只需很少的工作即可处理。但是,软件溢出可能需要软件显式测试溢出情况,因为硬件通常无法识别中的符号位整数数学运算
运行时库如何处理溢出取决于库。大多数库会忽略它,因为这样做更快,而其他库可能会抛出错误。
未定义的行为不适合我
std::numeric_limits<int>::is_modulo
bool multiplication_is_safe(uint32_t a, uint32_t b) {
size_t a_bits=highestOneBitPosition(a), b_bits=highestOneBitPosition(b);
return (a_bits+b_bits<=32);
}