2014-12-19 55 views
6

Java'da kayan nokta aritmetiği ve hassasiyeti ile ilgili bir sorum var. Araştırmamı burada ve google üzerinden yaptım ve bazı çözümlere rastladım ama onları tasarımımda uygulamakta zorluk çektim. Yani Java'da hesaplamalarımın doğru olmasını sağlamak için BigDecimal sınıfını kullanıyorum. Değişkenlerin çift olduğunu ve değerlerin hesaplamalar yapılırken sağa doğru 8 ondalık basamağa kadar hassas olabileceğini unutmayın. Gösterilecek sonuç (kesinlik) biliniyor ve şu anki değer olarak saklayacağım şey. Ayrıca, tüm değerler dinamik olarak (bir yöntemle) gelir. Aktarılan argüman currentValue + adım büyüklüğü olmalıdır.Java Kayan Nokta Hassas Sayı

public void newValue(float value) { 

    //Clip to valid range, can't go over minimum/max value 
    value = Math.max(minimumValue, Math.min(maximumValue, value)); 

    // TODO Implement better Floating Point Arithmetic precision 

    MathContext mcI = new MathContext(0, RoundingMode.HALF_UP);  
    MathContext mcF = new MathContext(8, RoundingMode.HALF_UP); 
    BigDecimal valueBD = new BigDecimal(value, mcF); 
    BigDecimal minimumBD = new BigDecimal(minimumValue, mcF); 
    BigDecimal stepBD = new BigDecimal(step, mcF); 
    BigDecimal currentValueBD = new BigDecimal(currentValue, mcF); 


    BigDecimal totalStepsBD = valueBD.subtract(minimumBD, mcF); 

    //Ensure value is divisible by stepsize 
    totalStepsBD = totalStepsBD.divide(stepBD, mcI); 

    valueBD = stepBD.multiply(totalStepsBD, mcF); 

    valueBD = valueBD.add(minimumBD, mcF); 

    // arithmetic without using BigDecimal (old) 
    //int totalSteps = (int) ((value- minimumValue)/ step); 
    //value = totalSteps * step + minimumValue; 

    if(!(valueBD.equals(currentValueBD))) { 
    valueBD = valueBD.setScale(displayPrecision, RoundingMode.HALF_UP); 
    currentValue = valueBD.floatValue(); 
    dispatch(); 
    } 

}

Şimdi, bazı değerlerin hepsi değil çalışır. Özellikle adım büyüklüğü ile uğraştığımda. Yani adım = 0.1 ise iyiydi. Ben 0,005 yapılmış olsa beni AirthmeticException almak istiyorum - olmayan sonlandırma ondalık genişleme

totalStepsBD = totalStepsBD.divide(stepBD, mcI); 

.005 bir BigDeciaml (stepBD) yaptıktan sonra, adım değişken için ayarlanmış adım o kadar çıkar üzerine. 0049999999 ... Bunun yardımcı olup olmadığından emin değilsiniz, ancak herhangi bir fikriniz varsa lütfen bana bildirin. Teşekkür ederim.

+0

Sana tanımlayan 'yerde step' görmüyorum kullanmak, bu yüzden tahmin ediyorum o için üye değişkeni var sınıf. Eğer bir "float" tipi ise ve 0.005 olarak atanırsa, .0049999999 veya benzeri bir şey olarak kaydedilir. Daha sonra 'step' değeri olan stepBD'yi atadığınızda, 0.00599 değerini değil, 0.005 değerini kullanır. Bu sorun olup olmadığından emin değil, ancak yardımcı olabilir. – Grice

+3

Not: 'BigDecimal's öğesini karşılaştırmak için' .equals() işlevini kullanmayın; örneğin, '0' ve '0.00' eşit değildir. '.compareTo() işlevini kullanın ve bunun yerine' == 0' seçeneğini işaretleyin. – fge

cevap

1

String step (ve String value) ürününü BigDecimal yapıcısına iletin. 0.005'u double (veya float) olarak tam olarak temsil edemezsiniz.

BigDecimal stepBD = new BigDecimal("0.005"); // <-- works as a `String`. 

Düzenleme

Ya aşağıda belirtildiği gibi, BigDecimal.valueOf(double)

BigDecimal stepBD = BigDecimal.valueOf(0.005); 
+0

Sanırım ['BigDecimal.valueOf (çift)'] kullanmak daha iyidir (http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#valueOf%28double%29) bunun yerine, OP kodunu o kadar değiştirmemeli. – Tom

+1

Sadece bir not BigDecimal.valueOf benim için işe yaramadı. Daha ziyade, ilk çözümde göstermiş olduğunuz gibi bir dizgiye dökmek zorunda kaldım. Yardımın için çok teşekkür ederim!! –

İlgili konular