C++ : Converting String to Double - c++

It's C++ code written in Visual Studio 2015. It's something as below,
LPSTR *endPtr;
string strDouble = "0.03456";
double valDouble = strtod(strDouble.c_str(), &endPtr);
Now the output in valDouble is "0.0345555566", something like that.
I want the value in valDouble to be exactly "0.03456".
Basically the value of "0.0345555566" needs to be rounded to say "0.03456".
Is there a way it can be achieved?
BTW, the value in strDouble changes all the time. So it's not possible to set precision to say 5 or something like that. Below are few examples that goes in to strDouble.
string strDouble = "0.1889";
string strDouble = "0.00883342";
string strDouble = "0.2111907";
string strDouble = "3.0045";
string strDouble = "1.45";

I want the value in valDouble to be exactly "0.03456".
That's not possible, unless you target a system whose double floating point representation can represent that number.
There exists no representation for 0.03456 in the ubiquitous IEEE 754 binary64 standard which your CPU probably uses. The closest representable number is 3.45600000000000004418687638008E-2. That's the number that you should get whether you use strtod, stod or a character stream to convert the string.
Is there a way it can be achieved?
In order to represent 0.03456 exactly on a system whose floating point cannot represent that number, you must use integers to represent the number. You can implement arbitrary precision arithmetic, fixed-point arithmetic or a decimal floating point using integers.
Basically the value ... needs to be rounded to say "0.03456".
You can round the output when you convert the non-exact float into a string:
std::cout << std::setprecision(4) << 0.03456;
BTW, the value in strDouble changes all the time. So it's not possible to set precision to say 5 or something like that.
Then you have to record the number of significant digits in the input string in order to use the same precision in output.
Here's an example function for that purpose:
template<class Range>
auto get_precision(const Range& r)
{
auto is_significant = [](auto c) {
return std::isdigit(c) && c != '0';
};
auto first = std::find_if(std:: begin(r), std:: end(r), is_significant);
auto last = std::find_if(std::rbegin(r), std::rend(r), is_significant).base();
return std::count_if(first, last, [](auto c) {
return std::isdigit(c);
});
}
// demo
std::cout << get_precision("0.03456"); // 4

Assuming that you want the number of digits after decimal point as some percent of the total number of digits after the decimal, you could do something like,
Calculate the number of digits after decimal point. Let it be n
Now convert the string to decimal just like you are doing. Let this be d
Now if you want 50% of the decimal places to be retained, you could do use an old trick,
double d_new = round(d * pow(10.0, 5)) / pow(10.0, 5). Assuming precision till 5 digits.
Note: Unlike the other answers, here you are rounding the original decimal itself. Not just printing the rounded decimal to stdout.
Example:
#include<stdio.h>
#include<cmath>
int main(){
double a = 0.0345555566;
double b = 0.00883342;
double c = 0.2111907;
double a_new = round(a * pow(10.0, 5)) / pow(10.0, 5);
double b_new = round(b * pow(10.0, 4)) / pow(10.0, 4);
double c_new = round(c * pow(10.0, 3)) / pow(10.0, 3);
printf("%.10f\n", a_new);
printf("%.10f\n", b_new);
printf("%.10f\n", c_new);
}
See the 50% precision
Results:
0.0345600000
0.0088000000
0.2110000000

Use string stream instead of strtod:
#include <iostream>
#include <sstream>
double convert(std::string string) {
std::stringstream s(string);
double ret = 0;
s >> ret;
return ret;
}
int main() {
std::cerr << convert("0.03456") << std::endl;
std::cerr << convert("0.1889") << std::endl;
std::cerr << convert("0.00883342") << std::endl;
std::cerr << convert("0.2111907") << std::endl;
std::cerr << convert("3.0045") << std::endl;
std::cerr << convert("1.45") << std::endl;
return 0;
}
On my system, this gives:
0.03456
0.1889
0.00883342
0.211191
3.0045
1.45
As some have pointed out in the comments, not all numbers can be represented with doubles. But most of the ones you listed can be.

Related

Converting a floating point number to string with MPFR

I want to convert a MPFR floating point number into a string.
If I run my program the string is generated but without the "." in the number. How can I do it right?
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <mpreal.h>
using mpfr::mpreal;
using std::cout;
using std::endl;
int main (int ac, char *av[])
{
char data[255];
mpreal x = 42.0, y = 3.14159265358979323846, res = 0.0;
mp_exp_t exponent = 10;
// string data_str[256];
int precision = 50;
res = x * y;
cout.precision(100);
cout << res;
cout << "\n";
// if (mpfr_snprintf (data, 254, "%.20Ff", res.mpfr_srcptr()) < 0)
/*
if (mpfr_snprintf (data, 254, "%.20Ff", res.mpfr_srcptr()) < 0)
{
cout << "gmp_prints_float: error saving string!\n";
}
*/
mpfr_get_str ((char *) &data, &exponent, 10, precision, res.mpfr_srcptr(), GMP_RNDN);
cout << data;
cout << "\n";
mpfr_free_cache ();
}
131.946891450771317977341823279857635498046875
13194689145077131797734182327985763549804687500000
There is no decimal point in the string output!
From the documentation
The generated string is a fraction, with an implicit radix point immediately to the left of the first digit. For example, the number -3.1416 would be returned as "-31416" in the string and 1 written at expptr.
It is up to you to generate a human-readable representation fron the string and the exponent.
An alternative would be to use mpfr_sprintf.
MPFR's mpfr_get_str function is copied on GMP's mpf_get_str function, explaining why it has been chosen not to write a decimal point. There are two solutions to have a decimal point:
Use mpfr_sprintf (or some variant), as suggested in this answer. I would recommend this solution (perhaps unless you want to ignore the locales), as it is the most flexible in the output format and does not need a correction.
If you just want the significand with an explicit decimal point, use mpfr_get_str, but with a pointer buffer+1 instead of buffer. Then, do something like (disregarding the locales)
int neg = buffer[1] == '-';
if (neg)
buffer[0] = '-';
buffer[neg] = '.';
after filtering the special cases (NaN and infinities).

Truncating a double floating point at a certain number of digits

I have written the following routine, which is supposed to truncate a C++ double at the n'th decimal place.
double truncate(double number_val, int n)
{
double factor = 1;
double previous = std::trunc(number_val); // remove integer portion
number_val -= previous;
for (int i = 0; i < n; i++) {
number_val *= 10;
factor *= 10;
}
number_val = std::trunc(number_val);
number_val /= factor;
number_val += previous; // add back integer portion
return number_val;
}
Usually, this works great... but I have found that with some numbers, most notably those that do not seem to have an exact representation within double, have issues.
For example, if the input is 2.0029, and I want to truncate it at the fifth place, internally, the double appears to be stored as something somewhere between 2.0028999999999999996 and 2.0028999999999999999, and truncating this at the fifth decimal place gives 2.00289, which might be right in terms of how the number is being stored, but is going to look like the wrong answer to an end user.
If I were rounding instead of truncating at the fifth decimal, everything would be fine, of course, and if I give a double whose decimal representation has more than n digits past the decimal point it works fine as well, but how do I modify this truncation routine so that inaccuracies due to imprecision in the double type and its decimal representation will not affect the result that the end user sees?
I think I may need some sort of rounding/truncation hybrid to make this work, but I'm not sure how I would write it.
Edit: thanks for the responses so far but perhaps I should clarify that this value is not producing output necessarily but this truncation operation can be part of a chain of many different user specified actions on floating point numbers. Errors that accumulate within the double precision over multiple operations are fine, but no single operation, such as truncation or rounding, should produce a result that differs from its actual ideal value by more than half of an epsilon, where epsilon is the smallest magnitude represented by the double precision with the current exponent. I am currently trying to digest the link provided by iinspectable below on floating point arithmetic to see if it will help me figure out how to do this.
Edit: well the link gave me one idea, which is sort of hacky but it should probably work which is to put a line like number_val += std::numeric_limits<double>::epsilon() right at the top of the function before I start doing anything else with it. Dunno if there is a better way, though.
Edit: I had an idea while I was on the bus today, which I haven't had a chance to thoroughly test yet, but it works by rounding the original number to 16 significant decimal digits, and then truncating that:
double truncate(double number_val, int n)
{
bool negative = false;
if (number_val == 0) {
return 0;
} else if (number_val < 0) {
number_val = -number_val;
negative = true;
}
int pre_digits = std::log10(number_val) + 1;
if (pre_digits < 17) {
int post_digits = 17 - pre_digits;
double factor = std::pow(10, post_digits);
number_val = std::round(number_val * factor) / factor;
factor = std::pow(10, n);
number_val = std::trunc(number_val * factor) / factor;
} else {
number_val = std::round(number_val);
}
if (negative) {
number_val = -number_val;
}
return number_val;
}
Since a double precision floating point number only can have about 16 digits of precision anyways, this just might work for all practical purposes, at a cost of at most only one digit of precision that the double would otherwise perhaps support.
I would like to further note that this question differs from the suggested duplicate above in that a) this is using C++, and not Java... I don't have a DecimalFormatter convenience class, and b) I am wanting to truncate, not round, the number at the given digit (within the precision limits otherwise allowed by the double datatype), and c) as I have stated before, the result of this function is not supposed to be a printable string... it is supposed to be a native floating point number that the end user of this function might choose to further manipulate. Accumulated errors over multiple operations due to imprecision in the double type are acceptable, but any single operation should appear to perform correctly to the limits of the precision of the double datatype.
OK, if I understand this right, you've got a floating point number and you want to truncate it to n digits:
10.099999
^^ n = 2
becomes
10.09
^^
But your function is truncating the number to an approximately close value:
10.08999999
^^
Which is then displayed as 10.08?
How about you keep your truncate formula, which does truncate as well as it can, and use std::setprecision and std::fixed to round the truncated value to the required number of decimal places? (Assuming it is std::cout you're using for output?)
#include <iostream>
#include <iomanip>
using std::cout;
using std::setprecision;
using std::fixed;
using std::endl;
int main() {
double foo = 10.08995; // let's imagine this is the output of `truncate`
cout << foo << endl; // displays 10.0899
cout << setprecision(2) << fixed << foo << endl; // rounds to 10.09
}
I've set up a demo on wandbox for this.
I've looked into this. It's hard because you have inaccuracies due to the floating point representation, then further inaccuracies due to the decimal. 0.1 cannot be represented exactly in binary floating point. However you can use the built-in function sprintf with a %g argument that should round accurately for you.
char out[64];
double x = 0.11111111;
int n = 3;
double xrounded;
sprintf(out, "%.*g", n, x);
xrounded = strtod(out, 0);
Get double as a string
If you are looking just to print the output, then it is very easy and straightforward using stringstream:
#include <cmath>
#include <iostream>
#include <iomanip>
#include <limits>
#include <sstream>
using namespace std;
string truncateAsString(double n, int precision) {
stringstream ss;
double remainder = static_cast<double>((int)floor((n - floor(n)) * precision) % precision);
ss << setprecision(numeric_limits<double> ::max_digits10 + __builtin_ctz(precision))<< floor(n);
if (remainder)
ss << "." << remainder;
cout << ss.str() << endl;
return ss.str();
}
int main(void) {
double a = 9636346.59235;
int precision = 1000; // as many digits as you add zeroes. 3 zeroes means precision of 3.
string s = truncateAsString(a, precision);
return 0;
}
Getting the divided floating point with an exact value
Maybe you are looking for true value for your floating point, you can use boost multiprecision library
The Boost.Multiprecision library can be used for computations requiring precision exceeding that of standard built-in types such as float, double and long double. For extended-precision calculations, Boost.Multiprecision supplies a template data type called cpp_dec_float. The number of decimal digits of precision is fixed at compile-time via template parameter.
Demonstration
#include <boost/math/constants/constants.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>
#include <limits>
#include <cmath>
#include <iomanip>
using boost::multiprecision::cpp_dec_float_50;
cpp_dec_float_50 truncate(cpp_dec_float_50 n, int precision) {
cpp_dec_float_50 remainder = static_cast<cpp_dec_float_50>((int)floor((n - floor(n)) * precision) % precision) / static_cast<cpp_dec_float_50>(precision);
return floor(n) + remainder;
}
int main(void) {
int precision = 100000; // as many digits as you add zeroes. 5 zeroes means precision of 5.
cpp_dec_float_50 n = 9636346.59235789;
n = truncate(n, precision); // first part is remainder, floor(n) is int value truncated.
cout << setprecision(numeric_limits<cpp_dec_float_50> ::max_digits10 + __builtin_ctz(precision)) << n << endl; // __builtin_ctz(precision) will equal the number of trailing 0, exactly the precision we need!
return 0;
}
Output:
9636346.59235
NB: Requires sudo apt-get install libboost-all-dev

C++: long to float with decimals?

I have a function that takes long as an argument, and I want it to return that number as a float with seven decimals.
This long gets in to the function: 631452947, and I want the function to convert it and return this float: 63.1452947
How can I do this?
I have tried this:
float makeLatLon (long val) {
float tzt = (float)val/10000000.0;
return tzt;
}
but it does not work.
Seven digits after the comma means nine digits of precision total, and you can only expect seven digits of precision in a float on platforms where that's an IEEE 32-bit FP type (practically everywhere). Use a double:
long n = 631452947;
float f = n / 10000000.f;
double d = n / 10000000.;
std::cout << std::setprecision(9)
<< f << std::endl
<< d << std::endl;
On my box, that prints
63.1452942
63.1452947
So you see that using a float causes a round-off error.
IEEE-754 double spec and variants don't ensure you 7 digits being present for any number because of the density of the double not being continuous, so also double is not a good choice here.
You may want to consider to build your fixed precision math working with integers only and using a structure like:
typedef struct { int int_part, unsigned long dec_part } myfloat;

How to generate random double numbers with high precision in C++?

I am trying to generate a number of series of double random numbers with high precision. For example, 0.856365621 (has 9 digits after decimal).
I've found some methods from internet, however, they do generate double random number, but the precision is not as good as I request (only 6 digits after the decimal).
Thus, may I know how to achieve my goal?
In C++11 you can using the <random> header and in this specific example using std::uniform_real_distribution I am able to generate random numbers with more than 6 digits. In order to see set the number of digits that will be printed via std::cout we need to use std::setprecision:
#include <iostream>
#include <random>
#include <iomanip>
int main()
{
std::random_device rd;
std::mt19937 e2(rd());
std::uniform_real_distribution<> dist(1, 10);
for( int i = 0 ; i < 10; ++i )
{
std::cout << std::fixed << std::setprecision(10) << dist(e2) << std::endl ;
}
return 0 ;
}
you can use std::numeric_limits::digits10 to determine the precision available.
std::cout << std::numeric_limits<double>::digits10 << std::endl;
In a typical system, RAND_MAX is 231-1 or something similar to that. So your "precision" from using a method like:L
double r = rand()/RAND_MAX;
would be 1/(2<sup>31</sup)-1 - this should give you 8-9 digits "precision" in the random number. Make sure you print with high enough precision:
cout << r << endl;
will not do. This will work better:
cout << fixed << sprecision(15) << r << endl;
Of course, there are some systems out there with much smaller RAND_MAX, in which case the results may be less "precise" - however, you should still get digits down in the 9-12 range, just that they are more likely to be "samey".
Why not create your value out of multiple calls of the random function instead?
For instance:
const int numDecimals = 9;
double result = 0.0;
double div = 1.0;
double mul = 1.0;
for (int n = 0; n < numDecimals; ++n)
{
int t = rand() % 10;
result += t * mul;
mul *= 10.0;
div /= 10.0;
}
result = result * div;
I would personally try a new implementation of the rand function though or at least multiply with the current time or something..
In my case, I'm using MQL5, a very close derivative of C++ for a specific market, whose only random generator produces a random integer from 0 to 32767 (= (2^15)-1). Far too low precision.
So I've adapted his idea -- randomly generate a string of digits any length I want -- to solve my problem, more reliably (and arguably more randomly also), than anything else I can find or think of. My version builds a string and converts it to a double at the end -- avoids any potential math/rounding errors along the way (because we all know 0.1 + 0.2 != 0.3 😉 )
Posting it here in case it helps anyone.
(Disclaimer: The following is valid MQL5. MQL5 and C++ are very close, but some differences. eg. No RAND_MAX constant (so I've hard-coded the 32767). I'm not entirely sure of all the differences, so there may be C++ syntax errors here. Please adapt accordingly).
const int RAND_MAX_INCL = 32767;
const int RAND_MAX_EXCL = RAND_MAX_INCL + 1;
int iRandomDigit() {
const double dRand = rand()/RAND_MAX_EXCL; // double 0.0 <= dRand < 1.0
return (int)(dRand * 10); // int 0 <= result < 10
};
double dRandom0IncTo1Exc(const int iPrecisionDigits) {
int iPrecisionDigits2 = iPrecisionDigits;
if ( iPrecisionDigits > DBL_DIG ) { // DBL_DIG == "Number of significant decimal digits for double type"
Print("WARNING: Can't generate random number with precision > ", DBL_DIG, ". Adjusted precision to ", DBL_DIG, " accordingly.");
iPrecisionDigits2 = DBL_DIG;
};
string sDigits = "";
for (int i = 0; i < iPrecisionDigits2; i++) {
sDigits += (string)iRandomDigit();
};
const string sResult = "0." + sDigits;
const double dResult = StringToDouble(sResult);
return dResult;
}
Noted in a comment on #MasterPlanMan's answer -- the other answers use more "official" methods designed for the question, from standard library, etc. However, I think conceptually it's a good solution when faced with limitations that the other answers can't address.

How to print a C++ double with the correct number of significant decimal digits?

When dealing with floating point values in Java, calling the toString() method gives a printed value that has the correct number of floating point significant figures. However, in C++, printing a float via stringstream will round the value after 5 or less digits. Is there a way to "pretty print" a float in C++ to the (assumed) correct number of significant figures?
EDIT: I think I am being misunderstood. I want the output to be of dynamic length, not a fixed precision. I am familiar with setprecision. If you look at the java source for Double, it calculates the number of significant digits somehow, and I would really like to understand how it works and/or how feasible it is to replicate this easily in C++.
/*
* FIRST IMPORTANT CONSTRUCTOR: DOUBLE
*/
public FloatingDecimal( double d )
{
long dBits = Double.doubleToLongBits( d );
long fractBits;
int binExp;
int nSignificantBits;
// discover and delete sign
if ( (dBits&signMask) != 0 ){
isNegative = true;
dBits ^= signMask;
} else {
isNegative = false;
}
// Begin to unpack
// Discover obvious special cases of NaN and Infinity.
binExp = (int)( (dBits&expMask) >> expShift );
fractBits = dBits&fractMask;
if ( binExp == (int)(expMask>>expShift) ) {
isExceptional = true;
if ( fractBits == 0L ){
digits = infinity;
} else {
digits = notANumber;
isNegative = false; // NaN has no sign!
}
nDigits = digits.length;
return;
}
isExceptional = false;
// Finish unpacking
// Normalize denormalized numbers.
// Insert assumed high-order bit for normalized numbers.
// Subtract exponent bias.
if ( binExp == 0 ){
if ( fractBits == 0L ){
// not a denorm, just a 0!
decExponent = 0;
digits = zero;
nDigits = 1;
return;
}
while ( (fractBits&fractHOB) == 0L ){
fractBits <<= 1;
binExp -= 1;
}
nSignificantBits = expShift + binExp +1; // recall binExp is - shift count.
binExp += 1;
} else {
fractBits |= fractHOB;
nSignificantBits = expShift+1;
}
binExp -= expBias;
// call the routine that actually does all the hard work.
dtoa( binExp, fractBits, nSignificantBits );
}
After this function, it calls dtoa( binExp, fractBits, nSignificantBits ); which handles a bunch of cases - this is from OpenJDK6
For more clarity, an example:
Java:
double test1 = 1.2593;
double test2 = 0.004963;
double test3 = 1.55558742563;
System.out.println(test1);
System.out.println(test2);
System.out.println(test3);
Output:
1.2593
0.004963
1.55558742563
C++:
std::cout << test1 << "\n";
std::cout << test2 << "\n";
std::cout << test3 << "\n";
Output:
1.2593
0.004963
1.55559
I think you are talking about how to print the minimum number of floating point digits that allow you to read the exact same floating point number back. This paper is a good introduction to this tricky problem.
http://grouper.ieee.org/groups/754/email/pdfq3pavhBfih.pdf
The dtoa function looks like David Gay's work, you can find the source here http://www.netlib.org/fp/dtoa.c (although this is C not Java).
Gay also wrote a paper about his method. I don't have a link but it's referenced in the above paper so you can probably google it.
Is there a way to "pretty print" a float in C++ to the (assumed) correct number of significant figures?
Yes, you can do it with C++20 std::format, for example:
double test1 = 1.2593;
double test2 = 0.004963;
double test3 = 1.55558742563;
std::cout << std::format("{}", test1) << "\n";
std::cout << std::format("{}", test2) << "\n";
std::cout << std::format("{}", test3) << "\n";
prints
1.2593
0.004963
1.55558742563
The default format will give you the shortest decimal representation with a round-trip guarantee like in Java.
Since this is a new feature and may not be supported by some standard libraries yet, you can use the {fmt} library, std::format is based on. {fmt} also provides the print function that makes this even easier and more efficient (godbolt):
fmt::print("{}", 1.2593);
Disclaimer: I'm the author of {fmt} and C++20 std::format.
You can use the ios_base::precision technique where you can specify the number of digits you want
For example
#include <iostream>
using namespace std;
int main () {
double f = 3.14159;
cout.unsetf(ios::floatfield); // floatfield not set
cout.precision(5);
cout << f << endl;
cout.precision(10);
cout << f << endl;
cout.setf(ios::fixed,ios::floatfield); // floatfield set to fixed
cout << f << endl;
return 0;
The above code with output
3.1416
3.14159
3.1415900000
There is a utility called numeric_limits:
#include <limits>
...
int num10 = std::numeric_limits<double>::digits10;
int max_num10 = std::numeric_limits<double>::max_digits10;
Note that IEEE numbers are not represented exactly bydecimal digits. These are binary quantities. A more accurate number is the number of binary bits:
int bits = std::numeric_limits<double>::digits;
To pretty print all the significant digits use setprecision with this:
out.setprecision(std::numeric_limits<double>::digits10);