Why is the "f" required when declaring floats?
Asked Answered
C

3

103

Example:

float timeRemaining = 0.58f;

Why is the f is required at the end of this number?

Crate answered 17/7, 2012 at 9:33 Comment(8)
Probably, because otherwise it would be treated as double.Costrel
0.58 (without the f suffix) is a literal of type double and one cannot assign a double value to a float, just like one cannot assign an int value to a string. However you can assign a float value to a double because here you are widening (C# will implicitly convert this for you as no precision will be lost).Womanhater
possible duplicate of Why should we use literals in C#?Canopy
@AVD Although this is a duplicate, the question title above doesn't yield your link in the possible duplicate list. So this may be adding value in terms of more search criteria at least.Hokku
@AdamHouldsworth: I 'm not sure if this is a dupe of the linked question. In this question you need to use the f (there's a compiler error otherwise). Perhaps this one should be edited to read "why does the compiler give this error?" -- although there's almost certainly a dupe of that too.Globate
@AdamHouldsworth - all road goes to double & int.Canopy
@Globate But this also forms part of the answer for the linked question, "Why should we use literals" because the provided example wouldn't compile otherwise. Like I said, I still think there is some value, however minimal, in leaving this question open. Duplicates are sometimes unwarranted if the answers actually provide differentiation also.Hokku
@AVD No idea what you are getting at there mate, I don't remember asking a question and I've no idea why you directed that at me.Hokku
K
114

Your declaration of a float contains two parts:

  1. It declares that the variable timeRemaining is of type float.
  2. It assigns the value 0.58 to this variable.

The problem occurs in part 2.

The right-hand side is evaluated on its own. According to the C# specification, a number containing a decimal point that doesn't have a suffix is interpreted as a double.

So we now have a double value that we want to assign to a variable of type float. In order to do this, there must be an implicit conversion from double to float. There is no such conversion, because you may (and in this case do) lose information in the conversion.

The reason is that the value used by the compiler isn't really 0.58, but the floating-point value closest to 0.58, which is 0.57999999999999978655962351581366... for double and exactly 0.579999946057796478271484375 for float.

Strictly speaking, the f is not required. You can avoid having to use the f suffix by casting the value to a float:

float timeRemaining = (float)0.58;
Kyrakyriako answered 21/7, 2012 at 7:29 Comment(7)
Two questions, how did you arrive at the number '0.579999946057796478271484375', and how will the (float) 0.58 work? You said earlier that there is no conversion, because information might be lost, then how come the cast will work?Subplot
1. I used the Windows calculator, which uses up to 34 digits. 2. I said there is no implicit conversion. A cast is an explicit conversion, so you are explicitly telling the compiler you want the conversion, and that is allowed.Kyrakyriako
Interesting ... I hope you're still monitoring this post. I got introduced to suffixes having run into 'm' previously for the webcast I'm viewing. How did you get the Windows calculator to display .58 as the float value? I tried a couple buttons that looked like they'd force this to happen but no ... kept getting 0.58. I have to respect a man who knows his tools so well ...Evanescent
I understand the whole F thing for float but why? When you declared the variable is declared it as a float so when compiled it should know this value is a float. And when you declare a double same thing. It doesn't make sense because you have float myvalue = 2.4; now when compiled the compiler should already know float is the type of variable. Am I missing something? Thanks!Pounds
@FrankG. Two reasons: 1. The expression 2.4 is interpreted as a double everywhere else. 2. Implicit narrowing conversions (like from double to float) are not allowed. If you want to make an exception to these rules, then you must have a very good reason. Saving 1 key stroke is not likely to be good enough.Kyrakyriako
@JeffreySax are you ok to add note about "the similar issue happens using integer literal like float v = 123456789012345678901234567890; - the right side considered on of the integer types and such value does not fit into even UInt64"? (I can do it too)Downe
Compiler is more clever than that and will optimize it for you. No need for an f but for to help human readings. sharplab.io/…Dellinger
G
39

Because there are several numeric types that the compiler can use to represent the value 0.58: float, double and decimal. Unless you are OK with the compiler picking one for you, you have to disambiguate.

The documentation for double states that if you do not specify the type yourself the compiler always picks double as the type of any real numeric literal:

By default, a real numeric literal on the right side of the assignment operator is treated as double. However, if you want an integer number to be treated as double, use the suffix d or D.

Appending the suffix f creates a float; the suffix d creates a double; the suffix m creates a decimal. All of these also work in uppercase.

However, this is still not enough to explain why this does not compile:

float timeRemaining = 0.58;

The missing half of the answer is that the conversion from the double 0.58 to the float timeRemaining potentially loses information, so the compiler refuses to apply it implicitly. If you add an explicit cast the conversion is performed; if you add the f suffix then no conversion will be needed. In both cases the code would then compile.

Globate answered 17/7, 2012 at 9:35 Comment(7)
but how can it be a double or a decimal if the variable is a float, I am missing somethingCrate
@BlazArt Yes, the sentence that states the compiler doesn't even try to check the assignment target. The reason for this will be buried in the design choices made by the compiler team. I would guess it is best to be explicit in the face of possible confusion, or it was too expensive to bother implementing instead of just having two rules, one for int and one for double.Hokku
@BlazArt: Just finished fleshing out the answer, please have a look again.Globate
Regarding the information loss, can you tell me how the cast is actually done, with respect to the IEEE 754 format they are stored in? Double has higher precision, so does that mean that cast from float to double will always work, like double a = 0.69f;?Subplot
@Cupidvogel: Yes, the spec guarantees (in §6.1.2) that "the other implicit numeric conversions never lose any information", which among others includes converting float to double.Globate
why does not cs do that automatically depending on the var type? like other languagesWaggish
Well if you do var x = 0, then it will be interpreted as int, if x=0.0 or 0d then as double, if 0.0f or 0f, then as float.Compander
R
4

The problem is that .NET, in order to allow some types of implicit operations to be carried out involving float and double, needed to either explicitly specify what should happen in all scenarios involving mixed operands or else allow implicit conversions between the types to be performed in one direction only; Microsoft chose to follow the lead of Java in allowing the direction which occasionally favors precision, but frequently sacrifices correctness and generally creates hassle.

In almost all cases, taking the double value which is closest to a particular numeric quantity and assigning it to a float will yield the float value which is closest to that same quantity. There are a few corner cases, such as the value 9,007,199,791,611,905; the best float representation would be 9,007,200,328,482,816 (which is off by 536,870,911), but casting the best double representation (i.e. 9,007,199,791,611,904) to float yields 9,007,199,254,740,992 (which is off by 536,870,913). In general, though, converting the best double representation of some quantity to float will either yield the best possible float representation, or one of two representations that are essentially equally good.

Note that this desirable behavior applies even at the extremes; for example, the best float representation for the quantity 10^308 matches the float representation achieved by converting the best double representation of that quantity. Likewise, the best float representation of 10^309 matches the float representation achieved by converting the best double representation of that quantity.

Unfortunately, conversions in the direction that doesn't require an explicit cast are seldom anywhere near as accurate. Converting the best float representation of a value to double will seldom yield anything particularly close to the best double representation of that value, and in some cases the result may be off by hundreds of orders of magnitude (e.g. converting the best float representation of 10^40 to double will yield a value that compares greater than the best double representation of 10^300.

Alas, the conversion rules are what they are, so one has to live with using silly typecasts and suffixes when converting values in the "safe" direction, and be careful of implicit typecasts in the dangerous direction which will frequently yield bogus results.

Ralphralston answered 21/6, 2013 at 23:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.