정수 나누기 : 이중을 어떻게 생성합니까?


249

이 코드 블록의 경우 :

int num = 5;
int denom = 7;
double d = num / denom;

의 값은 d입니다 0.0. 다음을 캐스팅하여 강제로 작동시킬 수 있습니다.

double d = ((double) num) / denom;

그러나 올바른 double결과 를 얻는 다른 방법이 있습니까? 나는 일어날 수있는 일을 알고있는 프리미티브 캐스팅을 좋아하지 않습니다.



9
'int'를 double로 캐스팅하는 것이 안전합니다. 정밀도 손실없이 항상 같은 값을 얻을 수 있습니다.
Peter Lawrey

1
다음은 분할을 위해 컴파일러가 수행 한 올바른 단계인지 알고 싶습니다. 내가 틀렸다면 알려주십시오.
mannyee

답변:


156
double num = 5;

그것은 캐스트를 피합니다. 하지만 캐스트 전환은 명확하게 정의되어 있습니다. 추측 할 필요는 없으며 JLS를 확인하십시오 . int to double은 확장되는 변환입니다. §5.1.2 부터 :

확장 기본 변환은 숫자 값의 전체 크기에 대한 정보를 잃지 않습니다.

[...]

int 또는 long 값을 float로 변환하거나 long 값을 double로 변환하면 정밀도가 손실 될 수 있습니다. 즉, 값의 최하위 비트가 일부 손실 될 수 있습니다. 이 경우 결과 부동 소수점 값은 IEEE 754 반올림 모드 (§4.2.4) 를 사용하여 정수 값의 올림 된 버전이 됩니다.

5는 정확히 double로 표현 될 수 있습니다.


60
+1. 캐스팅이 무서워하지 마십시오. 작동 방식에 대해 알아보십시오. 모두 잘 정의되어 있습니다.
Mark Peters

1
@FabricioPH 이것은 모든 상황에서 작동하며 * 1.0 솔루션과 동일합니다.
Vitruvius

3
@Saposhiente 그것은 작동하지 않습니다. 변수 유형을 변경하면 코드가 더러워 보입니다. 정수 여야하는 무언가가 있고 수학 연산을 수행 할 수 있도록 float의 표현을 변경하면 위험에 처할 수 있습니다. 또한 일부 컨텍스트에서 변수를 정수로 읽으면 코드를 더 쉽게 이해할 수 있습니다.
Fabricio PH

2
@FabricioPH, 곱하면 1.0여전히 다른 방식으로 결과 유형이 변경됩니다. '더티 코드가 나에게 보인다'는 당신이 어떤 시나리오를 곱하는 1.0것이 실제로 더 낫다고 생각 하는지 (또는 왜 그럴 수 있는지) 설명하지 않습니다 .
Matthew Flaschen

4
@FabricioPH 당신과 OP는 (double)num어떻게 든 변화 한다는 잘못된 믿음 ( "변수의 유형 변경"이라고 말함) 하에서 노력하고있는 것 같습니다 num. 그것은 아닙니다-그것은 문장의 문맥에 대해 임시 이중을 만듭니다.
Paul Tomblin

100

캐스팅 프리미티브의 문제점은 무엇입니까?

어떤 이유로 캐스팅하고 싶지 않다면 할 수 있습니다

double d = num * 1.0 / denom;

63
... 곱하기 전에 암시 적 캐스트
Alice Purcell

2
대부분의 경우 다른 변수의 유형을 변경하는 것보다 낫습니다.
Fabricio PH

3
@FabricioPH 인용 할 소스가없는 한, 이것이 사실이라고 제안하는 것은 없습니다.
Vitruvius

1
@Saposhiente는 다른 유사한 코멘트에 대답
파브 PH에게

1
"D"접미사를 사용하여 동일한 암시 적 캐스트를 수행 할 수도 있습니다. - 그래서 예를 들면 :double d = num * 1D / denom;
BrainSlugs83

73

나는 일어날 수있는 일을 아는 프리미티브 캐스팅을 좋아하지 않습니다.

왜 프리미티브를 캐스팅하는 것에 대한 비이성적 인 두려움이 있습니까? 당신이 캐스팅 할 때 아무것도 나쁜 일이 일어날 intA를 double. 작동 방식을 잘 모를 경우 Java 언어 사양 에서 찾아보십시오 . 주조 int하려면 doubleA는 확대 변환 프리미티브 .

분자 대신 분모를 캐스트하여 여분의 괄호를 제거 할 수 있습니다.

double d = num / (double) denom;

2
당신도 할 수 double d = (double) num / denom;... ... (이것은 우선 순위에 따라 다릅니다)
user85421

27

하나의 유형을 변경하면 수식이 변경되면이 변수가 계산의 일부로 중지되면 결과가 엉망이되기 때문에 다시 두 번 몰래 기억해야합니다. 계산 내에서 캐스트하는 습관을 만들고 그 옆에 주석을 추가합니다.

double d = 5 / (double) 20; //cast to double, to do floating point calculations

결과를 캐스트해도 효과가 없습니다.

double d = (double)(5 / 20); //produces 0.0

17

부동 소수점 Math로 연산을 수행하도록 정수의 정수 / 정수 중 하나를 캐스트합니다. 그렇지 않으면 정수 수학이 항상 선호됩니다. 그래서:

1. double d = (double)5 / 20;
2. double v = (double)5 / (double) 20;
3. double v = 5 / (double) 20;

결과를 캐스트해도 효과가 없습니다. 첫 번째 나누기는 우선 순위 규칙에 따라 수행되기 때문입니다.

double d = (double)(5 / 20); //produces 0.0

나는 당신이 생각하는 것처럼 캐스팅에 아무런 문제가 없다고 생각합니다.


10

유형 주조는 유일한 방법입니다


double정수 나누기에서 생성- 캐스팅 하지 않고 다른 방법은 없습니다 (명시 적으로하지는 않지만 발생할 수 있습니다).

지금, 거기에 우리가 정확한 얻는 것을 시도 할 수있는 몇 가지 방법입니다 double값은 (여기서 num하고 denom있는 int유형, 그리고 코스 주조와 ) -

  1. 명시 적 캐스팅

    • double d = (double) num / denom;
    • double d = ((double) num) / denom;
    • double d = num / (double) denom;
    • double d = (double) num / (double) denom;

하지만 double d = (double) (num / denom);

  1. 암시 적 캐스팅

    • double d = num * 1.0 / denom;
    • double d = num / 1d / denom;
    • double d = ( num + 0.0 ) / denom;
    • double d = num; d /= denom;

하지만 double d = num / denom * 1.0;
하지double d = 0.0 + ( num / denom );


2

다음과 같은 것을 사용하십시오 :

double step = 1d / 5;

(1d는 두 배로 캐스트입니다)


5
1d는 캐스트가 아니며 단지 선언 일뿐입니다.
Sefier Tang

0

오퍼레이션 랩핑을 고려할 수 있습니다. 예를 들면 다음과 같습니다.

class Utils
{
    public static double divide(int num, int denom) {
        return ((double) num) / denom;
    }
}

이를 통해 캐스트가 원하는 것을 정확하게 수행하는지 여부를 한 번만 조회 할 수 있습니다. 이 방법은 테스트를 계속 수행하여 원하는 작업을 계속 수행 할 수 있습니다. 또한 올바른 결과를 얻는 한 나눗셈을 유발하는 데 사용하는 트릭 (여기서 답변을 사용할 수 있음)은 중요하지 않습니다. 두 정수를 나눌 필요가있는 곳이라면 어디에서나 Utils::divide올바른 일을하고 있다고 믿을 수 있습니다 .



당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.