Yüzen sayıları bildirirken neden "f" gereklidir?


88

Misal:

float timeRemaining = 0.58f;

fBu numaranın sonunda neden gereklidir?


4
Muhtemelen, çünkü aksi takdirde olarak değerlendirilirdi double.
Uwe Keim

2
0.58 (f soneki olmadan) double türünde bir değişmezdir ve bir float'a double değer atayamaz, tıpkı bir dizgeye int değeri atayamayacağı gibi. Bununla birlikte, bir double'a bir float değeri atayabilirsiniz çünkü burada genişletiyorsunuz (C # bunu sizin için örtük olarak dönüştürür, çünkü hiçbir hassasiyet kaybolmaz).
Dave New


@AVD Bu bir kopya olmasına rağmen, yukarıdaki soru başlığı, bağlantınızı olası kopya listesinde göstermez. Bu, en azından daha fazla arama kriteri açısından değer katıyor olabilir.
Adam Houldsworth

1
@AdamHouldsworth - tüm yol gider double & int .
adatapost

Yanıtlar:


98

Şamandıra beyanınız iki bölümden oluşur:

  1. Değişkenin timeRemainingtürde olduğunu bildirir float.
  2. Değeri 0.58bu değişkene atar .

Sorun 2. bölümde ortaya çıkıyor.

Sağ taraf kendi başına değerlendirilir. C # spesifikasyonuna göre, son eki olmayan bir ondalık nokta içeren bir sayı, bir double.

Yani şimdi bir doubletür değişkenine atamak istediğimiz bir değerimiz var float. Bunu yapmak için, 'den' doublee örtük bir dönüşüm olmalıdır float. Böyle bir dönüştürme yoktur, çünkü dönüştürme sırasında bilgi kaybedebilirsiniz (ve bu durumda kaybedersiniz).

Bunun nedeni, derleyici tarafından kullanılan değerin gerçekten 0,58 olmaması, ancak 0,58'e en yakın kayan nokta değerinin 0,57999999999999978655962351581366 ... için doubleve tam olarak 0,579999946057796478271484375 için olmasıdır float.

Kesinlikle fgerekli değildir. fDeğeri a'ya çevirerek soneki kullanmak zorunda kalmayabilirsiniz float:

float timeRemaining = (float)0.58;

4
İki soru, '0.579999946057796478271484375' numarasına nasıl ulaştınız ve nasıl (float) 0.58çalışacak? Daha önce dönüştürme olmadığını söylemiştiniz, çünkü bilgi kaybolabilir, o zaman oyuncu nasıl çalışır?
SexyBeast

9
1. 34 haneye kadar kullanan Windows hesap makinesini kullandım. 2. Örtülü dönüştürme yok dedim . Bir dönüşüm, açık bir dönüşümdür, bu nedenle derleyiciye açıkça dönüşümü istediğinizi söylüyorsunuz ve buna izin veriliyor.
Jeffrey Sax

İlginç ... Umarım hala bu gönderiyi izliyorsundur. Görüntülediğim web yayını için daha önce 'm' ile karşılaşan soneklerle tanıştım. Windows hesap makinesinin kayan değer olarak .58'i görüntülemesini nasıl sağladınız? Bunu olmaya zorlayacak gibi görünen birkaç düğmeyi denedim ama hayır ... 0,58 almaya devam etti. Aletlerini çok iyi bilen bir adama saygı duymalıyım ...
user1585204

Float için F şeyinin tamamını anlıyorum ama neden? Değişken, bir kayan nokta olarak ilan edildiğinde, derlendiğinde bu değerin bir kayan nokta olduğunu bilmelidir. Ve aynı şeyi iki kez ilan ettiğinizde. Bu mantıklı değil çünkü float myvalue = 2.4; şimdi derlendiğinde derleyicinin float değişkeninin türü olduğunu zaten bilmesi gerekir. Bir şey mi kaçırıyorum? Teşekkürler!
Frank G.

@FrankG. İki sebep: 1. İfade 2.4her yerde çift olarak yorumlanır. 2. Örtük daraltma dönüşümlerine (ikiliden kayan noktaya gibi) izin verilmez. Bu kurallara bir istisna yapmak istiyorsanız, o zaman çok iyi bir sebebiniz olmalıdır. 1 tuş vuruşunu kaydetmek, muhtemelen yeterince iyi olmayacaktır.
Jeffrey Sax

36

Derleyici değeri temsil için kullanabileceği birçok sayısal türleri vardır Çünkü 0.58: float, doubleve decimal. Derleyicinin sizin için birini seçmesinde sorun olmadıkça, belirsizliği gidermeniz gerekir.

Belgeleri doubledevletler bu derleyici her zaman alır türünü kendiniz belirtmek yoksa doubleherhangi bir gerçek sayısal hazır türü olarak:

Varsayılan olarak, atama operatörünün sağ tarafındaki gerçek sayısal değişmez bilgi double olarak kabul edilir. Bununla birlikte, bir tamsayı sayısının çift olarak kabul edilmesini istiyorsanız, d veya D sonekini kullanın.

Son ekin eklenmesi a foluşturur float; sonek a doluşturur double; sonek m, bir decimal. Bunların hepsi de büyük harfle çalışır.

Ancak bu, neden derlenmediğini açıklamak için hala yeterli değildir:

float timeRemaining = 0.58;

Cevabın eksik yarısı, 'dan' double 0.58ye dönüşümün float timeRemainingpotansiyel olarak bilgiyi kaybetmesidir, bu nedenle derleyici bunu dolaylı olarak uygulamayı reddeder. Açık bir dönüşüm eklerseniz, dönüştürme gerçekleştirilir; fson eki eklerseniz, dönüştürme gerekmeyecektir. Her iki durumda da kod daha sonra derlenir.


ama değişken bir float ise nasıl çift veya ondalık olabilir, bir şeyi kaçırıyorum
Thomas

@BlazArt Evet, derleyiciyi ifade eden cümle atama hedefini kontrol etmeye bile çalışmıyor. Bunun nedeni, derleyici ekibinin yaptığı tasarım seçimlerinde gömülü olacaktır. Bunun mümkün karışıklık karşısında açık ve net olması en iyisidir tahmin ediyorum, yoksa uygulayan yerine sadece iki kural, diğeri sahip rahatsız çok pahalı olduğunu intve bir tane double.
Adam Houldsworth

@BlazArt: Cevabı oluşturmayı yeni bitirdim, lütfen tekrar bir göz atın.
Jon

1
Bilgi kaybıyla ilgili olarak, depolandıkları IEEE 754 formatına göre dökümün gerçekte nasıl yapıldığını bana söyleyebilir misiniz? Double, daha yüksek hassasiyete sahiptir, bu, float'tan double'a çevirmenin her zaman çalışacağı anlamına double a = 0.69f;mı gelir?
SexyBeast

@Cupidvogel: Evet, Spec garantiler (§6.1.2 olarak) o diğerleri arasında dönüştürme içerir "Diğer örtük sayısal dönüşümleri herhangi bir bilgi asla kaybetmek" floatiçin double.
Jon

2

Sorun şu ki .NET, bazı türden örtük işlemlerin gerçekleştirilmesine izin vermek için floatve doublekarma işlenenleri içeren tüm senaryolarda ne olması gerektiğini açıkça belirtmesi ya da türler arasında örtük dönüşümlerin bir işlemde gerçekleştirilmesine izin vermesi gerektiğidir. sadece yön; Microsoft, zaman zaman hassasiyeti tercih eden, ancak sık sık doğruluktan ödün veren ve genellikle güçlük yaratan yöne izin vermek için Java'nın liderliğini takip etmeyi seçti.

Neredeyse tüm durumlarda, doublebelirli bir sayısal miktara en yakın değeri almak ve bunu a'ya atamak , aynı miktara en yakın değeri floatverecektir float. 9,007,199,791,611,905 değeri gibi birkaç köşe durumu vardır; en iyi floattemsil 9.007.200.328.482.816 (536.870.911 ile kapalı), ancak en iyi doublegösterimi (yani 9.007.199.791.611.904) float9.007.199.254.740.992 (536.870.913 ile kapalı) vermek için kullanmak olacaktır. Genel olarak, yine de, bir doublemiktarın en iyi temsilini dönüştürmek floatya mümkün olan en iyi floatgösterimi ya da esasen eşit derecede iyi olan iki temsilden birini verecektir .

Bu arzu edilen davranışın aşırı durumlarda bile geçerli olduğuna dikkat edin; örneğin, float10 ^ 308 miktarının floaten iyi doublegösterimi, bu miktarın en iyi temsilini dönüştürerek elde edilen gösterimle eşleşir . Benzer şekilde, float10 ^ 309'un floaten iyi doubletemsili, o miktarın en iyi temsilini dönüştürerek elde edilen gösterimle eşleşir .

Maalesef, açık bir atama gerektirmeyen yöndeki dönüşümler nadiren her yerde bu kadar doğrudur. En iyi dönüştürme floatiçin değerin temsilini doublenadiren özellikle yakın iyi bir şey verecektir doubleörn iyi dönüştürme (yani değerin temsili, ve bazı durumlarda sonuç büyüklük dereceleri yüzlerce kapalı olabilir floatiçin 10 ^ 40 temsilini doubleirade verimi double10 ^ 300'ün en iyi temsilinden daha büyük olanı karşılaştıran bir değer .

Ne yazık ki, dönüştürme kuralları oldukları gibidir, bu nedenle, değerleri "güvenli" yönde dönüştürürken saçma tip diziler ve son ekler kullanmakla yaşamak ve sıklıkla sahte sonuçlar verecek tehlikeli yöndeki örtük tip yazılara dikkat etmek gerekir.

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.