0

What is the fastest and most efficient way to convert a float to an integer in c++ (rounding toward zero)? is it

long ftoint(float x) { unsigned int e = (0x7F + 31) - ((* (unsigned int*) &x & 0x7F800000) >> 23); unsigned int m = 0x80000000 | (* (unsigned int*) &x << 8); return int((m >> e) & -(e < 32)); } 

?

19
  • 13
    int y = x; ?? Commented Jul 5, 2021 at 14:54
  • Beside not compiling, the ftoint routine also has undefined behavior. Commented Jul 5, 2021 at 14:55
  • 1
    @463035818_is_not_a_number clang encodes your int y = x; as a single instruction: vcvttss2si eax, xmm0. That seems pretty fast. Commented Jul 5, 2021 at 15:02
  • 1
    maybe you got misled by floor from cmath being actually useful. The reason is that it returns a float. If it would return an integer, I have no clue what would it be good for in c++, you dont need floor (or some other fancy stuff) to convert a float to an int Commented Jul 5, 2021 at 15:04
  • 2
    @Random why not just cast the float/double directly to an int/long or have it implicitly converted? That'll be the fastest. Commented Jul 5, 2021 at 15:07

2 Answers 2

6

Lets compare the following two:

long ftoint(float x) { unsigned int e = (0x7F + 31) - ((* (unsigned int*) &x & 0x7F800000) >> 23); unsigned int m = 0x80000000 | (* (unsigned int*) &x << 8); return int((m >> e) & -(e < 32)); } long ftointfast(float x){ return x; } 

Clang with -O3 produces:

ftoint(float): # @ftoint(float) movd eax, xmm0 mov ecx, eax shr ecx, 23 movzx edx, cl mov ecx, 158 sub ecx, edx shl eax, 8 or eax, -2147483648 shr eax, cl xor edx, edx cmp ecx, 32 cmovb edx, eax movsxd rax, edx ret ftointfast(float): # @ftointfast(float) cvttss2si rax, xmm0 ret 

I am not fluent in assembly, but I am certain that you cannot get it faster than a single instruction.

std::floor(arg) computes the largest integer value not greater than arg. It returns a floating point value. If you do not need a floating point value but only the integer then you do not need std::floor. You also do not need to compare your solution to std::floor because it does something you don't need. And of course you can just write (assuming x actually fits in the range of long):

long y = x; 

or to be explicit

long y = static_cast<long>(x); 
Sign up to request clarification or add additional context in comments.

1 Comment

it's much more tricky than that and a single instruction can be slower than a bunch of instruction. And it depend on the target cpu and the allowed instruction set. This topic is a school case of "don't try to outsmart your compiler" :)
1

Probably with

long ftoint(float x) { return (long)x; } 

(or static_cast if you hate C-style casts)

In fact, you don't need a function. You can just write the cast.

3 Comments

This has "round-toward-zero" behavior, "floor" has round-down behavior. Not the same.
However, the question doesn't say it needs to round down.
i went with static_cast<int>(var_b);

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.