The behaviour of floating point division by zero

2019-01-14 05:16发布

Consider

#include <iostream>
int main()
{
    double a = 1.0 / 0;
    double b = -1.0 / 0;
    double c = 0.0 / 0;
    std::cout << a << b << c; // to stop compilers from optimising out the code.    
}

I have always thought that a will be +Inf, b will be -Inf, and c will be NaN. But I also hear rumours that strictly speaking the behaviour of floating point division by zero is undefined and therefore the above code cannot considered to be portable C++. (That theoretically obliterates the integrity of my million line plus code stack. Oops.)

Who's correct?

Note I'm happy with implementation defined, but I'm talking about cat-eating, demon-sneezing undefined behaviour here.

7条回答
何必那么认真
2楼-- · 2019-01-14 05:45

This also depends on the floating point environment.

cppreference has details: http://en.cppreference.com/w/cpp/numeric/fenv (no examples though).

This should be available in most desktop/server C++11 and C99 environments. There are also platform-specific variations that predate the standardization of all this.

I would expect that enabling exceptions makes the code run more slowly, so probably for this reason most platforms that I know of disable exceptions by default.

查看更多
太酷不给撩
3楼-- · 2019-01-14 05:49

C++ standard does not force the IEEE 754 standard, because that depends mostly on hardware architecture.

If the hardware/compiler implement correctly the IEEE 754 standard, the division will provide the expected INF, -INF and NaN, otherwise... it depends.

Undefined means, the compiler implementation decides, and there are many variables to that like the hardware architecture, code generation efficiency, compiler developer laziness, etc..

Source:

The C++ standard state that a division by 0.0 is undefined

C++ Standard 5.6.4

... If the second operand of / or % is zero the behavior is undefined

C++ Standard 18.3.2.4

...static constexpr bool is_iec559;

...56. True if and only if the type adheres to IEC 559 standard.217

...57. Meaningful for all floating point types.

C++ detection of IEEE754:

The standard library includes a template to detect if IEEE754 is supported or not:

static constexpr bool is_iec559;

#include <numeric>
bool isFloatIeee754 = std::numeric_limits<float>::is_iec559();

What if IEEE754 is not supported?

It depends, usually a division by 0 trigger a hardware exception and make the application terminate.

查看更多
Lonely孤独者°
4楼-- · 2019-01-14 05:51

As to the submitter's question 'Who's correct?', it is perfectly OK to say that both answers are correct. The fact that the C standard describes the behavior as 'undefined' DOES NOT dictate what the underlying hardware actually does; it merely means that if you want your program to be meaningful according to the standard you -may not assume- that the hardware actually implements that operation. But if you happen to be running on hardware that implements the IEEE standard, you will find the operation is in fact implemented, with the results as stipulated by the IEEE standard.

查看更多
Anthone
5楼-- · 2019-01-14 05:54

Division by 0 is undefined behavior.

From section 5.6 of the C++ standard (C++11):

The binary / operator yields the quotient, and the binary % operator yields the remainder from the division of the first expression by the second. If the second operand of / or % is zero the behavior is undefined. For integral operands the / operator yields the algebraic quotient with any fractional part discarded; if the quotient a/b is representable in the type of the result, (a/b)*b + a%b is equal to a .

No distinction is made between integer and floating point operands for the / operator. The standard only states that dividing by zero is undefined without regard to the operands.

查看更多
在下西门庆
6楼-- · 2019-01-14 06:01

Quoting cppreference:

If the second operand is zero, the behavior is undefined, except that if floating-point division is taking place and the type supports IEEE floating-point arithmetic (see std::numeric_limits::is_iec559), then:

  • if one operand is NaN, the result is NaN

  • dividing a non-zero number by ±0.0 gives the correctly-signed infinity and FE_DIVBYZERO is raised

  • dividing 0.0 by 0.0 gives NaN and FE_INVALID is raised

We are talking about floating-point division here, so it is actually implementation-defined whether double division by zero is undefined.

If std::numeric_limits<double>::is_iec559 is true, and it is "usually true", then the behaviour is well-defined and produces the expected results.

A pretty safe bet would be to plop down a:

static_assert(std::numeric_limits<double>::is_iec559, "Please use IEEE754, you weirdo");

... near your code.

查看更多
倾城 Initia
7楼-- · 2019-01-14 06:02

In [expr]/4 we have

If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined. [ Note: most existing implementations of C++ ignore integer overflows. Treatment of division by zero, forming a remainder using a zero divisor, and all floating point exceptions vary among machines, and is usually adjustable by a library function. —end note ]

Emphasis mine

So per the standard this is undefined behavior. It does go on to say that some of these cases are actually handled by the implementation and are configurable. So it won't say it is implementation defined but it does let you know that implementations do define some of this behavior.

查看更多
登录 后发表回答