7

I am facing a problem and unable to resolve it. Need help from gurus. Here is sample code:-

float f=0.01f;
printf("%f",f);

if we check value in variable during debugging f contains '0.0099999998' value and output of printf is 0.010000.

a. Is there any way that we may force the compiler to assign same values to variable of float type?

b. I want to convert float to string/character array. How is it possible that only and only exactly same value be converted to string/character array. I want to make sure that no zeros are padded, no unwanted values are padded, no changes in digits as in above example.

Josh Lee
  • 171,072
  • 38
  • 269
  • 275
Azher Iqbal
  • 547
  • 2
  • 4
  • 13

10 Answers10

6

It is impossible to accurately represent a base 10 decimal number using base 2 values, except for a very small number of values (such as 0.25). To get what you need, you have to switch from the float/double built-in types to some kind of decimal number package.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
3

You could use boost::lexical_cast in this way:

float blah = 0.01;
string w = boost::lexical_cast<string>( blah );

The variable w will contain the text value 0.00999999978. But I can't see when you really need it.

It is preferred to use boost::format to accurately format a float as an string. The following code shows how to do it:

float blah = 0.01;
string w = str( boost::format("%d") % blah ); // w contains exactly "0.01" now
Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
2

Have a look at this C++ reference. Specifically the section on precision:

float blah = 0.01;
printf ("%.2f\n", blah);
RedBlueThing
  • 42,006
  • 17
  • 96
  • 122
  • I think he is facing problem with floats not doubles – Aamir Jun 18 '09 at 05:33
  • hehe ... thats cool. I figure the original downvote may have been because of my first, very terse answer (sans sourcecode), and fair enough too ;). – RedBlueThing Jun 18 '09 at 05:40
  • Might also be because I have ignored the whole float point representation issue and answered the question on a fairly superficial level. – RedBlueThing Jun 18 '09 at 05:42
2

There are uncountably many real numbers.

There are only a finite number of values which the data types float, double, and long double can take.

That is, there will be uncountably many real numbers that cannot be represented exactly using those data types.

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
1

The reason that your debugger is giving you a different value is well explained in Mark Ransom's post.

Regarding printing a float without roundup, truncation and with fuller precision, you are missing the precision specifier - default precision for printf is typically 6 fractional digits.

try the following to get a precision of 10 digits:

float amount = 0.0099999998;
printf("%.10f", amount); 

As a side note, a more C++ way (vs. C-style) to do things is with cout:

float amount = 0.0099999998;
cout.precision(10);
cout << amount << endl;
Demi
  • 6,147
  • 7
  • 36
  • 38
1

For (b), you could do

std::ostringstream os;
os << f;
std::string s = os.str();
AngryWhenHungry
  • 458
  • 2
  • 15
1

Equally, you could use the stdlib.h, in there are the sprintf, ecvt and fcvt functions (or at least, there should be!).

int sprintf(char* dst,const char* fmt,...);

char *ecvt(double value, int ndig, int *dec, int *sign);

char *fcvt(double value, int ndig, int *dec, int *sign);

sprintf returns the number of characters it wrote to the string, for example

float f=12.00;
char buffer[32];
sprintf(buffer,"%4.2f",f) // will return 5, if it is an error it will return -1

ecvt and fcvt return characters to static char* locations containing the null terminated decimal representations of the numbers, with no decimal point, most significant number first, the offset of the decimal point is stored in dec, the sign in "sign" (1=-,0=+) ndig is the number of significant digits to store. If dec<0 then you have to pad with -dec zeros pror to the decimal point. I fyou are unsure, and you are not working on a Windows7 system (which will not run old DOS3 programs sometimes) look for TurboC version 2 for Dos 3, there are still one or two downloads available, it's a relatively small program from Borland which is a small Dos C/C++ edito/compiler and even comes with TASM, the 16 bit machine code 386/486 compile, it is covered in the help files as are many other useful nuggets of information.

All three routines are in "stdlib.h", or should be, though I have found that on VisualStudio2010 they are anything but standard, often overloaded with function dealing with WORD sized characters and asking you to use its own specific functions instead... "so much for standard library," I mutter to myself almost each and every time, "Maybe they out to get a better dictionary!"

Perception
  • 79,279
  • 19
  • 185
  • 195
1

In truth using the floating point processor or co-processor or section of the chip itself (most are now intergrated into the CPU), will never result in accurate mathematical results, but they do give a fairly rough accuracy, for more accurate results, you could consider defining a class "DecimalString", which uses nybbles as decimal characters and symbols... and attempt to mimic base 10 mathematics using strings... in that case, depending on how long you want to make the strings, you could even do away with the exponent part altogether a string 256 can represent 1x10^-254 upto 1^+255 in straight decimal using actual ASCII, shorter if you want a sign, but this may prove significantly slower. You could speed this by reversing the digit order, so from left to right they read units,tens,hundreds,thousands....

Simple example eg. "0021" becomes 1200 This would need "shifting" left and right to make the decimal points line up before routines as well, the best bet is to start with the ADD and SUB functions, as you will then build on them in the MUL and DIV functions. If you are on a large machine, you could make them theoretically as long as your heart desired!

0

You would need to consult your platform standards to determine how to best determine the correct format, you would need to display it as a*b^C, where 'a' is the integral component that holds the sign, 'b' is implementation defined (Likely fixed by a standard), and 'C' is the exponent used for that number.

Alternatively, you could just display it in hex, it'd mean nothing to a human, though, and it would still be binary for all practical purposes. (And just as portable!)

Arafangion
  • 11,517
  • 1
  • 40
  • 72
0

To answer your second question:

it IS possible to exactly and unambiguously represent floats as strings. However, this requires a hexadecimal representation. For instance, 1/16 = 0.1 and 10/16 is 0.A.

With hex floats, you can define a canonical representation. I'd personally use a fixed number of digits representing the underlying number of bits, but you could also decide to strip trailing zeroes. There's no confusion possible on which trailing digits are zero.

Since the representation is exact, the conversions are reversible: f==hexstring2float(float2hexstring(f))

MSalters
  • 173,980
  • 10
  • 155
  • 350