int total = (int) Math.ceil(157/32);
Neden hala 4 döndürüyor? 157/32 = 4.90625, Yuvarlamam gerekiyor, etrafa baktım ve bu doğru yöntem gibi görünüyor.
Tip totalolarak denedim doubleama 4.0 aldım.
Neyi yanlış yapıyorum?
Yanıtlar:
157/32Her zaman aşağı yuvarlanmış bir tamsayı ile sonuçlanan iki tamsayıyı birbiriyle bölerek yapıyorsunuz . Bu nedenle (int) Math.ceil(...)hiçbir şey yapmıyor. İstediğinizi elde etmek için üç olası çözüm vardır. Ben tavsiye birini kullanarak seçeneği 1 veya 2. seçeneği . Lütfen DEĞİL kullanmak seçeneği 0 .
## Seçenek 0
aVe bbir ikiye dönüştürün ve bölmeyi ve Math.ceilçalışmasını istediğiniz gibi kullanabilirsiniz. Bununla birlikte, bu yaklaşımın kullanılmasını kesinlikle önermiyorum, çünkü çift bölme kesin olmayabilir. Çiftlerin belirsizliği hakkında daha fazla bilgi edinmek için bu soruya bakın .
int n = (int) Math.ceil((double) a / b));
##Seçenek 1
int n = a / b + ((a % b == 0) ? 0 : 1);
Her a / bzaman zemin if ave bikisi de tamsayı ile yaparsınız . O zaman bir satır içi if-ifadesi cadı, yer yerine tavana geçmeniz gerekip gerekmediğini kontrol eder. Yani +1 veya +0, eğer bölümde bir kalan varsa + 1'e ihtiyacınız var.a % b == 0kalanı kontrol eder.
##Seçenek 2
Bu seçenek çok kısadır, ancak daha az sezgisel olabilir. Bu daha az sezgisel yaklaşımın ikili bölme ve karşılaştırma yaklaşımından daha hızlı olacağını düşünüyorum:
Lütfen bunun işe yaramadığını unutmayın b < 0.
int n = (a + b - 1) / b;
Taşma olasılığını azaltmak için aşağıdakileri kullanabilirsiniz. Ancak lütfen a = 0ve için çalışmadığını unutmayın b < 1.
int n = (a - 1) / b + 1;
## "Daha az sezgisel yaklaşım" ın arkasındaki açıklama
Java'da (ve diğer birçok programlama dilinde) iki tamsayıyı bölmek her zaman sonucu ortaya çıkaracaktır. Yani:
int a, b;
int result = a/b (is the same as floor(a/b) )
Ama istemiyoruz floor(a/b)ama Wikipedia'dakiceil(a/b) tanımları ve çizimleri kullanarak :
Zemin ve tavan fonksiyonunun bu grafikleriyle ilişkiyi görebilirsiniz.

Bunu görebilirsin floor(x) <= ceil(x). İhtiyacımız var floor(x + s) = ceil(x). Yani bulmamız gerekiyor s. Eğer bunu 1/2 <= s < 1doğru kabul edersek (bazı rakamları deneyin ve göreceksiniz ki, bunu kanıtlamakta kendimde zorlanıyorum). Ve 1/2 <= (b-1) / b < 1böylece
ceil(a/b) = floor(a/b + s)
= floor(a/b + (b-1)/b)
= floor( (a+b-1)/b) )
Bu gerçek bir kanıt değil, ama umarım tatmin olmuşsunuzdur. Birisi daha iyi açıklayabilirse, ben de minnettar olurum. Belki MathOverflow'da sorabilirsiniz .
157/32, int/intbir int.
Çift değişmez - kullanmayı deneyin 157/32d, bu da int/doublebir double.
157/32bir tamsayı bölümüdür çünkü tüm sayısal değişmez değerler, bir son ek ile aksi belirtilmedikçe ( uzun diçin çift liçin) tam sayıdır
bölme, ikiye (4.0) dönüştürülmeden önce aşağı yuvarlanır (4'e) ve daha sonra yukarı yuvarlanır (4.0'a)
bir değişken kullanıyorsanız bundan kaçınabilirsiniz
double a1=157;
double a2=32;
int total = (int) Math.ceil(a1/a2);
Hiç kimse en sezgisel olandan bahsetmedi:
int x = (int) Math.round(Math.ceil((double) 157 / 32));
Bu çözüm, çift bölme belirsizliğini düzeltir .
Java'da .0 eklemek onu iki katına çıkarır ...
int total = (int) Math.ceil(157.0 / 32.0);
İki tam sayıyı bölerken, örneğin,
int c = (int) a / (int) b;
sonuç, intdeğeri abölünerek bsıfıra yuvarlanan bir an olur. Sonuç zaten yuvarlanmış olduğu ceil()için hiçbir şey yapmaz. Bu yuvarlamanın, floor()negatif sonsuza yuvarlanan ile aynı olmadığına dikkat edin . Yani, 3/2eşittir 1(ve floor(1.5)eşittir 1.0, ancak (-3)/2eşittir -1(ancak floor(-1.5)eşittir)-2.0 ).
Çünkü eğer bu önemlidir a/bhep aynıydı floor(a / (double) b)o zaman sadece uygulamak, ceil()bir a/bşekilde-( (-a) / b) .
Alma önerisi ceil(a/b)dan
int n = (a + b - 1) / b;, eşdeğerdir a / b + (b - 1) / bveya(a - 1) / b + 1
çalışır çünkü tam sayı olması dışında ceil(a/b)her zaman bir büyüktür . Yani, bir tam sayı olmadığı sürece , onu bir sonraki tam sayıya çarpmak (veya geçmek) istersiniz . Eklemefloor(a/b)a/ba/b1 - 1 / b bunu yapacak. Tam sayılar için, onları bir sonraki tam sayıya pek itmez. Diğer her şey için olacak.
Eyvah. Umarım bu mantıklıdır. Eminim bunu açıklamanın matematiksel olarak daha zarif bir yolu vardır.
Ayrıca bir sayıyı tam sayıdan gerçek sayıya dönüştürmek için bir nokta ekleyebilirsiniz:
int total = (int) Math.ceil(157/32.);
Ve (157/32.) 'Nin sonucu da gerçek olacaktır. ;)
Sorunuz için aşağıdaki çözümü kontrol edin:
int total = (int) Math.ceil(157/32);
Burada Numerator'u 1.0 ile çarpmalısınız, o zaman cevabınızı verecektir.
int total = (int) Math.ceil(157*1.0/32);
Java, /varsayılan olarak yalnızca kat bölümü sağlar . Ancak tavan olarak da yazabiliriz . Bakalım:
yForm ile herhangi bir tam sayı yazılabilir y == q*k+r. Yuvarlanan kat bölme tanımına göre (burada floor) r,
floor(q*k+r, k) == q , where 0 ≤ r ≤ k-1
ve yuvarlanan tavan bölümü (burada ceil) r₁,
ceil(q*k+r₁, k) == q+1 , where 1 ≤ r₁ ≤ k
nerede yerini alabilir r+1için r₁:
ceil(q*k+r+1, k) == q+1 , where 0 ≤ r ≤ k-1
Sonra üçüncü içine ilk denklemi yerine qalma
ceil(q*k+r+1, k) == floor(q*k+r, k) + 1 , where 0 ≤ r ≤ k-1
Son olarak, herhangi bir tamsayı verilen bazıları için , , , elimizdekiyy = q*k+r+1qkr
ceil(y, k) == floor(y-1, k) + 1
Ve bitirdik. Bu yardımcı olur umarım.
ceilsezgisel tanımdan bu şekilde tanımlandığı, özellikle bir tamsayının tavanını aldığımız yerde, yani r1 = k, bana açık değil . Uç vakalar bu konuda zor olduğu için, biraz daha açıklanması gerektiğini düşünüyorum.
Çift değerinizi yuvarlayabileceğiniz iki yöntem vardır.
4.90625 cevabınızı 4 olarak istiyorsanız Math.floor ve 4.90625 cevabınızı 5 olarak istiyorsanız Math.ceil kullanabilirsiniz.
Bunun için aşağıdaki koda başvurabilirsiniz.
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);
}
}
Bunun eski bir soru olduğunu biliyorum ama bence, hassasiyet kaybını önlemek için BigDecimal kullanan daha iyi bir yaklaşımımız var . Bu arada, bu çözümü kullanarak birkaç yuvarlama ve ölçekleme stratejisi kullanma olanağımız var.
final var dividend = BigDecimal.valueOf(157);
final var divisor = BigDecimal.valueOf(32);
final var result = dividend.divide(divisor, RoundingMode.CEILING).intValue();
int total = (157-1)/32 + 1
veya daha genel
(a-1)/b +1