Is there any way to set the precision of the result when converting a double to string using std::to_string()?
No.
Returns: Each function returns a string object holding the character representation of the value of
its argument that would be generated by calling sprintf(buf, fmt, val) with a format specifier of
"%d", "%u", "%ld", "%lu", "%lld", "%llu", "%f", "%f", or "%Lf", respectively, where buf designates
an internal character buffer of sufficient size.
I was just looking for a solution to this as I was overloading the std::cout << operator and therefore it would have been tricky to do the std::stringstream workaround. I solved my problem by using the std::substr() function to locate the decimal and take a chosen number of digits past it.
std::string trimmedString = std::to_string(doubleVal).substr(0, std::to_string(doubleVal).find(".") + precisionVal + 1);
This will give you "precisionVal" 0's after your number.
Ex:
double doubleVal = 3;
int preisionVal = 2
3.000000 becomes 3.00
I believe that using std::stringstream with setprecision would be the most flexible/portable choice, but if you know your data, as an workaround, you could try to substring the to_string result. For example:
std::string seriesSum(int n)
{
double sum = 0, div = 1;
for(int i = 0; i < n; i++) {
sum += 1.0 / div;
div += 3;
}
return std::to_string(round(sum * 100)/100).substr(0,4);
}
In the code above I'm printing with two decimal places 0.00 by taking the first 4 digits of the string, but it only works because I know the integer part is never going above one digit. You could also use string.find() to search for the decimal separator and use it's position to calculate the size of the substring, making it a bit more dynamic.
Related
Is there any way to set the precision of the result when converting a double to string using std::to_string()?
No.
Returns: Each function returns a string object holding the character representation of the value of
its argument that would be generated by calling sprintf(buf, fmt, val) with a format specifier of
"%d", "%u", "%ld", "%lu", "%lld", "%llu", "%f", "%f", or "%Lf", respectively, where buf designates
an internal character buffer of sufficient size.
I was just looking for a solution to this as I was overloading the std::cout << operator and therefore it would have been tricky to do the std::stringstream workaround. I solved my problem by using the std::substr() function to locate the decimal and take a chosen number of digits past it.
std::string trimmedString = std::to_string(doubleVal).substr(0, std::to_string(doubleVal).find(".") + precisionVal + 1);
This will give you "precisionVal" 0's after your number.
Ex:
double doubleVal = 3;
int preisionVal = 2
3.000000 becomes 3.00
I believe that using std::stringstream with setprecision would be the most flexible/portable choice, but if you know your data, as an workaround, you could try to substring the to_string result. For example:
std::string seriesSum(int n)
{
double sum = 0, div = 1;
for(int i = 0; i < n; i++) {
sum += 1.0 / div;
div += 3;
}
return std::to_string(round(sum * 100)/100).substr(0,4);
}
In the code above I'm printing with two decimal places 0.00 by taking the first 4 digits of the string, but it only works because I know the integer part is never going above one digit. You could also use string.find() to search for the decimal separator and use it's position to calculate the size of the substring, making it a bit more dynamic.
I'm wondering what sort of algorithm could be used to take something like "4.72" into a float data type, equal to
float x = 4.72;
scanf, operator>> for istreams, and strtof would be the obvious choices.
There is also atof, but, like atoi, it lacks a way to tell you there was an error in the input, so it's generally best to avoid both.
For C++ you can use boost::lexical_cast:
std::string str( "4.72" );
float x = boost::lexical_cast< float >( str );
For C you can use sscanf:
char str[]= "4.72";
float x;
sscanf( str, "%f", &x );
For C++ This is the algorithm I use:
bool FromString(const string& str, double& number) {
std::istringstream i(str);
if (!(i >> number)) {
// Number conversion failed
return false;
}
return true;
}
I used atof() in the past for the conversion, but I found this problematic because if no valid conversion can be made, it will return (0.0). So, you would not know if it failed and returned zero, or if the string actually had "0" in it.
For C strtod() and C99 friends strtof() and strtold() (description on same link) already have that algorithm implemented.
If you are having problems writing your own, post your code and specific questions about it.
As you've asked for an algorithm, not a method, here is my explanation for a simple algorithm (and an implementation in C):
Initialize 4 integer variables, one for the value before dot, one for the after part, one for the power of the mantissa, one for the sign. Let's say, f, m, d, sign = 1.
First look for + or - sign at the beginning. If there are no sign characters or + sign then continue. If the first character is -, then sign = -1.
Then, read an integer value into f until a . or NULL character.
If you end up with a dot character, then start reading the mantissa part as in the previous step into m. But this time also multiply d by 10 with each digit.
In the end, return sign*(f + (float) m/d). The casting makes sure the division is done in floating-points and the type of the expression is float.
I guess, reading the code might be easier. So here is the code:
float atof(char *s)
{
int f, m, sign, d=1;
f = m = 0;
sign = (s[0] == '-') ? -1 : 1;
if (s[0] == '-' || s[0] == '+') s++;
for (; *s != '.' && *s; s++) {
f = (*s-'0') + f*10;
}
if (*s == '.')
for (++s; *s; s++) {
m = (*s-'0') + m*10;
d *= 10;
}
return sign*(f + (float)m/d);
}
You can use boost:lexical_cast
http://www.boost.org/doc/libs/1_44_0/libs/conversion/lexical_cast.htm
I assume you want an actual algorithm, not a library function that already does it. I don't have time to write and test actual code, but here is what I would do:
Initialize a float that will be used as an accumulator to 0.
Figure out where the decimal place is in the string, this will let you know what "column" each of the digits is (i.e. 100s, 10s, 1s, 1/10ths, etc).
Start at the beginning of the string.
Take that digit, convert to an int (trivially done by subtracting 0x30 from the ASCII value)
Multiply the value by the place column (for the first digit in your example, that would be 4 * 1 == 4, for the next digit 7 * 0.1 == 0.7).
Add the result to the accumulator
Repeat from step 4 for each remaining digit.
The accumulator now contains your result.
Due to the roundoff of converting between base 10 and base 2 in every iteration of this loop, the result you get from this algorithm may not be the closest possible binary representation to the original value. I don't really know of a good way to improve it though... perhaps someone else can chime in with that.
The atof() function can be helpful.
http://www.cplusplus.com/reference/clibrary/cstdlib/atof/
From cplusplus.com: "stringstream provides an interface to manipulate strings as if they were input/output streams."
You can initialize a stringstream with your string then read a float from the stringstream using operator>> just like you would with cin.
Here is an example:
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
int main() {
string s = "4.72";
stringstream sstrm(s);
float x;
sstrm >> x;
cout << x << endl;
}
How to convert string (22.123) format number into float variable format without using any API in c++. This is just to understand more about the inside coding.. thnx
something like:
double string_to_double(std::string s)
{
int p = 0;
int p_dec = s.length();
double val = 0;
for (int i=0; i<s.length(); ++i)
{
double digit = (double)(s[i] - '0');
if (s[i] == '.') { p_dec = p; }
else { val += digit*powf(10,p--); }
}
val /= powf(10, p_dec);
}
Basic algorithm, assuming no input in the form 1.2e-4:
(1) Read an integer before the dot. If the number of digits is > 16 (normal precision of double), convert that integer into floating point directly and return.
(2) Read an at most 16 digits dot as an integer. Compute (that integer) ÷ 10digits read. Sum up this with the integer in step (1) and return.
This only involve 2 floating point operation: one + and one ÷, and a bunch of integer arithmetics. The advantage over multiplications and divisions by powers of 10 is that the error won't accumulate unnecessarily.
(To read 16-digit integers you need a 64-bit int.)
In reality, you should use sscanf(str, "%lf", ...), std::istringstream, or boost::lexical_cast<double>.
go over the number digit by digit by using a bunch of multiplications and divisions by powers of 10 and construct the string character by character.
If you just want an idea of how to do it, the other answer, if you want an accurate result, the problem is not so simple and you should refer to the literature on the subject. An example: ftp://ftp.ccs.neu.edu/pub/people/will/howtoread.ps
I'm pretty sure that the Plauger Standard C Library book has a disc with the source of strtod.
http://www.amazon.co.uk/Standard-C-Library-P-J-Plauger/dp/0131315099
and there are online versions too:
http://www.google.co.uk/search?hl=en&client=firefox-a&hs=IvI&rls=org.mozilla%3Aen-GB%3Aofficial&q=strtod+source+code
Lets say that input from the user is a decimal number, ex. 5.2155 (having 4 decimal digits). It can be stored freely (int,double) etc.
Is there any clever (or very simple) way to find out how many decimals the number has? (kinda like the question how do you find that a number is even or odd by masking last bit).
Two ways I know of, neither very clever unfortunately but this is more a limitation of the environment rather than me :-)
The first is to sprintf the number to a big buffer with a "%.50f" format string, strip off the trailing zeros then count the characters after the decimal point. This will be limited by the printf family itself. Or you could use the string as input by the user (rather than sprintfing a floating point value), so as to avoid floating point problems altogether.
The second is to subtract the integer portion then iteratively multiply by 10 and again subtract the integer portion until you get zero. This is limited by the limits of computer representation of floating point numbers - at each stage you may get the problem of a number that cannot be represented exactly (so .2155 may actually be .215499999998). Something like the following (untested, except in my head, which is about on par with a COMX-35):
count = 0
num = abs(num)
num = num - int(num)
while num != 0:
num = num * 10
count = count + 1
num = num - int(num)
If you know the sort of numbers you'll get (e.g., they'll all be 0 to 4 digits after the decimal point), you can use standard floating point "tricks" to do it properly. For example, instead of:
while num != 0:
use
while abs(num) >= 0.0000001:
Once the number is converted from the user representation (string, OCR-ed gif file, whatever) into a floating point number, you are not dealing with the same number necessarily. So the strict, not very useful answer is "No".
If (case A) you can avoid converting the number from the string representation, the problem becomes much easier, you only need to count the digits after the decimal point and subtract the number of trailing zeros.
If you cannot do it (case B), then you need to make an assumption about the maximum number of decimals, convert the number back into string representation and round it to this maximum number using the round-to-even method. For example, if the user supplies 1.1 which gets represented as 1.09999999999999 (hypothetically), converting it back to string yields, guess what, "1.09999999999999". Rounding this number to, say, four decimal points gives you "1.1000". Now it's back to case A.
Off the top of my head:
start with the fractional portion: .2155
repeatedly multiply by 10 and throw away the integer portion of the number until you get zero. The number of steps will be the number of decimals. e.g:
.2155 * 10 = 2.155
.155 * 10 = 1.55
.55 * 10 = 5.5
.5 * 10 = 5.0
4 steps = 4 decimal digits
Something like this might work as well:
float i = 5.2154;
std::string s;
std::string t;
std::stringstream out;
out << i;
s = out.str();
t = s.substr(s.find(".")+1);
cout<<"number of decimal places: " << t.length();
What do you mean "stored freely (int"? Once stored in an int, it has zero decimals left, clearly. A double is stored in a binary form, so no obvious or simple relation to "decimals" either. Why don't you keep the input as a string, just long enough to count those decimals, before sending it on to its final numeric-variable destination?
using the Scientific Notation format (to avoid rounding errors):
#include <stdio.h>
#include <string.h>
/* Counting the number of decimals
*
* 1. Use Scientific Notation format
* 2. Convert it to a string
* 3. Tokenize it on the exp sign, discard the base part
* 4. convert the second token back to number
*/
int main(){
int counts;
char *sign;
char str[15];
char *base;
char *exp10;
float real = 0.00001;
sprintf (str, "%E", real);
sign= ( strpbrk ( str, "+"))? "+" : "-";
base = strtok (str, sign);
exp10 = strtok (NULL, sign);
counts=atoi(exp10);
printf("[%d]\n", counts);
return 0;
}
[5]
If the decimal part of your number is stored in a separate int, you can just count the its decimal digits.
This is a improvement on andrei alexandrescu's improvement. His version was already faster than the naive way (dividing by 10 at every digit). The version below is constant time and faster at least on x86-64 and ARM for all sizes, but occupies twice as much binary code, so it is not as cache-friendly.
Benchmarks for this version vs alexandrescu's version on my PR on facebook folly.
Works on unsigned, not signed.
inline uint32_t digits10(uint64_t v) {
return 1
+ (std::uint32_t)(v>=10)
+ (std::uint32_t)(v>=100)
+ (std::uint32_t)(v>=1000)
+ (std::uint32_t)(v>=10000)
+ (std::uint32_t)(v>=100000)
+ (std::uint32_t)(v>=1000000)
+ (std::uint32_t)(v>=10000000)
+ (std::uint32_t)(v>=100000000)
+ (std::uint32_t)(v>=1000000000)
+ (std::uint32_t)(v>=10000000000ull)
+ (std::uint32_t)(v>=100000000000ull)
+ (std::uint32_t)(v>=1000000000000ull)
+ (std::uint32_t)(v>=10000000000000ull)
+ (std::uint32_t)(v>=100000000000000ull)
+ (std::uint32_t)(v>=1000000000000000ull)
+ (std::uint32_t)(v>=10000000000000000ull)
+ (std::uint32_t)(v>=100000000000000000ull)
+ (std::uint32_t)(v>=1000000000000000000ull)
+ (std::uint32_t)(v>=10000000000000000000ull);
}
Years after the fight but as I have made my own solution in three lines :
string number = "543.014";
size_t dotFound;
stoi(number, &dotFound));
string(number).substr(dotFound).size()
Of course you have to test before if it is really a float
(With stof(number) == stoi(number) for example)
int main()
{
char s[100];
fgets(s,100,stdin);
unsigned i=0,sw=0,k=0,l=0,ok=0;
unsigned length=strlen(s);
for(i=0;i<length;i++)
{
if(isprint(s[i]))
{
if(sw==1)
{
k++;
if(s[i]=='0')
{
ok=0;
}
if(ok==0)
{
if(s[i]=='0')
l++;
else
{
ok=1;
l=0;
}
}
}
if(s[i]=='.')
{
sw=1;
}
}
}
printf("%d",k-l);
return 0;
}
This is a robust C++ 11 implementation suitable for float and double types:
template <typename T>
std::enable_if_t<(std::is_floating_point<T>::value), std::size_t>
decimal_places(T v)
{
std::size_t count = 0;
v = std::abs(v);
auto c = v - std::floor(v);
T factor = 10;
T eps = std::numeric_limits<T>::epsilon() * c;
while ((c > eps && c < (1 - eps)) && count < std::numeric_limits<T>::max_digits10)
{
c = v * factor;
c = c - std::floor(c);
factor *= 10;
eps = std::numeric_limits<T>::epsilon() * v * factor;
count++;
}
return count;
}
It throws the value away each iteration and instead keeps track of a power of 10 multiplier to avoid rounding issues building up. It uses machine epsilon to correctly handle decimal numbers that cannot be represented exactly in binary such as the value of 5.2155 as stipulated in the question.
Based on what others wrote, this has worked well for me. This solution does handle the case where a number can't be represented exactly in binary.
As suggested by others, the condition for the while loop indicates the precise behavior. My update uses the machine epsilon value to test whether the remainder on any loop is representable by the numeric format. The test should not compare to 0 or a hardcoded value like 0.000001.
template<class T, std::enable_if_t<std::is_floating_point_v<T>, T>* = nullptr>
unsigned int NumDecimalPlaces(T val)
{
unsigned int decimalPlaces = 0;
val = std::abs(val);
val = val - std::round(val);
while (
val - std::numeric_limits<T>::epsilon() > std::numeric_limits<T>::epsilon() &&
decimalPlaces <= std::numeric_limits<T>::digits10)
{
std::cout << val << ", ";
val = val * 10;
++decimalPlaces;
val = val - std::round(val);
}
return val;
}
As an example, if the input value is 2.1, the correct solution is 1. However, some other answers posted here would output 16 if using double precision because 2.1 can't be precisely represented in double precision.
I would suggest reading the value as a string, searching for the decimal point, and parsing the text before and after it as integers. No floating point or rounding errors.
char* fractpart(double f)
{
int intary={1,2,3,4,5,6,7,8,9,0};
char charary={'1','2','3','4','5','6','7','8','9','0'};
int count=0,x,y;
f=f-(int)f;
while(f<=1)
{
f=f*10;
for(y=0;y<10;y++)
{
if((int)f==intary[y])
{
chrstr[count]=charary[y];
break;
}
}
f=f-(int)f;
if(f<=0.01 || count==4)
break;
if(f<0)
f=-f;
count++;
}
return(chrstr);
}
Here is the complete program
#include <iostream.h>
#include <conio.h>
#include <string.h>
#include <math.h>
char charary[10]={'1','2','3','4','5','6','7','8','9','0'};
int intary[10]={1,2,3,4,5,6,7,8,9,0};
char* intpart(double);
char* fractpart(double);
int main()
{
clrscr();
int count = 0;
double d = 0;
char intstr[10], fractstr[10];
cout<<"Enter a number";
cin>>d;
strcpy(intstr,intpart(d));
strcpy(fractstr,fractpart(d));
cout<<intstr<<'.'<<fractstr;
getche();
return(0);
}
char* intpart(double f)
{
char retstr[10];
int x,y,z,count1=0;
x=(int)f;
while(x>=1)
{
z=x%10;
for(y=0;y<10;y++)
{
if(z==intary[y])
{
chrstr[count1]=charary[y];
break;
}
}
x=x/10;
count1++;
}
for(x=0,y=strlen(chrstr)-1;y>=0;y--,x++)
retstr[x]=chrstr[y];
retstr[x]='\0';
return(retstr);
}
char* fractpart(double f)
{
int count=0,x,y;
f=f-(int)f;
while(f<=1)
{
f=f*10;
for(y=0;y<10;y++)
{
if((int)f==intary[y])
{
chrstr[count]=charary[y];
break;
}
}
f=f-(int)f;
if(f<=0.01 || count==4)
break;
if(f<0)
f=-f;
count++;
}
return(chrstr);
}
One way would be to read the number in as a string. Find the length of the substring after the decimal point and that's how many decimals the person entered. To convert this string into a float by using
atof(string.c_str());
On a different note; it's always a good idea when dealing with floating point operations to store them in a special object which has finite precision. For example, you could store the float points in a special type of object called "Decimal" where the whole number part and the decimal part of the number are both ints. This way you have a finite precision. The downside to this is that you have to write out methods for arithmetic operations (+, -, *, /, etc.), but you can easily overwrite operators in C++. I know this deviates from your original question, but it's always better to store your decimals in a finite form. In this way you can also answer your question of how many decimals the number has.
How can I write a C++ function returning true if a real number is exactly representable with a double?
bool isRepresentable( const char* realNumber )
{
bool answer = false;
// what goes here?
return answer;
}
Simple tests:
assert( true==isRepresentable( "0.5" ) );
assert( false==isRepresentable( "0.1" ) );
Parse the number into the form a + N / (10^k), where a and N are integers, and k is the number of decimal places you have.
Example: 12.0345 -> 12 + 345 / 10^4, a = 12, N = 345, k = 4
Now, 10^k = (2 * 5) ^ k = 2^k * 5^k
You can represent your number as exact binary fraction if and only if you get rid of the 5^k term in the denominator.
The result would check (N mod 5^k) == 0
Holy homework, batman! :)
What makes this interesting is that you can't simply do an (atof|strtod|sscanf) -> sprintf loop and check whether you got the original string back. sprintf on many platforms detects the "as close as you can get to 0.1" double and prints it as 0.1, for example, even though 0.1 isn't precisely representable.
#include <stdio.h>
int main() {
printf("%llx = %f\n",0.1,0.1);
}
prints:
3fb999999999999a = 0.100000
on my system.
The real answer probably would require parsing out the double to convert it to an exact fractional representation (0.1 = 1/10) and then making sure that the atof conversion times the denominator equals the numerator.
I think.
Here is my version. sprintf converts 0.5 to 0.50000, zeros at the end have to be removed.
EDIT: Has to be rewritten to handle numbers without decimal point that end with 0 correctly (like 12300).
bool isRepresentable( const char* realNumber )
{
bool answer = false;
double dVar = atof(realNumber);
char check[20];
sprintf(check, "%f", dVar);
// Remove zeros at end - TODO: Only do if decimal point in string
for (int i = strlen(check) - 1; i >= 0; i--) {
if (check[i] != '0') break;
check[i] = 0;
}
answer = (strcmp(realNumber, check) == 0);
return answer;
}
This should do the trick:
bool isRepresentable(const char *realNumber)
{
double value = strtod(realNumber, NULL);
char test[20];
sprintf(test, "%f", value);
return strcmp(realNumber, test) == 0;
}
Probably best to use the 'safe' version of sprintf to prevent a potential buffer overrun (is it even possible in this case?)
I'd convert the string to its numeric bit representation, (a bit array or a long), then convert the string to a double and see if they match.
Convert the string into a float with a larger scope than a double. Cast that to a double and see if they match.