C : "(긴 긴 int) = (긴 긴 int) * (double)"에 대한 잘못된 출력?
-
06-07-2019 - |
문제
long long int A = 3289168178315264;
long long int B = 1470960727228416;
double D = sqrt(5);
long long int out = A + B*D;
printf("%lld",out);
결과는 다음과 같습니다. -2147483648
왜 그런지 알 수 없습니다 (긍정적 인 결과가되어야합니다). 누군가 도울 수 있습니까?
해결책
내 생각에 컴파일러는 결과를 int 필드 내에 저장하기 때문에 결과를 "A+B*D"에서 정수로 먼저 반올림해야한다고 생각합니다. 기본적으로 데이터 유형 충돌이 있습니다.
A와 B는 여전히 길이 긴 int의 경우 여전히 유효한 숫자이며, 이는 8 바이트 길이입니다. 당신은 그것들에 1.000을 곱할 수도 있고 여전히 유효한 긴 긴 INT 값을 가질 수 있습니다. 다른 언어에서는 int64라고도합니다.
그러나 더블은 64 비트이지만 그 중 일부는 지수로 사용됩니다. INT64에 더블을 곱하면 결과는 또 다른 두 배가됩니다. 다른 int64를 추가하면 여전히 두 배로 유지됩니다. 그런 다음 특정 반올림 방법을 사용하지 않고 결과를 Int64에 다시 할당합니다. 컴파일러가이를 위해 4 비트 반올림 함수를 사용한다면 놀라지 않을 것입니다. 컴파일러가 그 진술을 멈추지 않고 깨지지 않는다는 것에 놀랐습니다!
어쨌든, 이와 같은 많은 숫자를 사용할 때는 다른 유형을 혼합 할 때 더 조심해야합니다.
다른 팁
어쩌면 그 상수를 "긴 긴"리터럴로 지정해야할까요? 예를 들어 3289168178315264LL
어떤 컴파일러/운영 체제를 사용하고 있습니까? Windows XP에서 Visual C ++ 2008 Express Edition을 사용하여 코드를 실행했으며 작동합니다. 답변 : 6578333356630528 (이것은 53 비트 번호이므로 더블에 맞습니다).
또한 운영 순서가 중요한지 확인하기 위해 두 가지 변형을 시도했습니다.
긴 긴 int out = a; out+= b*d;
긴 긴 int out = b*d; out+= a;
이 둘 다 작동합니다!
궁금한.
귀하의 답변 (확인해야 함)은 성공적으로 석회화되지만 부호 비트로 오버플로가 발생하여 답변이 음수로 만듭니다. 해결책 : 모든 변수를 서명하지 않도록하십시오.
왜:
숫자는 컴퓨터의 메모리에 일련의 비트로 저장됩니다. 해당 시리즈의 첫 번째 비트는 세트가 숫자가 음수임을 의미합니다. 따라서 계산은 작동하지만 부호 비트로 넘쳐납니다.
추천:
이 큰 숫자로 작업하는 경우 Multiprecision 산술 라이브러리를 얻는 것이 좋습니다. 'T는 당신에게 많은 시간과 문제를 절약 할 것입니다.
SQRT의 매개 변수는 있어야합니다 더블.
#include <math.h>
double sqrt( double num );
또한 우리는 결과를 b * d에서 오래까지 시전하는 것을 설명해야합니다.
long long int A = 3289168178315264;
long long int B = 1470960727228416;
double D = sqrt(5.0);
printf("%f\n",D);
long long int out = A + (long long) (B * D);
printf("%lld",out);