当前位置:  开发笔记 > 编程语言 > 正文

正整数乘以负值

如何解决《正整数乘以负值》经验,为你挑选了4个好方法。

我正在通过阅读Stroustrup的"使用C++的原理和实践"来学习C++.

在关于前置和后置条件的部分中,有以下函数示例:

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;
}

困扰我的是关于这段代码的任务:

找到一对值,以便此版本区域的前置条件成立,但后置条件不会.

是否存在整数的可能值,前置条件是可以的但后置条件不是?



1> 小智..:

是否存在整数的可能值,前置条件是可以的但后置条件不是?

是的,有许多输入值,可能导致后置条件失败.如果是

int a = length*width;

溢出正int范围(std::numeric_limits::max())并且编译器实现为这种情况产生负值.


正如其他人在他们的回答中所指出的length*width那样,超出范围的]0-std::numeric_limits::max()[情况实际上是未定义的行为,而后置条件只是无用的,因为可能需要预期任何值a.

解决这个问题的关键点在@Deduplicator的回答中给出,前提条件需要改进.


作为Bjarne Stroustrup给出这个例子的理由的长矛:

我假设他想指出这种未定义的行为可能会导致后置条件中出现意外的负值,并且对于使用前置条件检查的天真假设会产生令人惊讶的结果.


@LightnessRacesinOrbit例如,46000*46000是2116000000,这是在界限内.最高可达47000*47000,你得到-2085967296,超出范围.继续上升到66000,你得到61032704,这是积极的,但不是真正的4356000000区域.
@LightnessRacesinOrbit确实正值不是<= 0.但请记住,后期条件是"返回**是区域**的正值".如果乘法溢出为正整数,则结果为**NOT**区域.
需要纠正.如果溢出产生正值,则后置条件不会保持**甚至**.

2> Sebastian Re..:

不,在标准C++的已定义行为的范围内,没有任何值会违反后置条件.但是,有些值仍然可以使函数表现不正确,即值太大而其产品不适合整数.尝试通过200'000和15'000.

由于大多数编译器实现C++的方式,您可能会看到后置条件被违反,但您实际观察到的是由于整数溢出而导致的未定义行为.



3> Deduplicator..:

答案是他的前提条件检查不完整.即使它太严格了.
他未能检查产品是否可以代表而不是产生UB:

int area(int length, int width) {
    // calculate area of a rectangle
    assert(length >= 0 && width >= 0 && (!width
        || std::numeric_limits::max() / width >= length));
    int a = length * width;
    assert(a >= 0); // Not strictly neccessary - the math is easy enough
    return a;
}



4> cadaniluk..:

我想到的是签名溢出.它是未定义的行为,但可能会产生负值.
尝试std::numeric_limits::max()2.

推荐阅读
大大炮
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有