converting float to double

D

Dilip

Dik said:
Consider not to use floating point for stock prices. Floating point
inherently carries imprecision (especially if you want to do decimal
calculations), which you do not want with stock prices.

THis isn't always possible. The market data vendor I connect to
insists that I read the stock prices as float. So when I reach into
the byte-stream I will have to memcpy sizeof(float) number of bytes.
Since everywhere else the system uses double to hold these prices, I
had no choice but to stuff that retreived float value into a double
causing all these problems.
 
R

Random832

2006-12-20 said:
THis isn't always possible. The market data vendor I connect to
insists that I read the stock prices as float.

Get a new vendor?
So when I reach into the byte-stream I will have to memcpy
sizeof(float) number of bytes. Since everywhere else the system uses
double to hold these prices, I had no choice but to stuff that
retreived float value into a double causing all these problems.

Well - if you can't get a better vendor, the best way would be to do this:

#include <math.h>
//...
float floating_price;
long int price_cents;
//...
price_cents = round(f*100.);

That way you'll actually get the value to the nearest cent, instead of
doing "voodoo magic" that happens to get the right answer in one
specific case you tested it on.

If you need tenths of a cent, use 1000. there, etc, whatever precision
you need. From that point, use the integer representation throughout
your program.
 
B

Ben Pfaff

Random832 said:
Well - if you can't get a better vendor, the best way would be to do this:

#include <math.h>
//...
float floating_price;
long int price_cents;
//...
price_cents = round(f*100.);

For what it's worth, the round function is new in C99.
 
E

Ernie Wright

Dilip said:
THis isn't always possible. The market data vendor I connect to
insists that I read the stock prices as float. So when I reach into
the byte-stream I will have to memcpy sizeof(float) number of bytes.
Since everywhere else the system uses double to hold these prices, I
had no choice but to stuff that retreived float value into a double
causing all these problems.

Putting float values into doubles probably isn't the cause of your
problems. A double will hold exactly the same value as the original
float.

In most implementations, both float and double represent numbers as

(1 + m / 2^b) * 2^e

where m is (part of) the mantissa, b is the number of bits in m, e is
the exponent, and '^' denotes exponentiation. b is 23 for floats and 53
for doubles. Given the m, b, e of a float, you get the double with

m <<= 30
b += 30
e = e

Or to put it another way,

float: 59.89 -> (1 + 7311196 / 8388608) * 32
double: 59.89 -> (1 + (7311196 << 30) / (8388608 << 30)) * 32

The values are identical, so the problems must be arising from what is
being done with them.

- Ernie http://home.comcast.net/~erniew
 
W

William Hughes

Ernie said:
Putting float values into doubles probably isn't the cause of your
problems. A double will hold exactly the same value as the original
float.

True, but irrelevent.

Mathematically

(float) (1000.0 * f) =/= 1000.0 * f

There is a small bit of rounding. So

(double)( (float) 1000.0*f)/ 1000.0 =/= f

In the present case we start out with a value just less than a multiple
of
a whole cent, and end up with a value just greater than a multiple
of a cent.

- William Hughes
 
C

CBFalconer

Dilip said:
THis isn't always possible. The market data vendor I connect to
insists that I read the stock prices as float. So when I reach
into the byte-stream I will have to memcpy sizeof(float) number of
bytes. Since everywhere else the system uses double to hold these
prices, I had no choice but to stuff that retreived float value
into a double causing all these problems.

This is inherently impossible. While some systems use IEEE float
format, many do not, so you don't even know the bit pattern coming
in. Are you sure you aren't reading and converting a text stream?
If so all you have to do is write a suitable parser for a
particular text format, say dddd.dd, where d is a digit.
 
W

William Hughes

Dilip said:
THis isn't always possible. The market data vendor I connect to
insists that I read the stock prices as float. So when I reach into
the byte-stream I will have to memcpy sizeof(float) number of bytes.
Since everywhere else the system uses double to hold these prices, I
had no choice but to stuff that retreived float value into a double
causing all these problems.

A system that uses floating point variables to store prices should
work correctly if a price is just above or just below the
correct price (e.g for a price of 0.010001 dollars or 0.009998
dollars).
The system you use does not have this property. It needs
to be fixed. However, it appears that by management fiat you have
to use this system, and any problems are deemed yours.

A possible workaround:

Read the prices as float
Round to the nearest cent or tenth of a cent (*)
Convert to double
Add a fudge factor of 0.00000001

Now your prices will be subtly wrong, but they will be subtly wrong in
the correct direction. This should work as well as the
(double)(f*1000.0)/1000.0
kludge, and will work for any value. (adding the fudge factor may or
may
not be necessary. It would not be necessary, but for the fact that you
have to use a broken system. There may be a price that when expressed
as a double is slightly below the true price.)

* if you don't have access to a C99 type round() function, roll your
own
(e.g. floor(100.0*dd + 0.5)/100.0) or sprintf the value and sscanf
it back

- William
Hughes
 
E

Ernie Wright

William said:
True, but irrelevent.

When someone writes that "stuffing a float value into a double causes
all these problems," it's perfectly relevant to tell them that's not the
case. Or to put it another way, if the OP changed all the doubles to
float, the problems would be exactly the same.
(double)( (float) 1000.0*f)/ 1000.0 =/= f

In the present case we start out with a value just less than a
multiple of a whole cent, and end up with a value just greater than a
multiple of a cent.

That wasn't the problem the OP was referring to. It was a "solution."

The real problem is the truncation, mentioned by the OP in his first
post but not shown in code. The truncation is where the code is broken.

- Ernie http://home.comcast.net/~erniew
 
W

William Hughes

Ernie said:
which is only one of several widely used rounding rules, and not
necessarily the one preferred for financial transactions.

The problem is "take a price, assumed to be an integer
number of cents, expressed as a floating
point number in dollars, and convert it to an integer number
of cents".

The expression given does this correctly. That it might not be
the correct solution for some other problem is irrelevent.


- William Hughes
 
C

CBFalconer

Ernie said:
which is only one of several widely used rounding rules, and not
necessarily the one preferred for financial transactions.

which won't matter in the case posted by the OP. He started with a
constant of the form 89.13, i.e. with exactly 2 decimal places.
The above will capture the original value.
 
D

Dik T. Winter

> Dilip wrote: ....
>
> A system that uses floating point variables to store prices should
> work correctly if a price is just above or just below the
> correct price (e.g for a price of 0.010001 dollars or 0.009998
> dollars).
> The system you use does not have this property. It needs
> to be fixed.

How do you fix a system that follows the C standard?
> A possible workaround:
> Read the prices as float
> Round to the nearest cent or tenth of a cent (*)
> Convert to double
> Add a fudge factor of 0.00000001
> Now your prices will be subtly wrong, but they will be subtly wrong in
> the correct direction. This should work as well as the
> (double)(f*1000.0)/1000.0
> kludge, and will work for any value.

But after subtraction you can be subtly wrong the wrong way. To avoid
all this is done by internally working with integers, longs, long longs,
or whatever integer size you need.
 
D

dcorbit

CBFalconer said:
and unnecessary.

price_cents = 100 * floating_price + 0.5;
Almost:
From the C-FAQ:
14.6: How do I round numbers?

A: The simplest and most straightforward way is with code like

(int)(x + 0.5)

This technique won't work properly for negative numbers,
though (for which you could use something like
(int)(x < 0 ? x - 0.5 : x + 0.5)).

Also, most banking institutions will prefer banker's rounding to simple
rounding.
 
K

Keith Thompson

CBFalconer said:
This is inherently impossible. While some systems use IEEE float
format, many do not, so you don't even know the bit pattern coming
in. Are you sure you aren't reading and converting a text stream?
If so all you have to do is write a suitable parser for a
particular text format, say dddd.dd, where d is a digit.

It's inherently possible to do this portably.

My guess (and it's only a guess) is that his vendor is providing raw
data of type "float", probably in 32-bit IEEE format in some
particular byte order. If Dilip has already been successful in
storing this incoming data in objects of type "float", then that part
of the problem is solved.

The remaining problem is what to do with the information once he has
it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top