두 개의 int를 나누면 double에 할당 될 때 올바른 값이 생성되지 않는 이유는 무엇입니까?


110

다음 스 니펫에서 어떻게

int a = 7;
int b = 3;
double c = 0;
c = a / b;

c예상대로 2.3333이 아닌 2의 값을 갖게됩니다. 경우 ab복식이다, 대답은 2.333로 전환 않습니다. 그러나 확실히 c 이미 double 이기 때문에 정수로 작업해야 했습니까?

그래서 어떻게 int/int=double작동하지 않습니까?


답변:


161

당신의 정수 나누기 버전을 사용하고 있기 때문이다 operator/이 개 소요 int들과를 반환합니다 int. double를 반환하는 버전 을 사용하려면 s double중 하나 이상을 int명시 적으로 double.

c = a/(double)b;

9
명확성 을 위해 둘 다 명시 적으로 a및 로 변환하는 것을 선호 하지만 실제로는 중요하지 않습니다. bdouble
John Dibling 2011 년

31
질문에 C ++ 태그가 지정되어 있으므로 C 캐스트보다 static_cast <>를보고 싶습니다.
Martin York

16
개인적으로 저는 C 스타일 캐스트가 더 명확하다고 느낍니다 (대부분의 다른 일반적인 언어로 캐스팅은 C 스타일 방식으로 수행됩니다). static_cast<>항상 나에게 긴 바람처럼 보였다. 프리미티브의 경우 static_cast<>, reinterpret_cast<>혼동 될 위험이 전혀 없습니다 .
Chad La Guardia

6
@ Tux-D : 산술 캐스트를 위해? static_cast이 경우 피하고 대신 C 스타일 캐스트를 사용하는 것이 좋습니다. 여기에서 C ++ 스타일 캐스트를 사용하는 것에는 이점이 없으며 C 스타일 캐스트보다 코드를 훨씬 더 복잡하게 만듭니다. 산술 캐스트는 C 스타일 캐스트가 완벽하게 적절하고 실제로 다른 캐스트보다 더 적절한 컨텍스트입니다.
AnT 2011 년

19
때때로 당신은 "no C-style-cast"사람들을 능가 할 수 있습니다 double(b). 명시 적 생성자 호출과 동일 해 보이기 때문에 항상 변환이라는 것을 인식하지는 않습니다.
Steve Jessop 2011 년

12

여기있어:

a) 둘로 나누기 int s를 항상 정수 나누기가 수행됩니다. 따라서 a/b귀하의 경우 결과 는 int.

유지하려는 경우 ab같이 int완전히 그들을의, 아직 분할, 당신은 두 배로 그들 중 적어도 하나에 캐스팅해야합니다 (double)a/b또는a/(double)b 또는 (double)a/(double)b.

b) cA는 double그것을 수 있도록 허용int assignement의 값을 다음은int 자동으로 변환된다 double및 할당 c.

c) 할당시의 오른쪽에있는 표현식 =먼저 계산 된 다음 (위의 규칙 (a)에 따라 왼쪽에있는 변수에 관계없이 =) 다음= (에 따라) 의 왼쪽에있는 변수에 할당됩니다. b) 위). 나는 이것이 그림을 완성한다고 믿는다.


11

아주 적은 예외 (하나만 생각할 수 있음)를 제외하고 C ++는 표현식 자체에서 표현식 (또는 하위 표현식)의 전체 의미를 결정합니다. 표현의 결과로 무엇을하든 상관 없습니다. 귀하의 경우에는 표현 a / b에서 a double가 보이지 않습니다 . 모든 것이입니다 int. 따라서 컴파일러는 정수 나누기를 사용합니다. 결과를 얻은 후에 만 ​​무엇을할지 고려하고 double.


3
내가 생각할 수있는 한 가지 예외는 포인터를 취할 때 함수 오버로드를 선택하는 것입니다. 값은 &funcname어떤 유형으로 캐스팅 하느냐에 따라 다릅니다.
Steve Jessop 2011 년

2
@Steve Jessop 그게 제가 생각할 수있는 유일한 예외입니다. (하지만 난 어떤 놓친 것을 맹세처럼, 표준의 크기와 복잡성을하지 않을 주어진.)
제임스 간제

6

cdouble변수이지만 할당되는 int값은 두 ints 의 나눗셈에서 발생하므로 "정수 나눗셈"(나머지 삭제)을 제공 하므로 값 입니다. 그래서 라인에서 일어나는 c=a/b일은

  1. a/b 평가되어 임시 유형을 만듭니다. int
  2. 임시 값은 c유형으로 변환 한 후 할당됩니다 double.

의 값은 a/b컨텍스트를 참조하지 않고 결정됩니다 (에 할당 double).


6

두 개의 정수를 나누면 결과는 double로 저장한다는 사실에 관계없이 정수가됩니다.


5

C ++ 언어에서 subexpresison의 결과는 주변 컨텍스트의 영향을받지 않습니다 (일부 예외가 있음). 이것은 언어가주의 깊게 따르는 원칙 중 하나입니다. 표현식 c = a / b에는 a / b해당 하위 표현식 외부의 모든 항목과 독립적으로 해석되는 독립 하위 표현식이 포함됩니다. 언어는 나중에 결과를 double.a / b정수 나눗셈입니다. 다른 것은 중요하지 않습니다. 이 원칙은 언어 사양의 많은 부분에서 따를 것입니다. 이것이 C ++ (및 C)가 작동하는 방식을 결정합니다.

위에서 언급 한 예외의 한 예는 함수 오버로딩이있는 상황에서 함수 포인터 할당 / 초기화입니다.

void foo(int);
void foo(double);

void (*p)(double) = &foo; // automatically selects `foo(fouble)`

이것은 할당 / 초기화의 왼쪽이 오른쪽의 동작에 영향을 미치는 하나의 컨텍스트입니다. (또한 배열 참조 초기화는 유사한 동작의 또 다른 예인 배열 유형 붕괴를 방지합니다.) 다른 모든 경우에 오른쪽은 왼쪽을 완전히 무시합니다.


4

/연산자는 정수 나눗셈 또는 부동 소수점 나눗셈에 사용할 수 있습니다. 두 개의 정수 피연산자를 제공하므로 정수 나눗셈을 수행하고 결과는 double에 저장됩니다.


2

이것은 기술적으로 언어에 따라 다르지만 거의 모든 언어가이 주제를 동일하게 취급합니다. 표현식의 두 데이터 유형간에 유형 불일치가있는 경우 대부분의 언어는 데이터를= 사전 정의 된 규칙 세트에 따라의 한쪽에있는 데이터를 다른쪽에있는 데이터와 일치 .

동일한 유형 (정수, 이중 등)의 두 숫자를 나눌 때 결과는 항상 동일한 유형이됩니다 (따라서 'int / int'는 항상 int가됩니다).

이 경우 분수 데이터가 이미 손실 된 경우 계산 후double var = integer result 정수 결과를 double로 캐스팅합니다 . (대부분의 언어는 예외 나 오류를 발생시키지 않고 유형 부정확성을 방지하기 위해이 캐스팅을 수행합니다.)

결과를 두 배로 유지하려면 다음과 같은 상황을 만들고 싶을 것입니다. double var = double result

이를 수행하는 가장 쉬운 방법은 방정식의 오른쪽에있는 표현식을 강제로 이중으로 변환하는 것입니다.

c = a/(double)b

정수와 double을 나누면 정수가 double로 캐스트됩니다 (수학을 수행 할 때 컴파일러는 종종 데이터 손실을 방지하기 위해 가장 특정한 데이터 유형으로 "업 캐스트"됩니다).

업 캐스트 후에는 a더블로 마무리되고 이제 두 더블 사이의 분할이 있습니다. 그러면 원하는 부서와 할당이 생성됩니다.

다시 말하지만, 이것은 언어에 따라 다르지만 (컴파일러에 한정 될 수도 있음) 거의 모든 언어 (확실히 내가 생각할 수있는 모든 언어)가이 예제를 동일하게 취급합니다.


이 질문에는 [C ++] 태그가 지정되어 있으며 C ++ 표준은 이것이 작동하는 방식을 정확히 지정합니다. "언어 별"이 무엇을 의미하는지 확실하지 않으며 컴파일러 확장이 사용되지 않는다는 가정하에 컴파일러와 관련이 없습니다.
John Dibling 2011 년

또한 "double var = int로 변환하는 double var = integer result"라고 말하는 것은 올바르지 않습니다. double은 int로 캐스트되지 않습니다. int 결과는 double로 변환됩니다.
John Dibling 2011 년

나는 컴파일러 확장의 가능성을 허용하고 있었다 (실제로 내 환경이 결과를 "잘못 캐스팅"하고 그 이유를 알 수 없었던 한 번이 문제가 발생했다). 결과는 일부 언어에서 동일한 캐스팅 규칙을 따르지 않기 때문에 특정 언어입니다. 나는 그것이 C ++ 특정 태그라고 생각하지 않았습니다. "double var = integer result"주석이 맞습니다. 그것을 반영하기 위해 편집되었습니다. 감사합니다!
matthewdunnam 2011 년

0

중요한 것은 계산 요소 중 하나가 float-double 유형이라는 것입니다. 그런 다음 이중 결과를 얻으려면이 요소를 아래와 같이 캐스팅해야합니다.

c = static_cast<double>(a) / b;

또는 c = a / static_cast (b);

또는 직접 만들 수 있습니다.

c = 7.0 / 3;

계산 요소 중 하나는 float-double 유형을 정수로 나눈 것을 나타 내기 위해 '.0'을 가져야합니다. 그렇지 않으면 c 변수가 double이지만 결과도 0이됩니다.


당신의 대답은 다른 9 개의 대답 중 아직 존재하지 않는 것은 무엇을 가져 오나요?
bolov
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.