views:

381

answers:

9

I have a string that looks like this:

"0.4794255386042030002732879352156"

which is approximately the sin(0.5). I would like to format the string to look a much nicer

"4.794255386042e-1"

How can I achieve this? Remember I am dealing with strings and not numbers (float, double). Also I need to round to keep the number as accurate as possible, I can't just truncate. If I need to convert to a different data type I would prefer a long double because a regular double doesn't have enough precision. I'd like at least 12 decimal digits before rounding. Perhaps there is a simple sprintf() conversion I could do.

+1  A: 

There is no standard function in either C or C++ to do this. The normal approach is either to convert to a number (and then use standard functions to format the number) or write your own custom output function.

anon
+3  A: 

Something like this:

#include<iostream>
using namespace std;

int main()
{
        char *s = "0.4794255386042030002732879352156";
        double d;

        sscanf(s,"%lf",&d);
        printf("%.12e\n",d);

        return EXIT_SUCCESS;
}

Output:

# g++ a.cpp  && ./a.out
4.794255386042e-01
codaddict
+1  A: 

In highly portable C the working example below outputs:

result is 4.794255386042E-01


#include <stdio.h>

int main()
{
    char *str = "0.4794255386042030002732879352156";

    double f;
    char   newstr [50];
    // convert string in `str` to float
    sscanf (str, "%le", &f);

    sprintf (newstr, "%.12E", f);
    printf ("result is %s\n", newstr);
    return 0;
}
wallyk
A: 

#include using namespace std; ... double dd = strtod( str ); cout << scientific << dd << endl;

Sanjaya R
No, that outputs 0.4794255386042030002732879352156, which isn't what he asked for.
dcp
No, it outputs 4.794255e-01 ( the default precision is 6 ).'cout.precision(12)' would set it to twelve.
Sanjaya R
+1  A: 

Convert to long double using sscanf(), then use sprintf() to print it back out as a string, using the scientific formatter:

long double x;
char num[64];

if(sscanf(string, "%Lf", &x) == 1)
  sprintf(num, "%.12Le", x);

Not sure if even long double actually gives you 12 significant digits, though. On my system, this generates "4.79425538604e-01".

unwind
John Scipione
@John: Yes, thanks!
unwind
A: 

Depending on how many decimal places you want (12 in this case) you could do something like this:

int main() { 
  char buff[500];
  string x = "0.4794255386042030002732879352156";
  double f = atof(x.c_str());
  sprintf(buff,"%.12fe-1",f*10);
  cout<<buff<<endl;
  return 0;
}

Result: ---------- Capture Output ----------

"c:\windows\system32\cmd.exe" /c c:\temp\temp.exe 4.794255386042e-1 Terminated with exit code 0.

dcp
+2  A: 

Looking at the strings in your question, it would seem you are using base-10 logarithms. In that case wouldn't it be relatively easy to just count the leading or trailing zeros and put that in an exponent, by scanning the strings directly?

Maybe i'm missing something..

S.C. Madsen
Agreed. In this case he could simply find the position of the point, move it, and append the exponent as a count of how far and in which direction the point was moved.
Clifford
+1  A: 

An IEEE 754 64 bit float (i.e. double precision), is good for 15 decimal significant figures, so you should have no problem converting to double. You are more likely to run into the problem of getting the format specifier to display all available digits. Although from the examples posted, this seems not to be the case.

Clifford
you are right a double is good enough once I added in a proper format string I even got 17 decimal digits out of a double, I am sure I could get more but that is plenty.
John Scipione
Not with a double you couldn't! In fact not even 17 is possible regardless of what you thing you got. The mantissa is 52 bits, 2^52 is a 16 digit decimal number, so the limit is 15 digits (mathematically 15.65 digits) because 52 bits is sufficient to represent all possible 15 digit numbers. Note that I am talking about *significant figures* not decimal places.
Clifford
+2  A: 

You are looking for something like this?

Here is a sample:

 // modify basefield
#include <iostream>
#include <sstream>

using namespace std;

int main () {
    std::string numbers("0.4794255386042030002732879352156");
    std::stringstream stream;
    stream << numbers;
    double number_fmt;
    stream >> number_fmt;
    cout.precision(30);

    cout << number_fmt << endl;

    cout.precision(5);
    cout << scientific << number_fmt << endl;
  return 0;
}

Output:

0.479425538604203005377257795772

4.79426e-01

coelhudo