Programing

C ++ 경고 : double을 0으로 나누기

lottogame 2020. 8. 23. 09:37
반응형

C ++ 경고 : double을 0으로 나누기


사례 1 :

#include <iostream>

int main()
{
    double d = 15.50;
    std::cout<<(d/0.0)<<std::endl;
}

경고없이 컴파일되고 인쇄 inf됩니다. 좋아요, C ++는 0으로 나누기를 처리 할 수 ​​있습니다 ( 라이브 참조 ).

그러나,

사례 2 :

#include <iostream>

int main()
{
    double d = 15.50;
    std::cout<<(d/0)<<std::endl;
}

컴파일러는 다음 경고를 표시합니다 (라이브 참조 ).

warning: division by zero [-Wdiv-by-zero]
     std::cout<<(d/0)<<std::endl;

두 번째 경우 컴파일러가 경고를 표시하는 이유는 무엇입니까?

인가 0 != 0.0?

편집하다:

#include <iostream>

int main()
{
    if(0 == 0.0)
        std::cout<<"Same"<<std::endl;
    else
        std::cout<<"Not same"<<std::endl;
}

산출:

Same

0으로의 부동 소수점 나누기는 IEEE에 의해 잘 정의되고 무한대를 제공합니다 (분자 값에 따라 양수 또는 음수 (또는 NaN± 0) ).

정수의 경우 무한대를 나타낼 수있는 방법이 없으며 언어는 정의 되지 않은 동작을 가지 도록 연산을 정의 하므로 컴파일러가 해당 경로에서 벗어나도록 도와줍니다.

그러나이 경우 분자가이므로 double제수 ( 0)도 double로 승격되어야하며 여기에 경고를 표시하지 않고 경고 할 이유가 없으므로 이것이 0.0컴파일러 버그라고 생각합니다.


표준 C ++에서 두 경우 모두 정의되지 않은 동작 입니다. 하드 드라이브 포맷을 포함하여 모든 일이 발생할 수 있습니다. "return inf. Ok"또는 다른 행동을 기대하거나 의존해서는 안됩니다.

컴파일러는 분명히 한 경우에는 경고를 제공하고 다른 경우에는 경고를 제공하지 않기로 결정했지만 이것이 하나의 코드는 정상이고 다른 하나는 그렇지 않다는 의미는 아닙니다. 컴파일러의 경고 생성의 특징 일뿐입니다.

C ++ 17 표준 [expr.mul] / 4에서 :

이항 /연산자는 몫을 산출하고 이항 %연산자는 첫 번째 표현식을 두 번째로 나눈 나머지를 산출합니다. 또는 의 두 번째 피연산자 가 0이면 동작이 정의되지 않습니다./%


답변을 내 추측 이 특정 문제는 경고가 컴파일러가 방출 될 전에 의 변환을 수행 int하는 double.

따라서 단계는 다음과 같습니다.

  1. 식 구문 분석
  2. 산술 연산자 /(T, T2) , 여기서 T=double, T2=int.
  3. 그 확인 std::is_integral<T2>::value입니다 trueb == 0이 트리거 경고 -을.
  4. 경고 방출
  5. 의 암시 적 변환 수행 T2에를double
  6. 잘 정의 된 분할을 수행합니다 (컴파일러가 IEEE 754를 사용하기로 결정했기 때문에).

This is of course speculation and is based on compiler-defined specifications. From standard point of view, we're dealing with possible Undefined Behaviours.


Please note that this is expected behaviour according to GCC documentation
(btw. it seems that this flag can't be used explicitly in GCC 8.1)

-Wdiv-by-zero
Warn about compile-time integer division by zero. This is default. To inhibit the warning messages, use -Wno-div-by-zero. Floating point division by zero is not warned about, as it can be a legitimate way of obtaining infinities and NaNs.


I will not go into the UB / not UB debacle in this answer.

I just want to point that 0 and 0.0 are different despite 0 == 0.0 evaluating to true. 0 is an int literal and 0.0 is a double literal.

However in this case the end result is the same: d/0 is floating point division because d is double and so 0 is implicitly converted to double.


I would argue that foo/0 and foo/0.0 are not the same. Namely, the resulting effect of the first (integer division or floating point division) is highly dependant on the type of foo, while the same is not true for the second (it will always be a floating point division).

Whether any of the two is UB is irrelevant. Quoting the standard:

Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).

(Emphasis mine)

Consider the "suggest parentheses around assignment used as truth value" warning: The way to tell the compiler that you really want to use the result of an assignment is by being explicit, and adding parenthesis around the assignment. The resulting statement has the same effect, but it tells the compiler you know what you're doing. The same can be said about foo/0.0: Since you're explicitly telling the compiler "This is floating point division" by using 0.0 instead of 0, the compiler trusts you and will not issue a warning.


This looks like a gcc bug, the documentation for -Wno-div-by-zero clearly says:

Do not warn about compile-time integer division by zero. Floating-point division by zero is not warned about, as it can be a legitimate way of obtaining infinities and NaNs.

and after Usual arithmetic conversions covered in [expr.arith.conv] both operands will be double:

Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions, which are defined as follows:

...

Otherwise, if either operand is double, the other shall be converted to double.

and [expr.mul]:

The operands of * and / shall have arithmetic or unscoped enumeration type; the operands of % shall have integral or unscoped enumeration type. The usual arithmetic conversions are performed on the operands and determine the type of the result.

With respect to whether floating point divide by zero is undefined behavior and how different implementation deal with it seem my answer here. TL;DR; It looks like gcc conforms to Annex F wrt to floating point divide by zero, so undefined does not play a role here. The answer would be different for clang.


Floating point division by zero behaves differently than integer division by zero.

The IEEE floating point standard differentiates between +inf and -inf, while integers cannot store infinity. Integer division by zero result is undefined behaviour. Floating point division by zero is defined by the floating point standard and results in +inf or -inf.

참고URL : https://stackoverflow.com/questions/51474239/c-warning-division-of-double-by-zero

반응형