Çiftler çoğunlukla bunun yerine önerildiğinde, neden yüzmeler hala Java dilinin bir parçası?


84

Baktığım her yerde, bunun neredeyse her yönden doubleüstün olduğunu söylüyor float. Java floattarafından eski hale getirildi double, öyleyse neden hala kullanılıyor?

Libgdx ile çok fazla program yapıyorum ve sizi kullanmaya floatzorluyorlar (deltaTime vb.), Ancak bana doubledepolama ve bellek açısından çalışmak daha kolay geliyor.

Ayrıca okuyorum Ne zaman float kullanıyorsunuz ve ne zaman çift kullanıyorsunuz , ancak floatondalık noktadan sonra çok fazla haneye sahip sayılar için gerçekten iyiyse, o zaman neden sadece birçok varyasyondan birini kullanamıyoruz double?

İnsanların artık hiç bir avantajı olmasa da, yüzme havuzunu kullanmakta ısrar etmelerinin bir nedeni var mı? Hepsini değiştirmek için çok mu fazla iş var?



58
Dünyada nasıl "yüzdürme gerçekten sadece ondalık basamaktan sonra çok fazla haneli sayılar için bu sorunun cevabından" sayılır ?! Doğrudan karşı söylüyorlar !
Ordous

20
@Eames "Rakam" değil, "sayılar" yazdığını unutmayın. Kesinlik veya aralığa ihtiyaç duyduğunuzda yüzdürme daha kötüdür , çok ve çok fazla kesin olmayan verilere ihtiyacınız olduğunda daha iyidir . Cevapların söylediği bu.
Ordous

29
Neden var byteve shortve intne zaman var long?
immibis

15
Çok daha uygun bir soru "neden bir anahtar kelimeyi ve ilkel bir veri türünü neden bir sebepsiz yere yıkacak, onlarca yıl kodlu bir dilden sildiniz?"
sara,

Yanıtlar:


169

LibGDX, çoğunlukla oyun geliştirme için kullanılan bir çerçevedir.

Oyun geliştirmede, genellikle gerçek zamanlı olarak çok sayıda sayı çırpma ve önemli olan her türlü performansı yapmanız gerekir. Bu yüzden oyun geliştiricileri, yüzerlik hassasiyeti yeterince iyi olduğunda genellikle yüzdürme kullanırlar.

FPU’nun CPU’daki kayıtlarının boyutu bu durumda göz önünde bulundurmanız gereken tek şey değil. Aslında, oyun geliştirmedeki ağır sayıdaki mücadelenin çoğu GPU tarafından yapılır ve GPU'lar genellikle çiftler için değil, yüzme için optimize edilmiştir .

Ve sonra da var:

  • bellek veriyolu bant genişliği (RAM, CPU ve GPU arasındaki verileri ne kadar hızlı küredebilirsiniz)
  • CPU önbelleği (öncekileri daha az gerekli kılan)
  • Veri deposu
  • VRAM

64bit double yerine 32bit float kullandığınızda iki kat fazla elde ettiğiniz tüm değerli kaynaklar.


2
Teşekkür ederim! Eğer bellek kullanımı değişti hakkında derinlemesine gitti ve neden çünkü bu gerçekten yardımcı oldu
Eames

7
Ayrıca, SIMD işlemleri için 32 bitlik değerlerin iki katı verime sahip olabilir. As 8bittree cevabı işaret, GPU'lar çift hassas daha da büyük bir performans kaybına sahiptir.
Paul A. Clayton,

5
Pek çok grafik boru hattı, hassasiyetin yeterli olduğu yerlerde performansı artırmak için 16 bit yarım yüzmeleri bile destekler.
Adi Shavit

22
@phresnel Hepsi. Pozisyonları taşımanız, verileri güncellemeniz ve yapmanız gerekmemelidir. Ve bu basit kısmı. Ardından dokuları, mesafeleri, ekran formatına getirip (= okumak, döndürmek, ölçeklendirmek ve çevirmek) zorundasınız. Yapacak çok şey var.
Sebb

8
Bir oyun geliştirme girişiminin eski bir VP Operasyonu olarak @ phresnel, sizi temin ederim ki hemen hemen her oyun bir ton sayıdaki çatırdama var. Genellikle kütüphanelerde bulunduğunu ve% 100 mühendisten soyutlandığını not edin, umarım ki bu çatırmanın devam ettiğini anlar ve saygı duyarlar. Sihirli ters kare kök, kimse?
corsiKa

57

Şamandıralar iki misli yarısını kullanır.

Çiftlere göre daha az hassasiyetleri olabilir, ancak birçok uygulama hassasiyet gerektirmez. Benzer boyuttaki herhangi bir sabit nokta formatından daha geniş bir yelpazeye sahiptirler. Bu nedenle, çok sayıda sayı gerektiren ancak yüksek hassasiyet gerektirmeyen ve bellek kullanımının önemli olduğu bir boşluğu dolduruyorlar. Bunları geçmişte büyük sinir ağları sistemleri için kullandım.

Java dışına taşınırken, aynı zamanda 3D grafiklerde de yaygın olarak kullanılırlar, çünkü birçok GPU bunları birincil formatı olarak kullanır - çok pahalı NVIDIA Tesla / AMD FirePro cihazlarının dışında, çift kesinlikli kayan nokta GPU'larda çok yavaştır.


8
Yapay sinir ağlarından bahsetmişken, CUDA şu anda yarı hassas (16-bit) kayan nokta değişkenleri için, daha az hassas olsa da, hatta daha düşük bellek ayak izleriyle, makine öğrenmesi için hızlandırıcı kullanımından dolayı desteği vardır.
JAB

Ve FPGA'ları programladığınızda, hem mantis hem de üstel için bit miktarını her seferinde manuel olarak seçme eğilimindesiniz: v
Sebi

48

Geriye uyumluluk

Davranışı zaten var olan bir dilde / kütüphanede / ISA / etc'de tutmanın bir numaralı nedeni budur .

Java dışına çıkarsa ne olacağını düşünün. Libgdx (ve binlerce diğer kütüphane ve program) işe yaramaz. Pek çok projede yıllar sürecek, muhtemelen her şeyi güncellemek için çok çaba sarf edeceğiz (Python 2'den Python 3'e geçişi izlemek için geriye dönük uyumluluğa bakın). Ve her şey güncellenmeyecek, bazı şeyler sonsuza dek bozulacak, çünkü bakımcılar onları terk ettiler, belki de onlardan daha erken, çünkü güncellemek istediklerinden daha fazla çaba harcayacaklardı ya da yazılımlarının ne olması gerektiğine ulaşmak artık mümkün değil yapmak.

Verim

64 bit çift bellek iki katına çıkar ve 32 bit yüzdürme işleminden neredeyse her zaman yavaşlar (32 bit yüzerlik kabiliyetinin o kadar nadir kullanıldıkları ya da hiç kullanmaları beklenmeyen çok nadir istisnalar, bunlar için optimize etmek için hiçbir çaba gösterilmemiştir) Özel bir donanım için geliştirmediğiniz sürece, yakın gelecekte bu deneyimi yaşamazsınız.)

Özellikle seninle alakalı olan Libgdx bir oyun kütüphanesidir. Oyunların çoğu yazılımdan daha fazla performansa duyarlı olma eğilimi vardır. Ve oyun grafik kartları (örn. AMD Radeon ve NVIDIA Geforce, FirePro ya da Quadro değil) 64 bitlik kayar nokta performansının çok zayıf olma eğilimindedir. AnandTech izniyle, burada çift duyarlıklı performansı bazı tek hassasiyet performansı ile karşılaştırmasını nasıl AMD ve NVIDIA'nın (erken 2016 itibariyle) En iyi oyun kartları mevcut

AMD
Card    R9 Fury X      R9 Fury       R9 290X    R9 290
FP64    1/16           1/16          1/8        1/8

NVIDIA
Card    GTX Titan X    GTX 980 Ti    GTX 980    GTX 780 Ti
FP64    1/32           1/32          1/32       1/24

R9 Fury ve GTX 900 serisinin R9 200 ve GTX 700 serisinden daha yeni olduğuna, bu nedenle 64 bitlik kayan nokta için göreceli performansın azaldığını unutmayın. Yeterince geriye gidin ve R9 200 serisi gibi 1/8 oranına sahip GTX 580'i bulacaksınız.

Performansın 1 / 32'si, kısıtlı bir zaman kısıtlamanız varsa ve daha büyük olanı kullanarak fazla kazanmamanız durumunda ödenecek oldukça büyük bir cezadır.


1
64 bitlik kayan nokta performansının, gerçek 64-bit performansın düşmesi nedeniyle değil, gittikçe daha yüksek düzeyde optimize edilmiş 32-bit komutlar nedeniyle 32-bit performansa göre azaldığını unutmayın. Aynı zamanda kullanılan gerçek kıyaslama ölçütüne de bağlıdır; 32 bit performans açığı bu kriterleri vurgulanan eğer hesaplama hız bellek bant genişliği sorunları nedeniyle hem de fiili olduğunu merak
sig_seg_v

Grafik kartlarındaki DP performansı hakkında konuşacaksanız, kesinlikle Titan / Titan Black'den bahsetmelisiniz. Her ikisi de, tek bir hassas performans pahasına, kartın 1/3 performansına ulaşmasını sağlayan modlara sahiptir.
SGR

@sig_seg_v Kesinlikle en azından 64 bitlik performansın kesinlikle göreceli olarak azaldığı bazı durumlar var. Bir GTX 780 Ti'nin hem GTX 1080 (1/32 oranlı bir kart) hem de 980 Ti ve AMD'nin yanında, 7970 (1/4 oranlı bir kart) ile attığı çift duyarlıklı Folding @ Home kıyaslaması için bu sonuçları görün R9 290 ve R9 290X’in yanı sıra R9 Fury serisini de geçmiştir. Bunu , yeni kartların öncekilerden daha iyi performans gösterdiği testin tekli hassas versiyonuyla karşılaştırın .
8bittree

36

Atomik işlemler

Diğerlerinin söylediklerine ek olarak, Java'ya özgü double(ve long) dezavantajı, 64 bitlik ilkel türlere yapılan atamaların atomik olmalarının garanti edilmemesidir . Gönderen Java Dil Şartname, Java SE 8 Sürümü , sayfa 660 (vurgu eklenmiştir):

17.7 Atomik Olmayan İşlemler doublevelong

Java programlama dili bellek modelinin amaçları doğrultusunda, uçucu olmayan longveya doubledeğere tek bir yazma iki ayrı yazma olarak değerlendirilir: her bir 32 bitlik yarıya. Bu, bir ipliğin 64 bitlik bir değerin ilk 32 bitini bir yazmadan, ikinci 32 bitini başka bir yazmadan görmesine neden olabilir.

Yuck.

Bunu önlemek için , 64 bit değişkenivolatile anahtar kelimeyle bildirmeniz veya ödevlerin çevresinde başka bir eşitleme yöntemi kullanmanız gerekir .


2
Kayıp güncellemeleri önlemek ve aşırı önbelleğe almayı engellemek için uçucu hale getirmek için, eşzamanlı olarak girişlere ve değişkenlere eşzamanlı erişimi senkronize etmeniz gerekmez mi? İnt / float atomunun önlediği tek şeyin, asla beklemeyecekleri “karışık” değerler içeremeyeceği düşüncesi yanlıştır mı?
Traubenfuchs

3
@Traubenfuchs Gerçekten, orada garantili olan şey. Bunun için kullanıldığını duyduğum terim "yırtılma" dır ve etkiyi çok güzel yakaladığını düşünüyorum. Java programlama dili modeli, okunurken 32 bitlik değerlerin bir noktada kendilerine yazılmış bir değere sahip olacağını garanti eder. Bu şaşırtıcı derecede değerli bir garantidir.
Cort Ammon

Atomiteyle ilgili bu nokta çok önemlidir. Vay, bu önemli gerçeği unutmuşum. İlkellerin doğası gereği atomik olduğunu düşünmeye meyilli olduğumuz gibi karşı sezgisel. Ancak bu durumda atomik değil.
Basil Bourque,

3

Diğer cevapların önemli bir noktayı kaçırdığı görülüyor: SIMD mimarileri, çalışmalarına doubleya da floatyapılarına bağlı olarak (örneğin, bir anda sekiz değişken değer veya bir anda dört çift değer) bağlı olarak daha az / daha fazla veri işleyebilir .

Performans değerlendirmeleri özeti

  • float belirli CPU'larda daha hızlı olabilir (örneğin, belirli mobil cihazlar).
  • float daha az bellek kullanır, böylece büyük veri setlerinde, gereken toplam belleği (sabit disk / RAM) ve tüketilen bant genişliğini önemli ölçüde azaltabilir.
  • float Tek duyarlıklı hesaplamalar için bir işlemcinin çift duyarlık hesaplamaları ile karşılaştırıldığında daha az güç tüketmesine neden olabilir (referans bulamıyorum, ancak en azından mümkün görünüyorsa).
  • float daha az bant genişliği tüketir ve önemli olan bazı uygulamalarda.
  • SIMD mimarileri, genellikle aynı veri miktarının iki katına kadar işlem yapabilir.
  • float iki katına kıyasla önbellek yarısının yarısını kullanır.

Doğruluk hususları özeti

  • Birçok uygulamada floatyeterli
  • double Zaten çok daha fazla hassasiyeti var

Uyumluluk konuları

  • Verileriniz bir GPU’ya gönderilmek zorundaysa (örneğin, OpenGL veya başka bir oluşturma API’sı kullanan bir video oyunu için ), kayan nokta biçimi, double(GPU üreticilerinin grafik çekirdeği sayısını artırmaya çalıştığından Böylece her çekirdekte mümkün olduğunca fazla devre kaydetmeye çalışırlar, bu nedenle optimizasyon için floatdaha fazla çekirdek içeren GPU'lar oluşturmaya izin verir)
  • Eski GPU'lar ve bazı mobil cihazlar yalnızca doubledahili format olarak kabul edemez (3B oluşturma işlemleri için)

Genel ipuçları

  • Modern masaüstü işlemcilerde (ve muhtemelen iyi miktarda mobil işlemcide) temelde doubleyığın üzerinde geçici değişkenler kullandığınızı varsayabilirsiniz (ücretsiz olarak ekstra hassasiyet sağlar) (performans cezası olmadan ekstra hassasiyet).
  • Asla ihtiyacınız olandan daha fazla hassasiyet kullanmayın (gerçekten ne kadar hassasiyete ihtiyacınız olduğunu bilmiyor olabilirsiniz).
  • Bazen sadece değerler aralığı tarafından zorlanırsınız (kullanıyorsanız bazı değerler sonsuz olur float, ancak kullanıyorsanız sınırlı olabilir double)
  • Yalnızca floatveya yalnızca doublebüyük ölçüde kullanılması, derleyicinin talimatları SIMD'ye ifşa etmesine yardımcı olur.

Daha fazla bilgi için PeterCordes'den aşağıdaki yorumları görün.


1
doubleTemsilcileri SSE2 ile değil, yalnızca x87'de x87 FPU ile ücretsizdir. Bir döngü otomatik Vektörizasyonu doublegeçicilere açma anlamına floatiçin doubleekstra bir talimat aldığı, ve vektör başına yarısı kadar elemanlarını işleyecektir. Otomatik vektörleştirme olmadan, dönüştürme genellikle bir yükleme veya depolama sırasında anında gerçekleşebilir, ancak yüzdürme ve ifadeleri iki katına çıkarırken ilave talimatlar anlamına gelir.
Peter Cordes

1
Modern x86 CPU'larda, div ve sqrt, float için iki katından daha hızlıdır, ancak diğer şeyler aynı hızdadır (SIMD vektör genişliği sorununu saymazsınız veya elbette bellek bant genişliği / önbellek alanı).
Peter Cordes,

@PeterCordes bazı noktaları genişlettiğin için teşekkürler. Div ve sqrt eşitsizliklerinin farkında
değildim

0

Belirtilen diğer nedenlerden ayrı olarak:

Verileriniz varsa, basınç, akış, akım, voltaj veya herhangi bir şekilde olursa olsun, bu genellikle bir ADC'ye sahip donanım ile yapılır.

Bir ADC tipik olarak 10 veya 12 bite sahiptir, 14 veya 16 biti olanlar daha nadirdir. Fakat hadi 16 bit'e yapışalım - eğer tam ölçekli ölçüm yapıyorsanız, 1/65535 hassasiyetine sahip olursunuz. Bu, 65534/65535'ten 65535/65535'e bir değişiklik demek sadece bu adımdır - 1/65535. Bu kabaca 1.5E-05. Şamandıranın doğruluğu 1E-07 civarındadır, bu yüzden çok daha iyidir. Bu, floatbu verileri depolamak için kullanarak hiçbir şey kaybetmediğiniz anlamına gelir .

Bunu yaparsanız aşırı yüzdürücülü hesaplamalar, sizinle daha hafif daha kötü performans doublesdoğruluğu açısından, hatta çoğu zaman sadece Benzer 2 V veya 2,00002 V'luk bir gerilim ölçülen eğer sık sık umurumda değil, o doğruluk gerekmez Bu gerilimi bir basınca dönüştürürseniz, 3 bar veya 3,0000 bar kullanmanızın bir önemi yoktur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.