Soru Hassasiyeti kaybetmeden float'ı ikiye dönüştürün


İlkel bir yüzüğüm var ve ilkel çiftliğe ihtiyacım var. Sadece floatı ikiye ayırmak bana garip ekstra bir hassasiyet veriyor. Örneğin:

float temp = 14009.35F;
System.out.println(Float.toString(temp)); // Prints 14009.35
System.out.println(Double.toString((double)temp)); // Prints 14009.349609375

Ancak, döküm yerine, katarı bir dize olarak çıkardım ve dizeyi bir çift olarak ayrıştırıyorum, istediğimi alıyorum:

System.out.println(Double.toString(Double.parseDouble(Float.toString(temp))));
// Prints 14009.35

Dize ve geri gitmek için daha iyi bir yolu var mı?


76
2018-05-27 14:39


Menşei




Cevaplar:


Bu senin değil aslında Daha fazla hassasiyet elde etmek - şamandıranın aslen hedeflediğin sayıyı doğru olarak göstermemesi. Çift olduğu Orijinal şamandıranın doğru bir şekilde temsil edilmesi; toString zaten mevcut olan "ekstra" verileri gösteriyor.

Örneğin (ve bu rakamlar doğru değil, sadece işleri yapıyorum) sahip olduğunuz desteği:

float f = 0.1F;
double d = f;

Sonra değeri f tam olarak 0.100000234523 olabilir. d tam olarak aynı değere sahip olacak, ancak onu bir dizeye dönüştürdüğünüzde, daha yüksek bir doğrulukta doğru olduğunu "güvendiğini", yani bu kadar erken olmayacak ve "zaten fazladan rakamları" göreceksiniz. Orada ama senden gizlenmiş.

Bir dize ve geri dönüştürdüğünüzde, orijinal floattan daha dize değerine daha yakın olan bir double değeriyle sona erersiniz - ama bu sadece iyi Eğer Gerçekten dize değerinin gerçekten istediğin şey olduğuna inanıyorsun.

Şamandıra / Çifte'nin burada kullanmak için uygun tip olduğundan emin misiniz? BigDecimal? Kesin ondalık değerleri olan sayıları (örneğin para) kullanmaya çalışıyorsanız BigDecimal daha uygun bir IMO türüdür.


103
2018-05-27 14:42



Bence cevabınız, benim sorunumun nedenini en iyi açıklıyor. Benim çözümüm 'işe yarayabilir' ama şimdi anladım ki, yanlış soruyu soruyorum. Teşekkürler. - Steve Armstrong
.NET'de aynı sorunu yaşıyorum ve bu çok iyi açıklıyor, teşekkürler. - EMP


İkili gösterime dönüştürme işlemini bu sorunu daha kolay kavradım.

float f = 0.27f;
double d2 = (double) f;
double d3 = 0.27d;

System.out.println(Integer.toBinaryString(Float.floatToRawIntBits(f)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d2)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d3)));

Yüzgecin, sonuna kadar 0'lar ekleyerek çifte genişletildiğini görebilirsiniz, ancak 0.27'nin ikili gösterimi 'daha doğru', yani problemdir.

   111110100010100011110101110001
11111111010001010001111010111000100000000000000000000000000000
11111111010001010001111010111000010100011110101110000101001000

32
2018-02-07 08:45





Bu sözleşme nedeniyle Float.toString(float), kısmen diyor ki:

İçin kaç basamak basılmalıdır   kesirli kısım […]? Orada   en az bir rakam olmalı   kesirli parçayı temsil eder ve   bunun ötesinde, ama sadece çok, benzersiz olarak ihtiyaç duyulan daha fazla rakam   argüman değerini ayırt et   tip floatın bitişik değerleri. o   , x'in kesin olduğunu varsayalım   tarafından temsil edilen matematiksel değer   tarafından üretilen ondalık gösterim   sonlu sıfır olmayan için bu yöntem   argüman f. Sonra f float olmalı   x'e en yakın değer; ya da iki şamandıra   değerler eşit olarak x'e, sonra f'ye   onlardan biri olmalı ve en az   önemli bir önemi   f 0 olmalıdır.


23
2018-05-27 14:56



+1 Belgelerden alıntı ile büyük cevap. - EMP


Bu sorunla bugün karşılaştım ve Refactor'u BigDecimal'e kullanamadım çünkü proje gerçekten çok büyük. Ancak kullanarak çözüm buldum

Float result = new Float(5623.23)
Double doubleResult = new FloatingDecimal(result.floatValue()).doubleValue()

Ve bu çalışır.

Result.doubleValue () çağrısının 5623.22998046875 değerini döndürdüğünü unutmayın.

Ancak, doubleResult.doubleValue () yönteminin doğru şekilde döndürülmesi 5623.23 değerini döndürür

Ama doğru bir çözüm olup olmadığından emin değilim.


14
2018-01-02 12:24



Benim için çalıştı. Ayrıca çok hızlı. Bunun neden bir yanıt olarak işaretlenmediğinden emin değil. - Sameer
Bu benim kullandığım yöntem ve yeni Float kısmına ihtiyacınız yok ... Sadece FloatingDecimal'i ilkel ile oluşturun. Otomatik olarak kutulacak ... Ve hızlı da çalışıyor ... Bir dezavantajı var, FloatingDecimal immutable, bu yüzden her bir float için bir tane yaratmanız gerekiyor ... O bir hesaplama kodu (1e10) hayal et! !! Elbette BigDecimal aynı dezavantaja sahip ... - Mostafa Zeinali
Bu çözümün dezavantajı, sun.misc.FloatingDecimal'in JVM'nin iç sınıfı ve yapısının imzasının Java 1.8'de değiştirilmiş olmasıdır. Gerçek yaşam uygulamasında iç sınıfları kimse kullanmamalıdır. - Igor Bljahhin


Kullanın BigDecimalyerine float/double. İkili kayan nokta olarak temsil edilemeyen çok sayıda sayı vardır. 0.1). Yani ya her zaman sonucu bilinen bir hassasiyete ya da kullanıma yuvarlamanız gerekir. BigDecimal.

Görmek http://en.wikipedia.org/wiki/Floating_point daha fazla bilgi için.


6
2018-05-27 14:45



Önbelleğinizde 10m float ticaret fiyatınız olduğunu, hala BigDecimal'i kullanmayı düşündüğünüzü ve benzersiz olanın ~ 6m nesneleri (flyweight / immutable indirim) olduğunu mu söylüyorsunuz ... ya da daha fazlası var mı? - Sendi_t
@Sendi_t Lütfen karmaşık sorular sormak için yorumları kullanmayın :-) - Aaron Digulla
Baktığınız için teşekkürler! .. Şimşekleri şu an on yıl önce kabul edilen şamandıralar kullanıyoruz - Bu durum hakkındaki görüşünüzün takibini görmeye çalışıyordum -. Teşekkürler! - Sendi_t
@Sendi_t Yanlış anlama. Sorunuzu 512 karaktere cevaplayamıyorum. Lütfen uygun bir soru sorun ve bana bir bağlantı gönderin. - Aaron Digulla
@GKFX Bilgisayarlardaki ondalıkların işlenmesi söz konusu olduğunda "herkese uyar" diye bir şey yoktur. Ama çoğu insan bunu anlamadığı için BigDecimal Bu yaygın hataların çoğunu yakalayacaktır. Eğer işler çok yavaşsa, daha fazla şey öğrenmeli ve sorunlarını optimize etmenin yollarını bulmalılar. Prematüre optimizasyon tüm kötülüklerin köküdür - D.E. Knuth. - Aaron Digulla


Aşağıdaki çözümü buldum:

public static Double getFloatAsDouble(Float fValue) {
    return Double.valueOf(fValue.toString());
}

Eğer kullanırsan şamandıra ve çiftyerine şamandıra ve Çift aşağıdakileri kullanın:

public static double getFloatAsDouble(float value) {
    return Double.valueOf(Float.valueOf(value).toString()).doubleValue();
}

4
2018-01-25 16:20





Şamandıralar, doğa tarafından, kesin değildir ve her zaman düzgün yuvarlama "sorunları" var. Hassasiyet önemliyse, uygulamanızı Ondalık veya Büyük Boyutlu kullanmak için yeniden düzenlemeyi düşünebilirsiniz.

Evet, yüzer işlemci işlemci desteği nedeniyle ondalıklardan daha hızlıdır. Ancak hızlı mı yoksa doğru mu istiyorsunuz?


1
2018-05-27 14:55



Ondalık aritmetik de geçersizdir. (ör. 1/3 * 3 == 0,999999999999999999999999999999) Tabii ki, kesin olarak temsil etmek daha iyidir ondalık para gibi miktarlar, ancak fiziksel ölçümler için hiçbir avantajı yoktur. - dan04
Ama 1 == 0,999999999999999999999999999999 :) - Emmanuel Bourg


Bilgi için bu Madde 48'in altında gelir - Joshua Bloch'un Effective Java 2nd editionının tam değerleri gerektiğinde float ve double kaçının. Bu kitap, iyi şeyler ile dolu reçel ve kesinlikle bir göz atmaya değer.


0
2018-05-27 15:05





Bu çalışıyor mu?

float flt = 145.664454;

Double dbl = 0.0;
dbl += flt;

0
2018-03-04 12:18