Precise std::string to float conversion [duplicate] - c++

This question already has answers here:
Why are floating point numbers inaccurate?
(5 answers)
Closed 7 years ago.
In my project I have to read some numeric data form an xml file ,use it ,and save it on disk in an another directory.
Skipping the file paring it comes to the problem of std::string to float conversion:
std::string sFloatNumber;
float fNumber = std::atof(sFloatNumber);
Which works fine but I noticed small deviations between value written in std::string and the one recieved after conversion to float (about ~0.0001).
Deviation is small but after number of such operations can accumulate to a big inacurracy later on.
So I ask if there is some conversion between std::string and float that has 1:1 accuracy?

You can't really can't make the conversion more precise than what you'd achieve by using the inbuilt operators for this. The reason is that floats can't represent all numbers. What they can represent is the number closest to the one you input, and I guess that is what they are showing. So there is no way possible in which you can convert a string exactly into a float.
If you want more accuracy, I suggest you use double. However, that also has a limit on the accuracy, but much better than float nonetheless. The reason for this is that double uses 64 bits to represent a number, whereas a float uses 32 bits. But their method of storing a number is similar, and so the same restrictions apply.

Related

Best variable types to use for floating-point value [duplicate]

This question already has answers here:
Floating point inaccuracy examples
(7 answers)
Closed 3 years ago.
I have a FLOAT column in a SQL Server database that appears as follows in SQL Server Management Studio.
18.001
When I read that value into a float variable, and format it using sprintf() ("%f"), it appears as:
18.000999
When I read that value into a double variable, and format it using sprintf(), it appears as:
18.001000
Could I get some suggestions on this? The values being stored are generally under 100, with up to 3 decimal places. What is the best SQL Server type? What is the best C++ type? And should I be using some rounding technique to get it in the format I want?
Note: I'm not actually using sprintf(), I'm using CString.Format(), but the expected behavior is the same.
The values being stored are generally under 100, with up to 3 decimal places.
SQL databases support the numeric/decimal (the two are synonyms) types for fixed-point values. For your specific type, you could use decimal(6, 3). That is six significant digits, with three of them to the right of the decimal point. These two values are called scale and precision respectively.
If the values can differ a bit from this, you might want a wider range.
With decimal/numeric, what-you-see-is-what-you-get. I would recommend storing them in the database as fixed-point numbers.
Answering the question on it's face value, assuming floating point should be used and fixed point is not applicable.
Unless you are really tight on memory, there is really no reason to use anything for floating numbers in C++ but double. Float looses precision without giving you much in return. You can also try long double, but in my experience it is rather overkill. Also, if your compiler is MSVC, I have heard it's long doubles are the same as doubles.
In alternative to the fixed comma decimals proposed already, just use ordinary integers!
Instead of storing 18.001 seconds, you'd store 18001 milliseconds, you wouldn't store Euro, Pound, Dollar, but tenth of a cent or penny, ...
Type in C++ would be an integer as well, large enough to hold maximum numbers you need, e. g. uint32_t, int64_t, ...

Convert string to double and then double to string without losing precision [duplicate]

This question already has an answer here:
Set precision of std::to_string when converting floating point values [duplicate]
(1 answer)
Closed 6 years ago.
I am using C++11. I have real world coordinates such as 38.0098662, 23.7805398 in a text file, meaning 2 double variables. I parse that file with C++ and I convert the strings to double with the stod() method. When I tried printing the values with count.precision(9);, the values seemed to be the same as in the text file.
Then, I want to convert those double values back to string format. For that I use to_string() method. However that seems to be changing the value slightly. For example:
38.0098662, 23.7805398 became
38.009866, 23.780540
// in fact, every number is xx.yyyyyy
I don't understand why this is so hard to do with C++11. Why do I lose precision for no reason ? How can I do this properly ? Every question I looked into pointed to to_string() method, which is what I am using.
Someone had the same problem as you had.
Simply set the precision of the std::ostringstream to your desired size and return it as std::string.
Here is a reference to an older question which shows the implementation:
Look at this!
Hope this helps!
It cause from compiler code optimization(for fastest run).
Sometimes C++ compiler optimizes floating point number processing, and loses a bit precision.

How to handle number with large exponent in c/c++? [duplicate]

This question already has answers here:
Is there a C++ equivalent to Java's BigDecimal?
(9 answers)
Closed 7 years ago.
I found myself with the need to compute the exponential of a large number, e. g.exp(709). Such a number would be represented, in floating point precision, as 8.2184074615549724e+307.
It seems that numbers with exponents larger than that would be simply translated into Inf, which creates problems in my code. I can only guess that things can be fixed using more bits to represent the exponent, but I am not aware of a pragmatical way to proceed.
Here is a code snippet:
double expon = exp(500); /*here I also tried `long double`, with no effect */
printf("%e\n", expon ); /*gives INF*/
double Wa = LambertW<0>( expon); /*gives error, as it can't handle inf*/
Is there a way to compute this?
This problem has been debated in general, but I did not find an useful answer. Also, it seems that GCC supports multiple-precision floating-point arithmetics since version 4.3. How does it help?
Edit: The suggested possible-duplicate questions turned out irrelevant because as I need huge decimals, not exact decimals. This is not a duplicate.
You should be able to perform your computation with adequate precision using long double arithmetic:
The maximum value for 80 bit long double is 1.18×10^4932, much larger than e^709.
In order for the computation to be performed as long double, your must use expl instead if exp:
long double expon = expl(500);
printf("%Le\n", expon);
The LambertW function will handle the long double if it is properly overloaded for this type, otherwise expon will be converted to double and produce inf and the computation will fail as you mentioned.
I don't know which implementation of Lambert W function you use, Darko Veberic's does not support long double arguments, but it might be feasible to extend the implementation to type long double as it is available in source form: https://github.com/DarkoVeberic/LambertW . You might want to contact him directly.
Another approach is to consider that exp(709) is just too close to the maximum precision of the double type, 10^308. If you can alter your computation using just smaller exponents and a different formula, the computation might be done with regular double types.

How would I find 100! accurately? [Programming challenge] [duplicate]

This question already has answers here:
Calculate the factorial of an arbitrarily large number, showing all the digits
(11 answers)
Closed 9 years ago.
I tried using double but it would give me scientific answers like 3.2e+12. I need proper answer. How would I do that??
My code so far:
int n, x;
double fact;
cin>>n;
while(n--)
{
fact=1;
cin>>x;
for(;x>1;x--)
fact*=x;
cout<<fact<<endl;
}
First things first, using floating point formats such as double and float will always introduce rounding error, if you want to reduce the error with large numbers, use long or long long, however these will not be able to represent values as large as double or long double (note that the behavior and support for long long and long double varies between compilers). You might want to look into BigNums like bigint or bigdouble, though you will sacrifice preformace.
That said, this issue might also be one of setting the formatting: the number is large enough that it is outputted in scientific notation, to change this you can use
cout<<std::fixed;
possible duplicate of How to make C++ cout not use scientific notation
double is a fixed-size type, typically 64 bits, with 53 bits of precision; so it can't accurately represent any integer with more than about 16 digits. The largest standard integer type typically has 64 bits, and can represent integers up to about 19 digits. 100! is much larger than that, so can't be represented accurately by any built-in type.
You'll need a large integer type, representing a number as an array of smaller numbers. There's no standard type; you could use a library like Boost.Multiprecision or GMP or, since this is a programming challenge, implement it yourself. To calculate factorials, you'll need to implement multiplication; the easiest way to do that is with the "long multiplication" algorithm you learnt in school.
There's no data type can store such a big number as (100!) so far.
You should finish something like a BigIntenger class to calculate 100!;
And usually,such big number can be stored by strings.

C++: How to Convert From Float to String Without Rounding, Truncation or Padding? [duplicate]

This question already has answers here:
Why do I see a double variable initialized to some value like 21.4 as 21.399999618530273?
(14 answers)
Closed 6 years ago.
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.
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.
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
Have a look at this C++ reference. Specifically the section on precision:
float blah = 0.01;
printf ("%.2f\n", blah);
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.
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;
For (b), you could do
std::ostringstream os;
os << f;
std::string s = os.str();
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!
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!"
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!)
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))