Imported from previous forum
Hi,
What is the most efficient way to encode a given double value into a scaled number?
For example, assuming that I have 2.5555 represented as a double on Linux, and want to create a FAST wired representation of this this field?
Thanks,
Dimitry
Hi,
What is the most efficient way to encode a given double value into a
scaled number?For example, assuming that I have 2.5555 represented as a double
on Linux, and want to create a FAST wired representation of this
this field?Thanks, Dimitry
Dimitry,
at Pantor (Pantor Presto and ORDO), we avoid shifting between base 2 and base 10 representations in our processing chain as a conversion may become part of the bottleneck at extreme rates. Also, we hand scaled numbers to users of our Presto API to avoid a conversion unless / until it turns out to be necessary.
If doubles are what you have to work with, there is not much to do but to create an optimized converter with all the tweaks in the book.
Kind regards, Anders
Thanks, Anders.
Yes, the source value is represented as a native double (on a Linux host). How do I create a FAST representation of this field then? Using a scaled number with a base of 10 (as the Fast spec requires) will certainly make it a performance bottleneck, as you say. So, should I simply split it into base 2 exponent and mantissa (via frexp()) and assume base 2? Does it not break compliance with FAST?
Thanks,
Dimitry
Hi,
What is the most efficient way to encode a given double value into a
scaled number?For example, assuming that I have 2.5555 represented as a double
on Linux, and want to create a FAST wired representation of this
this field?Thanks, Dimitry
Dimitry,
at Pantor (Pantor Presto and ORDO), we avoid shifting between base 2 and
base 10 representations in our processing chain as a conversion may
become part of the bottleneck at extreme rates. Also, we hand scaled
numbers to users of our Presto API to avoid a conversion unless / until
it turns out to be necessary. If doubles are what you have to work with,
there is not much to do but to create an optimized converter with all
the tweaks in the book.Kind regards, Anders
Dimitry,
your interpretation is correct. The current definition of scaled numbers require that you use a base 10 exponent. Using base 2 would be a transgression.
Maybe we should put this up for discussion along with the other extension proposals?
/Rolf
Thanks, Anders.
Yes, the source value is represented as a native double (on a Linux
host). How do I create a FAST representation of this field then? Using a
scaled number with a base of 10 (as the Fast spec requires) will
certainly make it a performance bottleneck, as you say. So, should I
simply split it into base 2 exponent and mantissa (via frexp()) and
assume base 2? Does it not break compliance with FAST?Thanks, Dimitry
Hi,
What is the most efficient way to encode a given double value into a
scaled number?For example, assuming that I have 2.5555 represented as a double on
Linux, and want to create a FAST wired representation of this this
field?Thanks, Dimitry
Dimitry,
at Pantor (Pantor Presto and ORDO), we avoid shifting between base 2
and base 10 representations in our processing chain as a conversion
may become part of the bottleneck at extreme rates. Also, we hand
scaled numbers to users of our Presto API to avoid a conversion unless
/ until it turns out to be necessary. If doubles are what you have to
work with, there is not much to do but to create an optimized
converter with all the tweaks in the book.Kind regards, Anders
Thanks, Rolf.
I think this should be added to a list of FAST extensions. I think spec should provide an ability to specify the base. In the meantime, what would your recommend as the most efficient approach to send a scaled number whose original representation is a double without breaking the spec? (I am actually using the C++ implementation which we plan to open-source).
Thanks again,
Dimitry
Dimitry,
your interpretation is correct. The current definition of scaled numbers
require that you use a base 10 exponent. Using base 2 would be a
transgression.Maybe we should put this up for discussion along with the other
extension proposals?/Rolf
Thanks, Anders.
Yes, the source value is represented as a native double (on a Linux
host). How do I create a FAST representation of this field then? Using
a scaled number with a base of 10 (as the Fast spec requires) will
certainly make it a performance bottleneck, as you say. So, should I
simply split it into base 2 exponent and mantissa (via frexp()) and
assume base 2? Does it not break compliance with FAST?Thanks, Dimitry
Hi,
What is the most efficient way to encode a given double value into
a scaled number?For example, assuming that I have 2.5555 represented as a double
on Linux, and want to create a FAST wired representation of this
this field?Thanks, Dimitry
Dimitry,
at Pantor (Pantor Presto and ORDO), we avoid shifting between base 2
and base 10 representations in our processing chain as a conversion
may become part of the bottleneck at extreme rates. Also, we hand
scaled numbers to users of our Presto API to avoid a conversion
unless / until it turns out to be necessary. If doubles are what you
have to work with, there is not much to do but to create an
optimized converter with all the tweaks in the book.Kind regards, Anders
I believe Anders’ recommendation stands:
– all the tweaks in the book.
Best,
Rolf
Thanks, Rolf.
I think this should be added to a list of FAST extensions. I think
spec should provide an ability to specify the base. In the meantime,
what would your recommend as the most efficient approach to send a
scaled number whose original representation is a double without
breaking the spec? (I am actually using the C++ implementation which
we plan to open-source).Thanks again, Dimitry
Dimitry,
your interpretation is correct. The current definition of scaled
numbers require that you use a base 10 exponent. Using base 2 would be
a transgression.Maybe we should put this up for discussion along with the other
extension proposals?/Rolf
Thanks, Anders.
Yes, the source value is represented as a native double (on a Linux
host). How do I create a FAST representation of this field then?
Using a scaled number with a base of 10 (as the Fast spec requires)
will certainly make it a performance bottleneck, as you say. So,
should I simply split it into base 2 exponent and mantissa (via
frexp()) and assume base 2? Does it not break compliance with FAST?Thanks, Dimitry
Hi,
What is the most efficient way to encode a given double value
into a scaled number?For example, assuming that I have 2.5555 represented as a double
on Linux, and want to create a FAST wired representation of this
this field?Thanks, Dimitry
Dimitry,
at Pantor (Pantor Presto and ORDO), we avoid shifting between base
2 and base 10 representations in our processing chain as a
conversion may become part of the bottleneck at extreme rates.
Also, we hand scaled numbers to users of our Presto API to avoid a
conversion unless / until it turns out to be necessary. If doubles
are what you have to work with, there is not much to do but to
create an optimized converter with all the tweaks in the book.Kind regards, Anders
OK, thanks.
Dimitry
I believe Anders’ recommendation stands: – all the tweaks in the book.
Best, Rolf
Thanks, Rolf.
I think this should be added to a list of FAST extensions. I think
spec should provide an ability to specify the base. In the meantime,
what would your recommend as the most efficient approach to send a
scaled number whose original representation is a double without
breaking the spec? (I am actually using the C++ implementation which
we plan to open-source).Thanks again, Dimitry
Dimitry,
your interpretation is correct. The current definition of scaled
numbers require that you use a base 10 exponent. Using base 2 would
be a transgression.Maybe we should put this up for discussion along with the other
extension proposals?/Rolf
Thanks, Anders.
Yes, the source value is represented as a native double (on a
Linux host). How do I create a FAST representation of this field
then? Using a scaled number with a base of 10 (as the Fast spec
requires) will certainly make it a performance bottleneck, as you
say. So, should I simply split it into base 2 exponent and
mantissa (via frexp()) and assume base 2? Does it not break
compliance with FAST?Thanks, Dimitry
Hi,
What is the most efficient way to encode a given double value
into a scaled number?For example, assuming that I have 2.5555 represented as a
double on Linux, and want to create a FAST wired
representation of this this field?Thanks, Dimitry
Dimitry,
at Pantor (Pantor Presto and ORDO), we avoid shifting between
base 2 and base 10 representations in our processing chain as a
conversion may become part of the bottleneck at extreme rates.
Also, we hand scaled numbers to users of our Presto API to avoid
a conversion unless / until it turns out to be necessary. If
doubles are what you have to work with, there is not much to do
but to create an optimized converter with all the tweaks in the
book.Kind regards, Anders
Dimitry,
I had posted a related thread a while back, see http://fixprotocol.org/discuss/read/eebb5ac9
I think the optimal way to do this is to determine the amount of precision you want from the IEEE float or double, and extract the mantissa and exponent to create a scaled decimal. As you would expect, this needs to be optimized, and I am not sure the standard C lib methods are the way to go. Then comes the question of rounding vs. truncation.
So, does someone want to submit a good algorithm for conversion ?
/Daniel
Thanks, Daniel.
My first instinct was to use frexp() for double->decimal and ldexp() from decimal to double. When I ran some initial benchmarks today I did not notice any big overhead.
fxrexp() returns an integer exponent and normalized double mantissa (between 0.5 and 1.0). The real challenge is how to represent the results in a FAST wire representation - as the mantissa is still represented as a double/float rather then integer field. It is possible the send mantissa as a bit vector but then it will use at least 4/8 bytes) not counting the length. So, I don’t really like this approach.
Dimitry
Dimitry, I had posted a related thread a while back, see
http://fixprotocol.org/discuss/read/eebb5ac9I think the optimal way to do this is to determine the amount of
precision you want from the IEEE float or double, and extract the
mantissa and exponent to create a scaled decimal. As you would expect,
this needs to be optimized, and I am not sure the standard C lib methods
are the way to go. Then comes the question of rounding vs. truncation.So, does someone want to submit a good algorithm for conversion ?
/Daniel
Hi everybody,
I believe you should first handle the rounding question
(truncation is much worse than rounding, I would not even
consider it) Once you decide how to round you can decide
how to pack the rounded result.
Let me explain why with the example x = 2.5555 mentioned
earlier. This number cannot be represented exactly as
a double. If you do something like
double xr = atof(“2.5555”)
then the xr you get is not exactly equal to 2.5555.
Actually, xr is the horrendous number
xr = 2555499999999999882760448599583469331264495849609375 x 10^(-51)
In principle you could convert xr back to decimal
with no rounding (its is always possible to
convert from IEEE float,double to decimal with
no rounding errors if you are wiling to use
enough bits to represent the result)
However, the exact conversion is clearly a
bad idea because you would get a mantissa with
too many digits. Therefore, it is best to
round this number somehow before sending it.
Once you decide what is a reasonable rounding
policy I may try to help you with the algorithm.
Walter.
Thanks, Daniel.
My first instinct was to use frexp() for double->decimal and ldexp()
from decimal to double. When I ran some initial benchmarks today I did
not notice any big overhead.fxrexp() returns an integer exponent and normalized double mantissa
(between 0.5 and 1.0). The real challenge is how to represent the
results in a FAST wire representation - as the mantissa is still
represented as a double/float rather then integer field. It is possible
the send mantissa as a bit vector but then it will use at least 4/8
bytes) not counting the length. So, I don’t really like this approach.Dimitry
Dimitry, I had posted a related thread a while back, see
http://fixprotocol.org/discuss/read/eebb5ac9I think the optimal way to do this is to determine the amount of
precision you want from the IEEE float or double, and extract the
mantissa and exponent to create a scaled decimal. As you would expect,
this needs to be optimized, and I am not sure the standard C lib
methods are the way to go. Then comes the question of rounding vs.
truncation.So, does someone want to submit a good algorithm for conversion ?
/Daniel
Walter,
The rounding or truncating really should be left at the application level, and FAST (and FIX) should not try to impose any type of rules to alter the original value. If you want to convey a floating point double with 51 points of precision, the FAST scaled decimal can do that. One of the reasons we chose a Base 10 approach rather than using a IEEE Base 2 approach was to achieve exact precision. The scaled decimal in FAST will allow up to 63 points of precision in either a negative or positive value [exponent range of [-63…63].
Usually the producer of the double or float would be responsible for rounding or truncating it down to a reasonable precision for the specific business case (ex. VWAP w/ 4 points of precision). From there it would be converted into a scaled decimal with a exponent = 4 in the case of the example.
So, assuming you have a nice rounded IEEE float with the value of 12.34500, what is the most efficient way to convert that to a FAST scaled decimal, using the smallest exponent possible without losing any precision ?
I have a few methods, I will come up with one that I think is the fastest, and we can have a bake off 
/Daniel
Dimity,
There are two ways to look at this problem. If you know ahead of time that you are going to always use a fixed number of decimal precision (again, let’s say your business rules require a precision of 4 decimal points), and you have already either rounded your float to those 4 points of precision, or truncation is okay for your application, then
the conversion is simple:
float x = 123.4500
int64_t mantissa = (int64_t)(x * 10000);
int32_t exponent = 4;
The more complicated case is when you are trying to generically convert a floating point number to a FAST scaled decimal with
a.) not losing any precision, and
b.) optimizing the exponent as to keep the mantissa as small as possible.
For this, take a look at modf() in the standard C library. It breaks a float into the whole and fractional parts. You can then cast or convert the float whole and fractional parts to integers. Next, you would remove any unnecessary precision from the fractional integer by using a mod and divide by 10 while there are trailing zeros left.
Finally, to create the FAST scaled decimal mantissa, you must determine the FAST exponent by inspecting the size of the fractional integer, and then adjust the whole integer by that factor, and add back the fractional part.
I am working on C/C++ an example for you…
/Daniel
Daniel and Dimitri,
These floating point issues can get very tricky. I,
for instance, have been mislead by them many, many times.
One point I am trying to make is that you don´t have the
12.34500 value in the double world to start with.
There is no such a thing as a nice double with value x = 12.34500.
The closest you will ever get to x is xr equal to
123450000000000006394884621840901672840118408203125 x 10^(-49)
with an error of about 6.4 x 10^(-16).
As a result, in most cases the double produced by rounding
will have its least signficant decimal different from zero
(for instance 12.34500 would look like 13.3450000000001)
and you would have no compression: the full 64 bits of the
number would need to be sent down the wire, because you would
never know if that last one was there on purpose or it
was caused by rounding. Or, in the bit vector alternative
suggest a few messages earlier, the bit vector would have
its maximum length most of the time.
as for Daniel´s suggestion,
float x = 123.4500
int64_t mantissa = (int64_t)(x * 10000);
int32_t exponent = 4;
I would do something different, but
his suggestion is much simpler and he
is right about the details: it can get
very messy in general cases.
I would go roughly like this
(assuming x > 0, that we have a unsigned
int with 128 bits and disregarding some details,
so that you get the idea):
int e;
double xm = frexp(x,&e);
UINT64 m = (UINT64) _scalb(xm,53); // now x = 2^(e - 53) m exactly
UINT128 result = Mult(m,5^4);
// now x = result * 2^(e - 49) * 10^(-4), exactly
if( e >= 49 )
{
result <<= (e - 49);
// now x = result * 10^(-4) exactly
}
else
{
UINT64 one = 1;
UINT64 mask = ((one << (49 - e)) - 1);
UINT128 reminder = result & mask;
if( 2 * reminder > mask )
result = (result >> (49 - e)) + 1;
else
result >>= 49 - e;
}
Hope this helps (but don´t trust the details…)
Walter.
Dimity, There are two ways to look at this problem. If you know ahead of
time that you are going to always use a fixed number of decimal
precision (again, let’s say your business rules require a precision of 4
decimal points), and you have already either rounded your float to those
4 points of precision, or truncation is okay for your application, then
the conversion is simple:float x = 123.4500 int64_t mantissa = (int64_t)(x * 10000); int32_t
exponent = 4;The more complicated case is when you are trying to generically convert
a floating point number to a FAST scaled decimal with
a.) not losing any precision, and
b.) optimizing the exponent as to keep the mantissa as small as
possible.For this, take a look at modf() in the standard C library. It breaks a
float into the whole and fractional parts. You can then cast or convert
the float whole and fractional parts to integers. Next, you would remove
any unnecessary precision from the fractional integer by using a mod and
divide by 10 while there are trailing zeros left.Finally, to create the FAST scaled decimal mantissa, you must determine
the FAST exponent by inspecting the size of the fractional integer, and
then adjust the whole integer by that factor, and add back the
fractional part.I am working on C/C++ an example for you…
/Daniel
Thanks, Walter,
you are right - using byte vector for mantissa essentially erases most of FAST compression benefits. As for the algorithm, I think Daniel’s approach is simpler and is probably more efficient, especially in the first case (there is only one multiplication operation). In the current implementation, we perform the conversion as double->string->FAST scaled number, so I am curious how much faster is double->FAST decimal approach is.
Dimitry
Daniel and Dimitri,
These floating point issues can get very tricky. I, for instance, have been mislead by them many, many times.One point I am trying to make is that you don´t have the
12.34500 value in the double world to start with. There is no such a
thing as a nice double with value x = 12.34500. The closest you will
ever get to x is xr equal to
123450000000000006394884621840901672840118408203125 x 10^(-49) with
an error of about 6.4 x 10^(-16).As a result, in most cases the double produced by rounding will have
its least signficant decimal different from zero (for instance 12.34500
would look like 13.3450000000001) and you would have no compression:
the full 64 bits of the number would need to be sent down the wire,
because you would never know if that last one was there on purpose or
it was caused by rounding. Or, in the bit vector alternative suggest a
few messages earlier, the bit vector would have its maximum length most
of the time.as for Daniel´s suggestion,
float x = 123.4500 int64_t mantissa = (int64_t)(x * 10000); int32_t
exponent = 4;I would do something different, but his suggestion is much simpler and
he is right about the details: it can get very messy in general cases.I would go roughly like this (assuming x > 0, that we have a
unsigned int with 128 bits and disregarding some details, so that
you get the idea):int e; double xm = frexp(x,&e); UINT64 m = (UINT64) _scalb(xm,53); //
now x = 2^(e - 53) m exactlyUINT128 result = Mult(m,5^4); // now x = result * 2^(e - 49) * 10^(-
4), exactlyif( e>= 49 ) { result <<= (e - 49); // now x = result * 10^(-4) exactly
} else { UINT64 one = 1; UINT64 mask = ((one << (49 - e)) - 1);
UINT128 reminder = result & mask;
if( 2* reminder > mask ) result = (result >> (49 - e)) + 1; else
result >>= 49 - e; } Hope this helps (but don´t trust the
details…)Walter.Dimity, There are two ways to look at this problem. If you know ahead
of time that you are going to always use a fixed number of decimal
precision (again, let’s say your business rules require a precision of
4 decimal points), and you have already either rounded your float to
those 4 points of precision, or truncation is okay for your
application, then the conversion is simple:float x = 123.4500 int64_t mantissa = (int64_t)(x * 10000); int32_t
exponent = 4;The more complicated case is when you are trying to generically
convert a floating point number to a FAST scaled decimal with
a.) not losing any precision, and
b.) optimizing the exponent as to keep the mantissa as small as
possible.For this, take a look at modf() in the standard C library. It breaks a
float into the whole and fractional parts. You can then cast or
convert the float whole and fractional parts to integers. Next, you
would remove any unnecessary precision from the fractional integer by
using a mod and divide by 10 while there are trailing zeros left.Finally, to create the FAST scaled decimal mantissa, you must
determine the FAST exponent by inspecting the size of the fractional
integer, and then adjust the whole integer by that factor, and add
back the fractional part.I am working on C/C++ an example for you…
/Daniel
Dimitri,
I agree that Daniel´s approach is simpler
and is certainly faster. It is clearly the best
option if you do not worry about high precision:
who cares about the 5th digit in a million
dollar amount?
(it is not bad in this aspect too, it is
just no optimal)
Last night I played a little bit with this
stuff and come up with the code pasted below.
It is specific for the 10^-4 precision and
certainly not perfect. I believe that, on
the average, if gives full precision using
a few shifts and multiplies of 64bit integers
(which is quite adequate for the 64bit platforms)
The “average” aspect comes from the normalization
step, which is not considered by Daniel and can
be quite time consuming. In the algorithm below
I belive that in 90% of the time there will
be no need to normalize the result, in 9% it
will normalized with one division, in 0.09%
normalization will take 2 divisions and so on.
The same approach works for precision 0,1,2 and 3
but higher precision would require 96bits arithmetic
or even higher for very high precisions.
Anyway, here is the code:
Walter
//
// Given a double x >= 0 and and integer precision
// DoubleToDecimal4 returns a mantissa m and
// assigns an exponent to e exp so that
//
// a) |x - m * 10^(-e)| <= 0.5 * 10^(-4)
// b) either x = m = 0 or (m % 10) != 0
//
// The function may trhow an exception if
// |x| >= 10^250 because for some x in this
// range case no such e and m exist.
//
#define FORMAT_SENSITIVE 1
__int64 DoubleToDecimal4(double x, int& exp)
{
int e2;
int sign;
__int64 mLong;
if( x < 0 )
{
x = -x;
sign = -1;
}
else
{
sign = 1;
}
double md = frexp(x,&e2);
mLong = (__int64) _scalb(md,53);
// At this point we have x = 2^(e2 - 53) * mLong (exactly, no rounding)
int e;
if( e2 < 49) // mLong * (2^(e2 - 49) * 5^4 is not an integer
{
int shift = 49 - e2;
if( shift >= 64 ) // for instance in the case of denormals
{
exp = 0;
return 0;
}
mLong *= 625; // 625 = 5^4 < 2^10 and since mLong <= 2^53 there is no overflow here
__int64 mask = (LongOne << shift) - 1;
__int64 remainder = mLong & mask;
if( (remainder << 1) >= mask )
{
mLong = (mLong >> shift) + 1;
}
else
{
mLong >>= shift;
}
if( mLong == 0 )
{
exp = 0;
return 0;
}
e = 4;
}
else
{
// here e2 >= 49 e mLong > 0
// Since x = 2^(e2 - 49) * 5^4 * mLong * 10^-4 there will
// be no rounding in this case.
switch(e2)
{
case 49:
{
if( mLong & 1 )
{
exp = 4;
return 625 * mLong;
}
mLong >>= 1;
// there is no break here
}
case 50:
{
if( mLong & 1 )
{
exp = 3;
return 125 * mLong;
}
mLong >>= 1;
// there is no break here
}
case 51:
{
if( mLong & 1 )
{
exp = 2;
return 25 * mLong;
}
mLong >>= 1;
// there is no break here
}
case 52:
{
if( mLong & 1 )
{
exp = 1;
return 5 * mLong;
}
mLong >>= 1;
}
case 53:
{
e = 0;
break;
}
default:
{
e = 0; // in the next while we try to divide mLong by 5 instead
// of multiply it by 2 in order to avoid overflow in mLong
do
{
__int64 remainder = (mLong % 5);
if( remainder )
{
int shift = e2 - 53;
if( mLong >= (LongOne << (63 - shift)) )
{
throw std::exception(“Overflow in function DoubleToDecimal4”);
}
exp = e;
return sign * (mLong << shift);
}
–e;
mLong /= 5;
}
while( --e2 > 53 );
}
}
}
// normalizing mLong
while( (mLong % 10) == 0 )
{
–e;
mLong /= 10;
}
exp = e;
return sign * mLong;
}
Thanks, Walter,
you are right - using byte vector for mantissa essentially erases most
of FAST compression benefits. As for the algorithm, I think Daniel’s
approach is simpler and is probably more efficient, especially in the
first case (there is only one multiplication operation). In the current
implementation, we perform the conversion as double->string->FAST
scaled number, so I am curious how much faster is double->FAST decimal
approach is.Dimitry
Daniel and Dimitri,
These floating point issues can get very tricky. I, for instance, have been mislead by them many, many times.One point I am trying to make is that you don´t have the
12.34500 value in the double world to start with. There is no such a
thing as a nice double with value x = 12.34500. The closest you
will ever get to x is xr equal to
123450000000000006394884621840901672840118408203125 x 10^(-49) with
an error of about 6.4 x 10^(-16).As a result, in most cases the double produced by rounding will have
its least signficant decimal different from zero (for instance
12.34500 would look like 13.3450000000001) and you would have no
compression: the full 64 bits of the number would need to be sent down
the wire, because you would never know if that last one was there on
purpose or it was caused by rounding. Or, in the bit vector
alternative suggest a few messages earlier, the bit vector would have
its maximum length most of the time.as for Daniel´s suggestion,
float x = 123.4500 int64_t mantissa = (int64_t)(x * 10000); int32_t
exponent = 4;I would do something different, but his suggestion is much simpler and
he is right about the details: it can get very messy in general cases.I would go roughly like this (assuming x > 0, that we have a
unsigned int with 128 bits and disregarding some details, so that
you get the idea):int e; double xm = frexp(x,&e); UINT64 m = (UINT64) _scalb(xm,53); //
now x = 2^(e - 53) m exactlyUINT128 result = Mult(m,5^4); // now x = result * 2^(e - 49) * 10^(-
4), exactlyif( e>= 49 ) { result <<= (e - 49); // now x = result * 10^(-4)
exactly } else { UINT64 one = 1; UINT64 mask = ((one << (49 - e)) -
1); UINT128 reminder = result & mask; if( 2* reminder > mask ) result
= (result >> (49 - e)) + 1; else result >>= 49 - e; } Hope this helps
(but don´t trust the details…)Walter.Dimity, There are two ways to look at this problem. If you know
ahead of time that you are going to always use a fixed number of
decimal precision (again, let’s say your business rules require a
precision of 4 decimal points), and you have already either rounded
your float to those 4 points of precision, or truncation is okay for
your application, then the conversion is simple:float x = 123.4500 int64_t mantissa = (int64_t)(x * 10000); int32_t
exponent = 4;The more complicated case is when you are trying to generically
convert a floating point number to a FAST scaled decimal with
a.) not losing any precision, and
b.) optimizing the exponent as to keep the mantissa as small as
possible.For this, take a look at modf() in the standard C library. It breaks
a float into the whole and fractional parts. You can then cast or
convert the float whole and fractional parts to integers. Next, you
would remove any unnecessary precision from the fractional integer
by using a mod and divide by 10 while there are trailing zeros left.Finally, to create the FAST scaled decimal mantissa, you must
determine the FAST exponent by inspecting the size of the fractional
integer, and then adjust the whole integer by that factor, and add
back the fractional part.I am working on C/C++ an example for you…
/Daniel
Daniel, thanks very much, this approach looks very promising. I will run performance tests in the next few days.
Dimitry
Dimity, There are two ways to look at this problem. If you know ahead of
time that you are going to always use a fixed number of decimal
precision (again, let’s say your business rules require a precision of 4
decimal points), and you have already either rounded your float to those
4 points of precision, or truncation is okay for your application, then
the conversion is simple:float x = 123.4500 int64_t mantissa = (int64_t)(x * 10000); int32_t
exponent = 4;The more complicated case is when you are trying to generically convert
a floating point number to a FAST scaled decimal with
a.) not losing any precision, and
b.) optimizing the exponent as to keep the mantissa as small as
possible.For this, take a look at modf() in the standard C library. It breaks a
float into the whole and fractional parts. You can then cast or convert
the float whole and fractional parts to integers. Next, you would remove
any unnecessary precision from the fractional integer by using a mod and
divide by 10 while there are trailing zeros left.Finally, to create the FAST scaled decimal mantissa, you must determine
the FAST exponent by inspecting the size of the fractional integer, and
then adjust the whole integer by that factor, and add back the
fractional part.I am working on C/C++ an example for you…
/Daniel