17

When I initialize float variables in my program, I commonly have vectors like:

Vector forward(0.f,0.f,-1.f),right(1.f,0.f,0.f),up(0.f,1.f,0.f)

(Vectors are just 3 floats like struct Vector{ float x,y,z; };)

This looks much easier to read as:

Vector forward(0,0,-1),right(1,0,0),up(0,1,0)

Must I initialize my float variables using floats? Am I losing anything or incurring some kind of penalty when I use integers (or doubles) to initialize a float?

bobobobo
  • 64,917
  • 62
  • 258
  • 363
  • You should not really use Vector as a struct name, since that easily gets confused with the stl::vector. You could instead name it something like vector3f or vector3d – SinisterMJ Sep 28 '12 at 09:56
  • In FORTRAN you must use the appropriate assignment, so a zero double has to be 0.0d0, not 0.0e0 or 0. A lot of people that start with FORTRAN get burned by this behaviour and explicitly put 0.f in their C++ code. C++, by contrast, actually specifies the how to raise a literal 0 or 1 to the appropriate floating point value. – Phil H Sep 28 '12 at 10:10
  • I think initialization won't be the problem. However if you have comparisons, the bigger data type will be used (0.0f against 0.0), so it tends so be slower. Obviously depends on the use case, but not using the right type, you're definitively causing a conversion. Either compile time or runtime. Avoiding it saves time. – stefan Sep 28 '12 at 10:43

3 Answers3

12

There's no semantic difference between the two. Depending on some compilers, it is possible for extra code to be generated, though. See also this and this SO questions of the same topic.

I can confirm that gcc generates the same code for all variants of

int main()
{
    float a = 0.0f; /* or 0 or 0.0 */
    return 0;
}

and that this code is

    .file   "1.c"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $0x00000000, %eax
    movl    %eax, -4(%rbp)
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
    .section    .note.GNU-stack,"",@progbits

The relevant line is

    movl    $0x00000000, %eax

Changing a to 0.1 (or 0.1f) changes the line to

    movl    $0x3dcccccd, %eax

It seems that gcc is able to deduce the correct constant and doesn't generate extra code.

Mihai Maruseac
  • 20,967
  • 7
  • 57
  • 109
8

For a single literal constant, it shouldn't matter. In the context of an initializer, a constant of any numeric type will be implicitly converted to the type of the object being initialized. This is guaranteed by the language standard. So all of these:

float x = 0;
float x = 0.0;
float x = 0.0f;
float x = 0.0L;   // converted from long double to float

are equally valid and result in the same value being stored in x.

A literal constant in a more complex expression can have surprising results, though.

In most cases, each expression is evaluated by itself, regardless of the context in which it appears. Any implicit conversion is applied after the subexpression has been evaluated.

So if you write:

float x = 1 / 2;

the expression 1 / 2 will be evaluated as an int, yielding 0, which is then converted to float. It will setxto0.0f, not to0.5f`.

I think you should be safe using unsuffixed floating-point constants (which are of type double).

Incidentally, you might consider using double rather than float in your program. double, as I mentioned, is the type of an unsuffixed floating-point constant, and can be thought of in some sense as the "default" floating-point type. It usually has more range and precision than float, and there's typically not much difference in performance.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
2

It could be a good programming practise to always write 0.f, 1.f etc., even if often gcc can figure out what the programmer means by 1.0 et al.

The problematic cases are not so much trivial float variable initializations, but numeric constants in somewhat more complex formulae, where a combination of operators, float variables and said constants can easily lead to occurrence of unintended double valued calculations and costly float-double-float conversions.

Spotting these conversions without specifically checking the compiled code for them becomes very hard if the intended type for numeric values is mostly omitted in the code and instead only included when it's absolutely required. Hence I for one would choose the approach of just typing in the f's and getting used to having them around.