Fast int<-->float conversion routines?
#1
Posted 24 June 2007 - 10:34 PM
I'm looking for conversion routines [int <--> float] faster
than the standard cast ops int() and float().
I can write my own in C++, but I need to best the standard
cast ops. Instead I barely match them.
Looking for material, the best I've found is Agner Fog's
"float to int" rounding routines, but I'm interested in
truncation, not rounding.
And there's no "int to float" conversion anyway.
Other links I've found either point me to libraries to license,
or quick explanations about why the standard cast ops
should be avoided when performance is of importance, and
not a line of usable code.
Please, do you have any valid link?
Ciao ciao : )
(readin' this? you ought to get out more)
#3
Posted 25 June 2007 - 09:17 AM
Nautilus said:
I'm looking for conversion routines [int <--> float] faster
than the standard cast ops int() and float().
I can write my own in C++, but I need to best the standard
cast ops. Instead I barely match them.
Looking for material, the best I've found is Agner Fog's
"float to int" rounding routines, but I'm interested in
truncation, not rounding.
And there's no "int to float" conversion anyway.
Other links I've found either point me to libraries to license,
or quick explanations about why the standard cast ops
should be avoided when performance is of importance, and
not a line of usable code.
Please, do you have any valid link?
Ciao ciao : )
If I remember correctly the cast ops are slow because they actually result in a function call to ftol. Simply write a piece of assembly code that pops the float you want from the floating point stack. That will atuomatically truncate it. I can post a piece of code when I'm home from work in a few hours or so.
#4
Posted 25 June 2007 - 12:07 PM
My stuff: torus.untergrund.net <-- some diy electronic stuff and more.
#5
Posted 25 June 2007 - 12:12 PM
unsigned char flt_to_byte (float a)
{
float x = a + 256.0f;
return ((*(int*)&x)&0x7fffff)>>15;
}
My stuff: torus.untergrund.net <-- some diy electronic stuff and more.
#6
Posted 25 June 2007 - 04:00 PM
#7
Posted 25 June 2007 - 04:49 PM
I'll use Google's cache to read the pages.
IE and Mozilla fail to open them directly =/
Hi Anubis,
anubis said:
More precisely, with _ftol two FPU state changes happen.
First the FPU current rounding mode is changed, then the
desired bitmask is built, and finally the FPU rounding mode
is set back to the original state.
This is done to guarantee taht the ANSI C standard is fully
respected, no matter the platform, because there's no
dedicated asm instruction***.
[edit]
*** maybe due to the fact that the IEEE 754 is still under
R&D, and may change in future. Just a wild guess...
[/edit]
These state changes stall the FPU twice per each cast.
Collaterally, the designated CPU pipe has to sit and rot
while waiting for the FPU to finish.
To add insult to injury, the state changes are unnecessary
in most cases anyway.
anubis said:
I recognize jumps, and some basic instructions.
I know that the count of "push" and "pop" must always
match.
But that's all.
As far as my job is concerned, I don't need to know assembly.
Yet game programming is my 2nd hobby, and I'll have to
buy a good book someday.
Examining the asm produced by the compiler isn't enough.
Kind regards everyone,
Ciao ciao : )
(readin' this? you ought to get out more)
#8
Posted 25 June 2007 - 04:53 PM
unsigned ftoi(double d)
{
d += 4503599627370496.0; // 1 << 52
return (unsigned &)d;
}
-
Currently working on: the 3D engine for Tomb Raider.
#9
Posted 25 June 2007 - 05:49 PM
int FloatToInt(float x)
{
unsigned e = (0x7F + 31) - ((* (unsigned*) &x & 0x7F800000) >> 23);
unsigned m = 0x80000000 | (* (unsigned*) &x << 8);
return int((m >> e) & -(e < 32));
}
Any reason why the values has to be truncated? Rounding is faster, and this SSE2 snippet performs quite well:
#include <intrin.h>
int FloatToInt_SSE(float x)
{
return _mm_cvt_ss2si( _mm_load_ss(&x) );
}
#10
Posted 25 June 2007 - 06:16 PM
1. float[4] -> *unsigned* int [4] conversion from SSE xmm(n) (to anywhere, xmm register would be fine ;)
2. float[4] -> unsigned char [4] (normalized) conversion from SSE xmm(n) to anywhere, xmm, mm, 32 bit ALU register, .. memory (!)
The case 1 is easy for signed, but for unsigned have to swizzle, crackle and pop the values in multiple parts through mm registers. Likewise for case 2, am I missing something vital or is "unsigned" a second class citizen with SSE? (SSE2, SSE3, ..)
// example of case 2
__m128 c = ...;
__m64 frag = _mm_cvtps_pi16©;
uint32 v = _mm_cvtsi64_si32(_mm_packs_pu16(frag,frag));
FWIW, there is a better sequence for what I actually use this for (mantissa extraction) but it's not so good with the case 1, so I came wondering while bumping into this thread.. my bad. :O
#11
Posted 25 June 2007 - 06:37 PM
-
Currently working on: the 3D engine for Tomb Raider.
#12
Posted 25 June 2007 - 08:17 PM
.oisyn said:
(type&)x is prettier but less secure than *(type*)&x.
Indeed both produce the same result, but consider the case:
float f = 1.0f; // Forget the &, and the compiler may not complain. // In this case it won't. DWORD d = (DWORD &) f;
float f = 1.0f; // Forget either a * or the &, and the compiler will catch // the error. DWORD d = *(DWORD*) &f;
Also (DWORD &) f at first glance looks like a plain cast to DWORD.
Using *(DWORD*) &f instead you hardly get fooled, even if quickly skimming through the code.
Ciao ciao : )
(readin' this? you ought to get out more)
#13
Posted 25 June 2007 - 08:20 PM
-
Currently working on: the 3D engine for Tomb Raider.
#14
Posted 25 June 2007 - 08:42 PM
type every time, and even uglier than *(type*)&x
I prefer the old style casts, thanks ^_^
Ciao ciao : )
(readin' this? you ought to get out more)
#15
Posted 25 June 2007 - 08:48 PM
But when Man Gotta Cast, Man Gotta Cast.. *_cast<> ! FAP!
And a worn-out cliche: "and you can grep _cast..."
#16
Posted 25 June 2007 - 08:51 PM
.oisyn said:
Neither of them are secure since they break the type aliasing rule. The only secure way to do it is to put float and int into a union and access them as needed. Most compilers will sort such little float to int hacks without any overhead these days.
Btw oisyn,
Nice little code snippet! I knew there is a general purpose way to do this cast conversion, but I never had the time to do it. I always write these kind of quick-casts on purpose, hand-tailored for the special case I need (sometimes it's fixed point, sometimes not).
Anyways, I'd like to note that these casts work in reverse just as well. Construct your float from an integer, add he correct exponent and subtract some magic float from it. Once you've understood the float format it becomes second nature.
Nils
My stuff: torus.untergrund.net <-- some diy electronic stuff and more.
#17
Posted 25 June 2007 - 09:15 PM
You are quite right, as usual.
And I forgot my manners by not saying "thanks" to .oysin, for the snippet you just mentioned.
@ .oysin:
Thank you : )
@ Kenneth:
Thank you too.
I need truncation because I often cast to int from floats with fractional parts and the truncation of float() is handy.
Rounding has its uses too, of course.
I think I now have enough material to go on.
But if any of you has more to share, feel free to do so!
@ t0rakka:
I've read an article, once, where the author was complaining about the triad of the _cast<> operators.
He said that they are meant to substitute the old C style casts.
C++ programmers should always resort to such _cast<> and forget about the old C way.
On the other hand -and here I'll repeat part of what you said- casts are evil and should be avoided.
And that's why when they had to decide on syntax and names of the new C++ _cast<> operators, they chose such long and inelegant names. Kind of to discourage their use.
The article concluded saying that the _cast<> ops were superfluous and were adding nothing -in terms of functionality- to the existing language.
I don't remember the link anymore, sorry.
IIRC the article's title had the words "Why I hate [+something else]" in it.
It was one of several articles on C++.
The site is still up for sure.
Regards,
Ciao ciao : )
(readin' this? you ought to get out more)
#18
Posted 25 June 2007 - 11:01 PM
Nautilus said:
Look, either you want to be safe from mistakes, or you wat to type something short. If you want to be safe, you should use the C++ style casts (with reinterpret_cast you express what you mean and you can't accidentally cast away cv qualifiers - A C style cast could do pointer conversions if the types are related)
Quote
Nils Pipenbrinck said:
-
Currently working on: the 3D engine for Tomb Raider.
#19
Posted 22 March 2010 - 05:49 AM
Nils Pipenbrinck said:
yes, its really very much interesting and very informative piece of work.
#20
Posted 05 April 2012 - 03:17 PM
i've suceeded into using Kenneth Godring code, but i've not fully understood how this work.
I try to modify the code of FloatToInt into DoubleToUnsignedShort, if someone can give me a Hand.
int FloatToInt(float x)
{
unsigned e = (0x7F + 31) - ((* (unsigned*) &x & 0x7F800000) >> 23);
unsigned m = 0x80000000 | (* (unsigned*) &x << 8);
return int((m >> e) & -(e < 32));
}
Anyway i would like to understand :
- The first line extract the exponent, all right but why 0x7f + 31 at the beginning?
- The second line extract the mantissa , all rigth but why addinf a forced to 1 MSB?
- The third line confuse me
Thanks for Help
1 user(s) are reading this topic
0 members, 1 guests, 0 anonymous users












