Reputation: 65
Using C or C++ what is the fastest way to create a float from an integer where the Integer is after the mantissa?
By example I'd like to create the float 0.12345f from 12345.
A slow way which worked for me was to create a string from the integer and pass to atof. However there must be much faster ways to resolve it by way of bit shifting?
Upvotes: 0
Views: 104
Reputation: 304
The quickest way to do this is to use the log10()
and pow()
functions from math.h
.
#include <math.h>
// An integer representation of a fractional value less than 1.
long integer_mantissa = 12345;
// Use `log10()` to count the decimal digits in the number, minus 1.
// Add back the 1 to get the total number of digits.
long decimal_places = ((long)log10(integer_mantissa) + 1);
// Get the scale factor used to shift the decimal point to the right
// by raising 10 to the negative `decimal_places` power.
double mantissa_scale = pow(10, -decimal_places);
// Multiply the integer by our scale factor to get the final value.
double fraction = integer_mantissa * mantissa_scale;
This method doesn't contain any loops or branch instructions, making it the fastest implementation on any architecture with native floating-point operations. This also works regardless of the underlying floating point representation, making it completely portable to any compiler or platform.
Upvotes: 0
Reputation: 241861
This will be a bit faster than the "divide by 10 until the number is scaled" solutions, because multiplication is faster than division. But the main reason I'd use it is because it is more accurate: dividing by 10 loses precision on every divide, whereas multiplying by 10 doesn't (until you do it 23 times, which is way more than you need to handle a long integer). So only the last division here is imprecise:
double to_fraction(long mantissa) {
double mag = fabs(mantissa), e = 10.;
while (e < mag) e *= 10.;
return mantissa / e;
}
Upvotes: 0
Reputation: 882048
Well, you could just use a loop:
int ival = 12345;
float fval = ival;
while (fabs(fval) >= 1) fval /= 10;
You should generally only worry about performance once you've identified it as a real issue. Unless you need to do this millions of times a second, it should be adequate.
Upvotes: 1
Reputation: 10893
The actual operation you are trying to do is x/10^d where x is your number and d is the number of digits in x. This makes it a bit easier. All you have to do is count the digits.
There are many ways to count digits. The naieve way would be
double y = 1;
while (y <= x)
y *= 10;
return (double)x / y;
But if you want fast....
If your numbers are 32 bit integers, you can use this trick from Bit Twiddling Hacks
unsigned int v; // non-zero 32-bit integer value to compute the log base 10 of
int r; // result goes here
int t; // temporary
static unsigned int const PowersOf10[] =
{1, 10, 100, 1000, 10000, 100000,
1000000, 10000000, 100000000, 1000000000};
t = (IntegerLogBase2(v) + 1) * 1233 >> 12; // (use a lg2 method from above)
r = t - (v < PowersOf10[t]);
And when they say "use a lg2 method from above," you can use an algorithm they wrote earlier in the page, such as
static const char LogTable256[256] =
{
#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
};
unsigned int v; // 32-bit word to find the log of
unsigned r; // r will be lg(v)
register unsigned int t, tt; // temporaries
if (tt = v >> 16)
{
r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
}
else
{
r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
}
Of course, that may be overkill. But just shows how many fast ways there are to do things!
Upvotes: 1