473,657 Members | 2,351 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

converting float to double


Recently in our code, I ran into a situation where were stuffing a
float inside a double. The precision was extended automatically
because of that. To make a long story short, this caused problems
elsewhere in another part of the system where that figure was used for
some calculation and some eventual truncation led to the system going
haywire. So my question is, given this code:

int main()
{
float f = 59.89F;
/* the following line caused problems */
double d = f;

/* they ended up solving it like this */
f *= 1000.0;
double dd = (double)f / 1000.0;

return 0;
}

I see what is being done but why does the latter make the situation
better?
(consider 'f' in real life to hold stock prices)

Dec 19 '06
116 35833
Dilip wrote:
I came across that paper quite a few times in the past. I never
realized one day I would need to know that amount of detail. Do you
have any insights into that normalized integer thing everyone has been
pointing out so far? If one of you can give me an example, i'd
appreciate it.
Store the amount as pennies in a long long integer. The Goldberg paper
is a must read if you are doing numerics with other people's money.
IMO-YMMV.

#include <stdio.h>
#include <stdlib.h>

char string[256];
int main(void)
{
long long pennies;

try_again:
puts("Enter a cost in pennies:");
if (fgets(string, sizeof string, stdin)) {
sscanf(string, "%lld", &pennies);
printf("That's %lld dollars and %lld cents or $%lld.%lld\n",
pennies / 100, pennies % 100, pennies / 100, pennies % 100);
} else
goto try_again;

return EXIT_SUCCESS;
}
/* e.g.:
Enter a cost in pennies:
99999999
That's 999999 dollars and 99 cents or $999999.99
*/

Dec 19 '06 #11

"Dilip" <rd*****@lycos. comwrote in message
news:11******** **************@ 79g2000cws.goog legroups.com...
>
Recently in our code, I ran into a situation where were stuffing a
float inside a double. The precision was extended automatically
because of that. To make a long story short, this caused problems
elsewhere in another part of the system where that figure was used for
some calculation and some eventual truncation led to the system going
haywire. So my question is, given this code:

int main()
{
float f = 59.89F;
/* the following line caused problems */
double d = f;

/* they ended up solving it like this */
f *= 1000.0;
double dd = (double)f / 1000.0;

return 0;
}

I see what is being done but why does the latter make the situation
better?
(consider 'f' in real life to hold stock prices)
That is called hacking.
Somehow a cent must have been knocked off in the code - decimals cannot be
represented perfectly in binary floating point notation - leading the
program to suspect salami tactics. Multiplying by 1000 converts the number
to an integer, and the division is done in double precision, so the cent
might not have been dropped.

This approach to problem solving, incidentally, is known as hacking, and is
an indication that the company's management is in a serious mess.
--
www.personal.leeds.ac.uk/~bgy1mm
freeware games to download.

Dec 19 '06 #12
Dilip wrote:
Keith Thompson wrote:
>CBFalconer <cb********@yah oo.comwrites:
>>Dilip wrote:

Recently in our code, I ran into a situation where were stuffing a
float inside a double. The precision was extended automatically
because of that. To make a long story short, this caused problems
elsewhere in another part of the system where that figure was used
for some calculation and some eventual truncation led to the system
going haywire. So my question is, given this code:

int main()
{
float f = 59.89F;
/* the following line caused problems */
double d = f;

/* they ended up solving it like this */
f *= 1000.0;
double dd = (double)f / 1000.0;

return 0;
}

I see what is being done but why does the latter make the
situation better?
(consider 'f' in real life to hold stock prices)

It doesn't. It should make it dead wrong. Either you are not
showing the real situation or you have a compiler bug.

Are you sure about that? The code multiplies f by 1000.0, then
divides the result by 1000.0. The *mathematical* result is the same,
but the way it's done is likely to change the rounding behavior
slightly. It's not likely to be a general solution to any problem.
It smacks of "cargo cult programming"; see
<http://www.catb.org/~esr/jargon/html/C/cargo-cult-programming.htm l>.

I totally agree which is the reason why I posted to this NG to
understand what exactly is being solved by that 1000.0 workaround.
>Another good resource is Goldberg's paper "What Every Computer
Scientist Should Know About Floating-Point". Google "goldberg
floating" to find it.

I came across that paper quite a few times in the past. I never
realized one day I would need to know that amount of detail. Do you
have any insights into that normalized integer thing everyone has been
pointing out so far? If one of you can give me an example, i'd
appreciate it.
As a temporary measure, try converting the value to a long:

long longvalueincent s;

longvalueincent s = (f * 100) + 0.5; /* control rounding */

and, to print it out, try:

printf("%ld.%ld ", longvalueincent s/100, longvalueincent s%100);
fflush(stdout);

Note that you don't need any casts. A cast is probably an error.

You can probably incorporate all this in a single function that
dumps the double rounded to two decimals, but reading the printf
documentation is likely to be more rewarding.

You could also hire me. :-) See below.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home .att.net>
Dec 19 '06 #13

<dc*****@connx. comwrote in message
news:11******** **************@ t46g2000cwa.goo glegroups.com.. .
Dilip wrote:
>I came across that paper quite a few times in the past. I never
realized one day I would need to know that amount of detail. Do you
have any insights into that normalized integer thing everyone has been
pointing out so far? If one of you can give me an example, i'd
appreciate it.

Store the amount as pennies in a long long integer. The Goldberg paper
is a must read if you are doing numerics with other people's money.
IMO-YMMV.
Or in a double, but as an integral number of pence.
That way the maths is accurate up to 48 bits or so, and degrades garcefully
under hyperinflation.
--
www.personal.leeds.ac.uk/~bgy1mm
freeware games to download.

Dec 20 '06 #14

Dilip wrote:
Recently in our code, I ran into a situation where were stuffing a
float inside a double. The precision was extended automatically
because of that. To make a long story short, this caused problems
elsewhere in another part of the system where that figure was used for
some calculation and some eventual truncation led to the system going
haywire. So my question is, given this code:

int main()
{
float f = 59.89F;
/* the following line caused problems */
double d = f;

/* they ended up solving it like this */
f *= 1000.0;
double dd = (double)f / 1000.0;

return 0;
}

I see what is being done but why does the latter make the situation
better?
(consider 'f' in real life to hold stock prices)
For the purposes of this explanation treat double as exact
and float as approximate.

The problem is that most exact decimal fractions cannot
be represented exactly by floats. So you need to use
a value that is just a little above or just a little below.

Suppose we have

f=0.0001

then f will have a value slightly below 0.0001
(or maybe not, but it did on my machine just now).

Now multiply by 1000
Now f will have to approximate 0.1. The best approximation is
a value slightly above 0.1 (at least on my machine just now)
So after

1000*f

we get a value slightly above 0.1. We now assign to a double

dd=1000*f

(This is done by first calculating 1000*f as a float and then
assigning to double). We next divide dd by 1000.
dd now has a value slightly greater than 0.0001.

So the net effect of multiplying by 1000, storing in a double, then
dividing by 1000, is to convert a value slightly below 0.0001 to a
value
slightly above 0.0001. Because the code is clearly incompetently
written, it will later blindly truncate, converting a miniscule
difference into
a noticable one.

Of course if you start out with some other value for f, something
different
may happen. Something different may happen on different machines,
or with different compilers, or with different compiler options, or on
different days, or on different runs, or at different times within the
same run.

I wouldn't trust this code in a rigged demo.

- William Hughes.

Dec 20 '06 #15
dc*****@connx.c om wrote:
printf("That's %lld dollars and %lld cents or $%lld.%lld\n",
pennies / 100, pennies % 100, pennies / 100, pennies % 100);
printf("That's %lld dollars and %lld cents or $%lld.%02lld\n" ,
pennies / 100, pennies % 100, pennies / 100, pennies % 100);
--
Thad
Dec 20 '06 #16
In article <11************ **********@79g2 000cws.googlegr oups.com"Dilip" <rd*****@lycos. comwrites:
Recently in our code, I ran into a situation where were stuffing a
float inside a double. The precision was extended automatically
because of that. To make a long story short, this caused problems
elsewhere in another part of the system where that figure was used for
some calculation and some eventual truncation led to the system going
haywire. So my question is, given this code:
....
float f = 59.89F;
/* the following line caused problems */
double d = f;
d will be approximately equal to 59.89 with the same precision as f
/* they ended up solving it like this */
f *= 1000.0;
By sheer luck (due to the rounding rules) f is exactly equal to 59890.
(You could even use 100 here with exactly the same results.)
double dd = (double)f / 1000.0;
And so this is a better approximation in double precision of 59.89.
I see what is being done but why does the latter make the situation
better?
It is only luck. For other values of f it could fail and dd could
(I think) even be worse than d.
(consider 'f' in real life to hold stock prices)
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.
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/
Dec 20 '06 #17
In article <11************ **********@79g2 000cws.googlegr oups.com"Dilip" <rd*****@lycos. comwrites:
....
I am showing exactly what is being done in our codebase. Why do you
say there is a compiler bug?
There is indeed none, but you are misunderstandin g floating point.
If you try the example, as soon as the
1st line is executed the variable f contains 59.889999. After its
stuffed into double d, it becomes 59.889999389648 437 (I know these
values vary after a certain decimal position).
They do not vary, but you should print with sufficient precision.
The exact value stored in both f and d is:
59.889999389648 4375
The
multiplication/division to 1000.0 however produces 59.890000000000 001
in dd.
Actually the value stored in dd is:
59.890000000000 000568434188608 080148696899414 0625
But as I stated in another article, it is only luck that this value is
larger than 59.89.
The management somehow feels thats a more "accurate"
representation. I guess after rounding off to 2 decimal places they
expected 59.89 but a bug somewhere in the code ensured that the former
case got rounded off to 59.88.
Probably not rounding was done but truncation. In that case
when d * 100 is truncated to int it will indeed give 59.88 and
dd * 100 is truncated to 59.89. I can come up with initial values
where this is all reversed. And it is even platform dependent.
See message <11************ **********@48g2 000cwx.googlegr oups.com>
in comp.arch.arith metic and the associated thread.
It was off by a penny and that
triggered major problems in other calculations.
If off by a penny triggers major problems, you should *really* consider
using integer arithmetic in pennies.
Since stock prices (today)
are decimalized, just use a normalized integer of suitable size.
Read Knuth (TAOCP) on floating point and expected errors.

I am not exactly unfamiliar with floating point representations and its
associated accuracy related problems but I think this is the first time
I am working in a domain where such problems crop up on a more frequent
basis. Could you please elaborate on that "normalized integer of
suitable size"?
Use 64 bit integers for the amounts in pennies. When you use floating
point and store the amount in dollars you should not be surprised that
after a number of calculations the result is off by a penny (or perhaps
more). Floating point variables can not store amounts in dollars with
precision upto pennies.
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/
Dec 20 '06 #18
"Malcolm" <re*******@btin ternet.comwrite s:
<dc*****@connx. comwrote in message
news:11******** **************@ t46g2000cwa.goo glegroups.com.. .
>Dilip wrote:
>>I came across that paper quite a few times in the past. I never
realized one day I would need to know that amount of detail. Do you
have any insights into that normalized integer thing everyone has been
pointing out so far? If one of you can give me an example, i'd
appreciate it.

Store the amount as pennies in a long long integer. The Goldberg paper
is a must read if you are doing numerics with other people's money.
IMO-YMMV.
Or in a double, but as an integral number of pence.
That way the maths is accurate up to 48 bits or so, and degrades garcefully
under hyperinflation.
For certain values of "gracefully ".

In some contexts, I would think that a one-penny error in a
multi-trillion pound calculation ("trillion" meaning 10**12) would be
considered unacceptable.

64-bit integers should be more than enough to handle anything short of
really extreme hyperinflation with no errors -- assuming that
addition, subtraction, and multiplication by whole numbers are the
only required operations.

Compound interest introduces some interesting problems, but I think
there are very specific rules for how to do those calculations. I
suspect floating-point would not implement those rules correctly.

Warning: I'm musing about stuff I've heard about here and there, but
in which I have no particular expertise.

--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Dec 20 '06 #19
"Dik T. Winter" <Di********@cwi .nlwrites:
[...]
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.
If you need to do calculations with stock prices, find out what the
formal rules are for doing those calculations. (I have no idea what
those rules are, or where you'd find out about them.) Once you've
done that, implement those rules. ("How?" "Correctly. ")

--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Dec 20 '06 #20

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
2331
by: Marc Schellens | last post by:
My compiler warns about assignment to int form float/double. Will it nevertheless do what I expect? Are there caveeats/pits? (Apart from the range and the precision of course) What would be the best way to do it? thanks, marc
26
3165
by: Alexander Block | last post by:
Hello newsgroup, let's say I have a function like template<class Type> inline bool areEqual(const Type &a, const Type &b) { return ( a == b ); }
4
11780
by: JKop | last post by:
Does the Standard specify any minimum range or minimum precision for the float, double and long double. I haven't found anything in the Standard about it. -JKop
3
23741
by: Madan | last post by:
Hi all, I had problem regarding float/double arithmetic only with + and - operations, which gives inaccurate precisions. I would like to know how the arithmetic operations are internally handled by C# or they are hardware (processor) dependent. Basic addition operation errors, for ex: 3.6 - 2.4 = 1.19999999999 or 1.20000000003 There are the erroneous values I'm getting. I'm using C#.Net v1.1 Please reply me how these operations are...
20
43570
by: Ollie | last post by:
Ok, As the Convert.ToDateTime has not been implimented yet, how do I convert a double to datetime??? I have looked all over with no luck at all. Please help me!
4
5068
by: illegal.prime | last post by:
Hi all, I have a class that I would like to use to hide the data type I'm using to store decimal point numbers. Failing all else, I will just use object and do conversion/casts as necessary. But I was wondering if I could use double to house all basic/primitive decimal numbers (i.e. only the float, double and decimal types) in C#. This type would also have to allow numerical greater than and less than comparisons. So I'm pretty sure...
1
2648
by: veremue | last post by:
I want to store a float/double as String. I have an input file with a column with float values i.e. have the form 1.4E15. I want to store these values as Strings. Here is my code which is resulting in storing 1.4E15 not the value as a String. String accNumber="";//declaring and initialisation //open file and read line then store the column in accNumber //the line read has been stored into an array String split ...
3
7696
by: Wander | last post by:
currently there are those functions is_float, is_double and is_real, which do exactly the same as far as i can see what surprises me is that $a = (float/double/real) 1; all work, while with settype() only float and double work, and 'real' not. now im wondering, is there any difference between those? and if not, will they all keep existing in php6? or will php continue with only one of them?
0
8399
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8312
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
8827
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
8732
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
8504
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
1
6169
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4159
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
2
1959
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
2
1622
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.