Should C and Objective-C use 0.5f or 0.5?

There are many places that I saw when the author used:

sprite.anchorPoint = CGPointMake(1, 0.5f); 

then why not use 0.5 instead of 0.5f - is there an advantage to using 0.5f ?

+7
source share
5 answers

0.5 is a double constant, and 0.5f is a float constant.

is there an advantage to using 0.5f?

Yes. you either want to specify the type (read: precision) to compute or avoid implicit narrowing (and corresponding compiler warnings).

the example you provided is not convincing, avoiding compiler warnings or just very demanding on the type of parameter.

However, less obvious double-precision promotions can be expensive.

To answer "Should we use 0.5f or 0.5": because there is a suitable time for each of them, you should use both in your programs. You must either use a type suitable for the calculation / precision you need, a type of the passed parameter, or a type suitable for other values ​​in the expression. This is just like integers - there are suitable times for considering the width and suitable times for the suffix (for example, U and L ). There are times when the difference is important and (naturally) when it is not important.

+5
source

Constant 0.5 declares double in Objective-C, putting f at the end - 0.5f declares the constant as a (32-bit) float.
Take a look at the "f" after number / float in the Objective-C / C post.

+2
source

The final f causes the constant to be a single-point float , since floating-point constants default to double s. This was more important a few changes in the compiler back, since I do not think there was an automatic type conversion for double numbers to float, since the compiler could not guarantee that there were no side effects. The result was that the f specifier was stored in a large amount of code in order to avoid write cycles when loading double-precision floating-point registers when only single-point ones are needed.

+2
source

There are consequences of using the float constant when using a double constant or vice versa:

  • Many constants change value. For example, .3 is not equal to .3f. When the source text contains a decimal digit, the compiler must convert it to a value represented in floating point. The 1999 C standard requires it to be converted either to the nearest higher representable value, or to the nearest lower representable value. A good compiler converts it to the closest value in any direction and, in case of equality, selects one in which the least significant bit is zero. (Returning this value is called "proper rounding.") When properly rounded to the floating point formats that are commonly used, .3 becomes 0x1.3333333333333p-2, and .3f becomes 0x1.333334p-2. (These are hexadecimal floating-point constants. The part after "0x" and before "p" is the hexadecimal digit, and the part after "p" is the decimal value for 2. Thus, 0x3.cp4 is 0x3.c times 2 4 which equals (3 + 12/16) β‹…2 4 = 60.)

  • Type of expression change. When the operands of an arithmetic operator contain both float and double operands, the float operand is converted to double. This can lead to a change in the calculated values. The 1999 C standard allows the compiler to represent a floating-point value with greater precision and range than is required for its type, so float values ​​can be stored in double registers and work with double arithmetic. However, if you use double constants, you need the compiler to use double arithmetic. So, if float x contains 0x1.24924ap-3 (approximately 1/7), then "x + .5f" can give 0x1.492492p-1, while "x +.5" should produce 0x1.4924928p-1.

  • In Objective-C, C ++, and other languages ​​that can choose which function to call based on argument types, changing the type of the argument can completely change the code that is executed. A call to "foo (.5f)" can call a procedure that allocates memory, and "foo (.5)" is written to the network socket. This is usually a poor design for the called object, but there are special circumstances in which the objects must be sensitive to the types of their arguments. It is also technically possible in C (as in tgmath.h), but it is rare (and usually involves using a preprocessor to define "foo" as an expression that checks the size of its arguments).

The above list is not intended to be used on an all-inclusive basis.

On the other hand, code or data size is rarely a problem. There is no guarantee that if you write .5f or .5, the compiler will actually save the float or double. For example, if I write "printf ("% g ", 3. * 4. + 5.)", the Compiler should not store 3, 4 or 5. It just needs to create a program that writes "17" to standard output, and he can do this by storing 3, 4, and 5 and doing calculations at runtime, or saving 17 and passing it to printf at runtime, or keeping only the string β€œ17” and writing it to standard output with puts, without saving any numbers or without calling printf at all.

So, as a rule, the important thing about which type to use is to correctly express the calculation that you want to perform, and not to worry about optimization. If you write "foo (.5)" and foo has a double parameter, the compiler can store .5f in program constants and generate code that at run time loads .5f in double register and passes it to foo, I would expect that a good compiler will save constants in the smallest form that can be loaded without the additional cost of execution.

+2
source

You should also keep in mind that a value of 0.5 is accurately represented as a floating point with single or double precision. This means that they are exactly the same. The number of significant bits available in the corresponding format is not significant, since a value of 0.5 requires only one bit (implicit bit) in the value, and all other bits are 0.

So if you need to save 0.5f storage space, it is preferable.

0
source

All Articles