Math.ceil을 사용하여 Java 반올림 int


101
int total = (int) Math.ceil(157/32);

왜 여전히 4를 반환합니까? 157/32 = 4.90625, 반올림해야합니다. 둘러 보았는데 이것이 올바른 방법 인 것 같습니다.

나는 노력 total으로 double유형, 그러나 4.0을 얻을.

내가 뭘 잘못하고 있죠?

답변:


187

157/32두 개의 정수를 서로 나누는 작업 을 수행 하면 항상 내림 된 정수가됩니다. 따라서는 (int) Math.ceil(...)아무것도하지 않습니다. 원하는 것을 달성하기위한 세 가지 가능한 솔루션이 있습니다. 나는 추천 중 하나를 사용하여 옵션 1 또는 옵션 2 . 옵션 0을 사용 하지 마십시오 .

## 옵션 0

두 배로 변환 a하고 원하는대로 b나누기를 사용할 수 있습니다 Math.ceil. 그러나 이중 나눗셈은 부정확 할 수 있으므로이 방법을 사용하지 않는 것이 좋습니다. double의 부정확성에 대해 자세히 알아 보려면 이 질문을 참조하십시오 .

int n = (int) Math.ceil((double) a / b));

##옵션 1

int n = a / b + ((a % b == 0) ? 0 : 1); 

당신이 할 a / b경우 항상 바닥 ab양의 정수입니다. 그런 다음 인라인 if 문 마녀가 바닥 대신 천장을해야하는지 여부를 확인합니다. 따라서 +1 또는 +0, 나눗셈에 나머지가 있으면 +1이 필요합니다. a % b == 0나머지를 확인합니다.

## 옵션 2

이 옵션은 매우 짧지 만 다소 덜 직관적 일 수 있습니다. 나는이 덜 직관적 인 접근 방식은 빠른 이중 분열과 비교 방식보다 것이라고 생각 :
이가 일을하지 않는하시기 바랍니다 참고 b < 0.

int n = (a + b - 1) / b;

오버플로 가능성을 줄이려면 다음을 사용할 수 있습니다. 그러나 a = 0및 에서는 작동하지 않습니다 b < 1.

int n = (a - 1) / b + 1;

## '덜 직관적 인 접근 방식'에 대한 설명

Java (및 대부분의 다른 프로그래밍 언어)에서 두 정수를 나누면 항상 결과가 내려갑니다. 그래서:

int a, b;
int result = a/b (is the same as floor(a/b) )

그러나 우리는 원하지 floor(a/b)않지만 ceil(a/b), Wikipedia 의 정의와 플롯을 사용합니다 .여기에 이미지 설명 입력

바닥과 천장 함수의 플롯을 통해 관계를 볼 수 있습니다.

바닥 기능 Ceil 기능

당신은 그것을 볼 수 있습니다 floor(x) <= ceil(x). 우리는 floor(x + s) = ceil(x). 그래서 우리는 s. 우리가 1/2 <= s < 1그것이 옳을 것이라고 생각 한다면 (몇 가지 숫자를 시도해 보면 그것이 실제로 나타나는 것을 보게 될 것입니다. 나는 이것을 증명하기가 어렵습니다). 그리고 1/2 <= (b-1) / b < 1, 그래서

ceil(a/b) = floor(a/b + s)
          = floor(a/b + (b-1)/b)
          = floor( (a+b-1)/b) )

이것은 실제 증거는 아니지만 귀하가 그것에 만족하기를 바랍니다. 누군가가 더 잘 설명 할 수 있다면 나도 감사 할 것입니다. MathOverflow에서 물어볼 수도 있습니다 .


1
덜 직관적 인 접근 방식의 직관을 설명 할 수 있다면 큰 호의가 될까요? 나는 이것이 옳다는 것을 알고 있습니다. 어떻게 당신이 그것을 얻었는지, 그리고 그것이 옳다는 것을 수학적으로 어떻게 보여줄 수 있는지 알고 싶습니다. 나는 그것을 수학적으로 풀려고했지만 확신하지 못했다.
Saad Rehman Shah

나는 더 나은 내가 생각 :( 할 수 없어, 당신이 내 편집에 만족 희망
martijnn2008

Math.floor와 ceil은 값이 double로 캐스팅 될 때 긴 나누기가 아닌 정수 나누기에 대해서만 정확하다고 가정합니다. 카운터 예는 4611686018427386880/4611686018427387137이 바닥에서 실패하고 4611686018427386881/4611686018427386880이 ceil에서 실패합니다
Wouter

2
설명의 요점 : 옵션 2의 두 하위 옵션 결과가 모든 경우에 동일하지는 않습니다. a의 값이 0이면 첫 번째에 0을, 두 번째에 1을 제공합니다 (대부분의 응용 프로그램에서 정답이 아님).
Sushisource

1
"하지만 a = 0 및 b < 1 에서는 작동하지 않습니다"를 의미하지 않으
셨나요

60

157/32는 int/int이며 결과는 int.

- 이중 문자 그대로 사용해보십시오 157/32d이다, int/double하는 결과를 double.


int / int가 항상 int가되는 것이 확실합니까?! 거기에 소스를 주시겠습니까?!


34

157/32접미사로 달리 지정하지 않는 한 모든 숫자 리터럴은 정수이므로 정수 나눗셈 입니다 (long의 d경우 double l)

나누기는 이중 (4.0)으로 변환되기 전에 반 내림 (4로) 된 다음 반올림됩니다 (4.0으로).

변수를 사용하면 피할 수 있습니다.

double a1=157;
double a2=32;
int total = (int) Math.ceil(a1/a2);


7

가장 직관적 인 것은 아무도 언급하지 않았습니다.

int x = (int) Math.round(Math.ceil((double) 157 / 32));

이 솔루션은 이중 나누기 부정확성을 수정합니다 .


1
Math.round 긴 반환
Zulqurnain Jutt에게

감사 @ZulqurnainJutt는 캐스트를 추가
IG 파스 쿠알에게

4

Java에서 .0을 추가하면 두 배가됩니다.

int total = (int) Math.ceil(157.0 / 32.0);

3

두 정수를 나눌 때, 예 :

int c = (int) a / (int) b;

결과는 int값을로 a나누고 b0으로 반올림 한입니다. 결과가 이미 반올림되었으므로 ceil()아무 작업도하지 않습니다. 이 반올림은 floor()음의 무한대 로 반올림하는과 동일하지 않습니다 . 따라서 3/2같음 1(및 floor(1.5)같음 1.0, 그러나 (-3)/2같음 -1(그러나 floor(-1.5)같음)-2.0 )).

경우가 있기 때문에 의미가 a/b항상 동일하다 floor(a / (double) b)다음 방금 구현할 수 ceil()a/b-( (-a) / b) .

얻는 제안 ceil(a/b) 에서

int n = (a + b - 1) / b;, 이는 a / b + (b - 1) / b 또는(a - 1) / b + 1

는 정수일 때를 제외하고 ceil(a/b)는 항상보다 1보다 크므로 작동합니다 . 따라서 정수 가 아닌 경우 다음 정수와 충돌 (또는 과거)하려고합니다 . 첨가floor(a/b)a/ba/b1 - 1 / b 됩니다. 정수의 경우 다음 정수로 밀어 붙이지 않습니다. 그 밖의 모든 경우에는 그럴 것입니다.

Yikes. 이해가 되길 바랍니다. 나는 그것을 설명하는 더 수학적으로 우아한 방법이 있다고 확신합니다.


2

또한 숫자를 정수에서 실수로 변환하려면 점을 추가 할 수 있습니다.

int total = (int) Math.ceil(157/32.);

그리고 (157/32.)의 결과도 진짜입니다. ;)


2
int total = (int) Math.ceil( (double)157/ (double) 32);

1

질문에 대한 아래 솔루션을 확인하십시오.

int total = (int) Math.ceil(157/32);

여기에서 Numerator에 1.0을 곱하면 답을 얻을 수 있습니다.

int total = (int) Math.ceil(157*1.0/32);

0

다음과 같이 캐스트하려면 이중 사용

Math.ceil((double)value) 또는 좋아

Math.ceil((double)value1/(double)value2);

0

Java는 /기본적으로 바닥 분할 만 제공합니다 . 그러나 우리는 바닥으로 천장을 쓸 수 있습니다 . 보자 :

모든 정수 y는 형식으로 쓸 수 있습니다 y == q*k+r. floor반올림되는 바닥 분할 (여기 ) 의 정의에 따르면 r,

floor(q*k+r, k) == q  , where 0  r  k-1

그리고 ceil반올림되는 천장 분할 (여기 ) r₁,

ceil(q*k+r₁, k) == q+1  , where 1  r  k

여기서 우리가 대체 할 수 있습니다 r+1위해 r₁:

ceil(q*k+r+1, k) == q+1  , where 0  r  k-1


그럼 우리의 세 번째로 첫 번째 식을 대체 q지고

ceil(q*k+r+1, k) == floor(q*k+r, k) + 1  , where 0  r  k-1

마지막으로, 정수 주어진 일부 , , , 우리가을yy = q*k+r+1qkr

ceil(y, k) == floor(y-1, k) + 1

그리고 우리는 끝났습니다. 도움이 되었기를 바랍니다.


나는 이것이 옳다고 확신하지만, 이것의 요점은 명확히하는 것이기 때문에, 왜 ceil우리가 정수의 천장을 취하고 있는지, 즉 r1 = k를 취하고있는 경우에, 왜 그렇게 정의 되는지 가 명확하지 않습니다 . 엣지 케이스는 이것에 대해 까다로운 것이므로 조금 더 철자가 필요하다고 생각합니다.
Luigi Plinge

@LuigiPlinge 나에게 파생 작업은 분할 작업의 맥락에서 바닥과 천장의 본질적인 차이로 인해 더 간단 할 수 없습니다. 엣지 케이스에 집중할 필요는 없다고 생각합니다. 정수를 분해하여 바닥과 천장의 정의를 통일하려고 할 때 자연스러운 사실입니다. 결과적으로 증명은 3 단계에 불과하며 결론은 "상각 후 한 단계 뒤로 물러 난 다음 한 단계 앞으로"라는 결론을 대략적으로 기억할 수 있습니다.
ShellayLee

0

이중 값을 반올림 할 수있는 두 가지 방법이 있습니다.

  1. Math.ceil
  2. Math.floor

4.90625를 4로하고 싶다면 Math.floor를 사용해야하고, 4.90625를 5로하고 싶다면 Math.ceil을 사용할 수 있습니다.

이를 위해 다음 코드를 참조 할 수 있습니다.

public class TestClass {

    public static void main(String[] args) {
        int floorValue = (int) Math.floor((double)157 / 32);
        int ceilValue = (int) Math.ceil((double)157 / 32);
        System.out.println("Floor: "+floorValue);
        System.out.println("Ceil: "+ceilValue);

    }

}

-3
int total = (157-1)/32 + 1

또는 더 일반적인

(a-1)/b +1 

나는 이것이 작동한다고 생각하지만 원래 버전이 작동하지 않는 이유를 실제로 설명하지 않았습니다.
Teepeemm 2014 년

" 그러나 a = 0 및 b <1에서는 작동하지 않습니다. "
IG Pascual
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.