Programing

C의 int 변수에 이중 정밀도를 할당하는 비직관적 결과

c10106 2022. 4. 17. 12:27
반응형

C의 int 변수에 이중 정밀도를 할당하는 비직관적 결과

다음 코드에서 출력된 14번과 15번 두 개의 번호를 왜 구하는지 누가 설명 좀 해줄래?

#include <stdio.h>  

int main()
{
    double Vmax = 2.9; 
    double Vmin = 1.4; 
    double step = 0.1; 

    double a =(Vmax-Vmin)/step;
    int b = (Vmax-Vmin)/step;
    int c = a;

    printf("%d  %d",b,c);  // 14 15, why?
    return 0;
}

나는 두 경우 모두 15점을 받을 것으로 예상하지만 언어의 기초가 부족한 것 같다.

그게 관련이 있는지는 모르겠지만 코드블록에서 테스트를 하고 있었어.그러나 일부 온라인 컴파일러(: 이 코드)에 동일한 코드 라인을 입력하면 두 개의 인쇄된 변수에 대해 15의 답이 나온다.

...왜 내가 두개의 다른 숫자를 가지게 되었는지...

일반적인 부동 소수점 문제는 제쳐두고 다음 연산 경로로 이동b그리고c다른 방법으로 도착했다. c먼저 값을 다음과 같이 저장하여 계산한다.double a.

double a =(Vmax-Vmin)/step;
int b = (Vmax-Vmin)/step;
int c = a;

C는 중간 부동소수점 산술을 더 넓은 유형을 사용하여 계산할 수 있도록 한다.값 의 확인FLT_EVAL_METHOD로부터<float.h>.

할당 및 캐스트(추가 범위와 정밀도를 모두 제거하는)를 제외하고...

-1 불변;

0은 유형의 범위와 정밀도에만 모든 연산 및 상수를 평가한다.

1의 및 float그리고double의 범위와 정밀도까지double유형, 평가long double의 범위와 정밀도에 대한 연산 및 상수long double타자를 치다;

2의 범위와 정밀도에 대한 모든 연산 및 상수를 평가한다.long double타자를 치다

C11dr §5.2.4.2.2 9

OP 보고 2

에 대한 지수를 저장함으로써double a = (Vmax-Vmin)/step;, 정밀도는 다음과 같이 강요된다.double반면에int b = (Vmax-Vmin)/step;라고 계산할 수 있다.long double.

이 미묘한 차이는 다음과 같다.(Vmax-Vmin)/step (아마도 있는)long double되어 있다.double남은 a에 대한 대long double하나는 15(또는 바로 위), 다른 하나는 15 바로 밑이다. int잘림 현상은 15와 14로 이 차이를 증폭시킨다.

다른 컴파일러의 경우, 두 결과가 모두 다음과 같은 이유로 동일했을 수 있다.FLT_EVAL_METHOD < 2또는 기타 부동 소수점 특성.


전환int부동 소수점부터 숫자가 정수에 가까울 정도로 심각하다.에게 종종 더 좋다.round()또는lround()가장 좋은 해결책은 상황에 따라 달라지는 것이다.

이것은 정말로 흥미로운 질문이다. 여기 당신의 하드웨어에서 정확히 무슨 일이 일어나는지 있다.의 정道를 한 것으로서 한국의 계을을을을을을한한한한 gives한한한한한한한한한한한 다.double정밀 부동(예: 52비트 matissa + 하나의 암시적 비트)표현에 대한 자세한 내용은 위키백과 기사를 참조하십시오.

먼저 몇 가지 변수를 정의하십시오.

double Vmax = 2.9;
double Vmin = 1.4;
double step = 0.1;

2진수의 각 값은 다음과 같은 값이다.

Vmax =    10.111001100110011001100110011001100110011001100110011
Vmin =    1.0110011001100110011001100110011001100110011001100110
step = .00011001100110011001100110011001100110011001100110011010

비트를 세어보면 오른쪽에 52비트를 더한 첫 번째 비트를 내가 준 것을 알 수 있을 것이다.이것은 정확히 당신의 컴퓨터가 a를 저장하는 정밀도 입니다.double. 값이 반올림되었다는 점에 유의하십시오.

이제 이 숫자들을 계산해봐첫 번째 수술인 뺄셈은 정확한 결과를 낳는다.

 10.111001100110011001100110011001100110011001100110011
- 1.0110011001100110011001100110011001100110011001100110
--------------------------------------------------------
  1.1000000000000000000000000000000000000000000000000000

그 다음 으로 나눈다.step, 컴파일러에 의해 반올림된 것:

   1.1000000000000000000000000000000000000000000000000000
 /  .00011001100110011001100110011001100110011001100110011010
--------------------------------------------------------
1110.1111111111111111111111111111111111111111111111111100001111111111111

의 라운딩으로 인해step, 결과는 약간 아래에 있다.15이전과는 달리, 나는 즉시 라운딩을 하지 않았다. 왜냐하면 그곳이 바로 흥미로운 일이 일어나는 곳이기 때문이다.CPU는 실제로 a보다 더 큰 정밀도의 부동소수를 저장할 수 있다.double, 그래서 라운딩은 즉시 일어나지 않는다.

그래서 결과를 변환할 때(Vmax-Vmin)/step에 직접int, 당신의 CPU는 단지 분절점 뒤의 비트를 잘라낸다 (이것이 암묵적인 방법이다).double -> int변환은 언어 표준에 의해 정의된다.

               1110.1111111111111111111111111111111111111111111111111100001111111111111
cutoff to int: 1110

그러나 결과를 이중 유형의 변수에 처음 저장하면 반올림이 수행된다.

               1110.1111111111111111111111111111111111111111111111111100001111111111111
rounded:       1111.0000000000000000000000000000000000000000000000000
cutoff to int: 1111

그리고 이게 바로 네가 얻은 결과야.

"단순한" 대답은 겉보기에는 단순해 보이는 숫자 2.9, 1.4, 0.1은 모두 내부적으로 이진 부동소수로 표시되며, 이진에서는 숫자 1/10을 무한 반복하는 이진분수 0.0001100110011001100110011로 표시한다는 것이다.[2] . . (이것은 십진수에서 1/3이 0.3333333... . .) 다시 십진수로 환산하면, 그 원래의 숫자는 2.899999999999, 1.3999999999, 0.0999999999와 같은 것이 된다.그리고 그들에 대한 추가적인 계산을 할 때, 그 .099999999는 증식하는 경향이 있다.

그리고 또 다른 문제는 어떤 것을 계산하는 경로 -- 특정 유형의 중간 변수에 저장하든, 아니면 "모두 한 번에" 계산하든 간에, 프로세서가 유형보다 더 정밀하게 내부 레지스터를 사용할 수 있다는 겁니다.double큰 수 있다 - 안 된다.

요컨대, 변환할 때double로 되돌아가다.int너는 거의 항상 자르기가 아니라 둥글게 하고 싶어 한다.여기서 일어난 일은 (실제로) 하나의 계산 경로가 15.0000000001을 줬고, 다른 하나는 14.9999999999를 줬다는 겁니다.

C FAQ 목록에서 질문 14.4a도 참조하십시오.

FLT_EQUAL_METHOD=2에 대한 C 프로그램의 분석에서 등가 문제를 분석한다.

만약FLT_EVAL_METHOD==2:

double a =(Vmax-Vmin)/step;
int b = (Vmax-Vmin)/step;
int c = a;

계산하다bA를 평가하여long double식을 사용하여 이를 잘라내십시오.int에 ,,,,라면.c로부터 평가하고 있다.long double, 잘라내기 위치double그 다음으로는int.

따라서 두 값 모두 동일한 공정을 통해 얻을 수 없으며, 부동형은 통상적인 정확한 산수를 제공하지 않기 때문에 다른 결과를 초래할 수 있다.

참조URL: https://stackoverflow.com/questions/49012793/nonintuitive-result-of-the-assignment-of-a-double-precision-number-to-an-int-var

반응형