double to String conversion, better way?
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 20

Thread: double to String conversion, better way?

Hybrid View

  1. #1
    Join Date
    Feb 2001
    Posts
    2,455

    double to String conversion, better way?

    I need to convert from a double value to an architectural string format. EG:

    25.875 ->> 25'-10 1/2"

    To do this, I have written the following code, but I am not sure about it although it seems to work.

    I thought I would post the code for any possible improvement suggestions:


    Code Removed!
    On second thought, I will attach a CEdit derived class I use that converts the value from a real (double) to a string (in imperial) as required.


    Take a look if you are interested.

    its ugly I know!

    Any suggestions.

    Mike B
    Last edited by MikeB; October 23rd, 2003 at 03:28 PM.

  2. #2
    Join Date
    Feb 2001
    Posts
    2,455
    Here is the attachment.

    Mike B
    Attached Files Attached Files

  3. #3
    Join Date
    Apr 1999
    Posts
    27,433
    Originally posted by MikeB
    Here is the attachment.

    Mike B
    Why not make this a general C or C++ function?

    There is no need for any GUI involvement such as CEdit. If I were you, I would remove the CEdit dependency -- something like this:
    Code:
    std::string ArchitectureFormat(double d)
    {
       std::string s;
       // code to convert
       return s;
    }
    You then call this function whenever you want an architectural string, regardless of whether it is going to a CEdit, the console window, a file, or to the printer.

    Regards,

    Paul McKenzie

  4. #4
    Join Date
    Feb 2001
    Posts
    2,455
    Originally posted by Paul McKenzie
    Why not make this a general C or C++ function?
    ....
    Regards,

    Paul McKenzie
    You must have sent me a paranormal message. I was just thinking that exact same thing.

    Thanks for the reply,.

    Mike B

  5. #5
    Join Date
    Apr 1999
    Posts
    27,433
    To start"
    Code:
    #include <string>
    #include <sstream>
    #include <iostream>
    
    std::string ArchitectureFormat(double d)
    {
        std::ostringstream strm;
    
       int numft = (int)d;
       double frac = d - (double)numft;
       double dInches = frac * 12.0;
       int nInches = (int) dInches;
       
       // the fractional part for inches was not done.  This is a little bit harder to do.  But here is the output.
       
       // code to convert
      strm << numft << "'-" << nInches << "\"";
      return strm.str();
    }
    
    int main()
    {
        std::cout << ArchitectureFormat(25.875);
    }
    This is just a starting point. There are things left out, but this is much simpler than what you are attempting to do. You just need to fill in the gaps in the function I provided.

    Regards,

    Paul McKenzie

  6. #6
    Join Date
    Feb 2001
    Posts
    2,455
    Thank Paul. This is what I have so far. Still tweeking it but when I compile I get an assertion:

    Code:
    #include <string>
    #include <sstream>
    #include <iostream>
    #include <vector>
    
    typedef std::vector<double>				DRANGE;
    typedef std::vector<double>::iterator	DITER;
    
    DRANGE		BuildPrecisionRange(int nPrecision);
    bool		GetFraction(DRANGE dRange, double dFraction, int& nNumerator, int& nDenominator);
    std::string ArchitecturalFormat(double d, int n);
    
    DRANGE BuildPrecisionRange(int nPrecision)
    {
        if((nPrecision % 2) != 0)
    		++nPrecision;
    
    	double dDecimal = 1.0 / (double)nPrecision;
    	double dTotal = dDecimal / 2.0;
    
    	DRANGE dRange;
    	dRange.push_back(0.0);
    	dRange.push_back(dTotal); // Starting point
    	
    	while(dTotal + dDecimal < 1)
    		dRange.push_back(dTotal += dDecimal);
    
    	return dRange;
    }
    
    bool GetFraction(DRANGE dRange, double dFraction, int& nNumerator, int& nDenominator)
    {
    	bool bFound = false;
    
    	double dValue = 0.0;
    	DITER it = dRange.begin();
    	for(; it != dRange.end() - 1; it++)
    	{
    		double dLow = *it;
    		double dHigh = *(it + 1);
    
    		if(dFraction > dLow && dFraction <= dHigh)
    		{
    			double dHalfWay = dLow + ((dHigh - dLow) / 2);
    			dValue = dFraction > dHalfWay ? dHigh : dLow;
    			bFound = true;
    			break;
    		}
    	}
    	
    	double dGap = bFound ? dRange[1] * 2 : 0;
    	nNumerator = bFound ? (int)(dValue / dGap) : 0;
    	nDenominator = bFound ?  (int)(1 / dGap) : 0;
    	
    	return bFound;
    }
    
    std::string ArchitecturalFormat(double d, int n)
    {
    	std::ostringstream strm;
    
    	int nFeet = (int)d;
    	double dFrac = d - (double)nFeet;
    	double dInches = dFrac * 12;
    	int nInches = (int)dInches;
    	double dFracInches = dInches - (double)nInches;
    
    	DRANGE dRange = BuildPrecisionRange(n);
    
    	int nNumerator, nDenominator;
    	GetFraction(dRange, dFracInches, nNumerator, nDenominator);
    
    	strm << nFeet << "'-" << nInches << " " << nNumerator << "\\" << nDenominator << "\"";
    	return strm.str;
    }
    
    int main()
    {
    	std::cout << ArchitecturalFormat(28.875, 4);
    	return 0;
    }
    Last edited by MikeB; October 23rd, 2003 at 06:05 PM.

  7. #7
    Join Date
    Sep 2002
    Location
    14 39'19.65"N / 121 1'44.34"E
    Posts
    9,815
    Originally posted by MikeB
    Still tweeking it but when I compile I get an assertion:
    ...and now you want us to guess which assertion is failing?

  8. #8
    Join Date
    Feb 2001
    Posts
    2,455
    Originally posted by gstercken
    ...and now you want us to guess which assertion is failing?
    hehe, sorry, thought it would be obvious to the guru gods such as yourself

    It is not really an assertion I don' t think, it is "Unhandled exception in GeneralFunctions.exe: 0XC0000005 Access Violation"

    Thanks for the interest gstercken

    Mike B

  9. #9
    Join Date
    Sep 2002
    Location
    14 39'19.65"N / 121 1'44.34"E
    Posts
    9,815
    Originally posted by MikeB
    It is not really an assertion I don' t think, it is "Unhandled exception in GeneralFunctions.exe: 0XC0000005 Access Violation"
    OK, so it is not an assertion failure but an access violation...
    Now while I could of course go through your code and figure out where and why it fails or copy it to a local project and compile it and try to run it to see what happens - it would be easier if you would provide that information. Just run your code in the debugger and tell us on which line it stops when the access violation occurs.

  10. #10
    Join Date
    Feb 2001
    Posts
    2,455
    More info to provide. I added the following line to the code:
    Code:
    std::string str = ArchitecturalFormat(28.875, 4);
    and it appears the str is invalid after the ArchitecturalFormat(...) returns.

    Maybe something wrong with the use of ostringstream in the architecturalFormat(..) function?

    Any ideas?

    The line it fails was highlighted in red in a previouse post. Sorry should have indicated why.

    fails here in main() std::cout << ArchitecturalFormat(28.875, 4);

    Mike B

  11. #11
    Join Date
    Feb 2001
    Posts
    2,455
    Found it gstercken, thanks for you input. The problem was inside the ArchitecturalFormat(...) function:
    Code:
    return strm.str
    
    should be 
    
    return strm.str()
    Thanks for the help, sorry for the vaguness (if that is a word!)

    Mike B

  12. #12
    Join Date
    Sep 2002
    Location
    14 39'19.65"N / 121 1'44.34"E
    Posts
    9,815
    Oops, I just wanted to reply that your call to strm.str() was missing the parentheses... I admit that I didn't find that out by looking at the code, but by running your code in the debugger. Actually, it doesn't fail on the line you indicated, but inside the implementation of strlen. Walking up the callstack brings you to the implementation of std::string, where you could see that the 'this' pointer is invalid, indicating that ArchitecturalFormat() returned something else than a valid string object.

  13. #13
    Join Date
    Feb 2001
    Posts
    2,455

    Red face It works!!!!

    Here is the complete code. Which may not be the best but I am proud of it!

    Thanks for the help Paul and gstercken. You guys are number 1. Try it out!

    Mike B

    Version #1.2 lol This was fun to work on
    Code:
    #include <string>
    #include <sstream>
    #include <iostream>
    #include <vector>
    
    typedef std::vector<double>				DRANGE;
    typedef std::vector<double>::iterator	DITER;
    
    DRANGE		BuildPrecisionRange(int nPrecision);
    bool		GetFraction(DRANGE dRange, double dFraction, int& nNumerator, int& nDenominator);
    std::string ArchitecturalFormat(double d, int n);
    
    DRANGE BuildPrecisionRange(int nPrecision)
    {
        if((nPrecision % 2) != 0)
    		++nPrecision;
    
    	double dDecimal = 1.0 / (double)nPrecision;
    	double dTotal = dDecimal / 2.0;
    
    	DRANGE dRange;
    	dRange.push_back(0.0);
    	dRange.push_back(dTotal); // Starting point
    	
    	while(dTotal + dDecimal < 1)
    		dRange.push_back(dTotal += dDecimal);
    
    	return dRange;
    }
    
    bool GetFraction(DRANGE dRange, double dFraction, int& nNumerator, int& nDenominator)
    {
    	bool bFound = false;
    
    	double dValue = 0.0;
    	DITER it = dRange.begin();
    	for(; it != dRange.end() - 1; it++)
    	{
    		double dLow = *it;
    		double dHigh = *(it + 1);
    
    		if(dFraction > dLow && dFraction <= dHigh)
    		{
    			double dHalfWay = dLow + ((dHigh - dLow) / 2);
    			dValue = dFraction >= dHalfWay ? dHigh : dLow;
    			bFound = true;
    			break;
    		}
    	}
    	
    	if(bFound)
    	{
    		double dPrecision = dRange[1] * 2;
    		nNumerator = (int)(dValue / dPrecision);
    		nDenominator = (int)(1 / dPrecision);
    	}
    	else
    	{
    		nNumerator = 1;
    		nDenominator = 1;
    	}
    	return bFound;
    }
    
    std::string ArchitecturalFormat(double d, int n)
    {
    	std::ostringstream strm;
    	int nNumerator = 0;
    	int nDenominator = 0;
    	bool bFraction = false;
    	int nFeet = (int)d;
    	double dFrac = d - (double)nFeet;
    	double dInches = dFrac * 12;
    	int nInches = (int)dInches;
    	double dFracInches = dInches - (double)nInches;
    	double dTolerance = (1.0/(double)n) / 2.0;
    
    	if(dFracInches > dTolerance)
    	{
    		DRANGE dRange = BuildPrecisionRange(n);
    
    		GetFraction(dRange, dFracInches, nNumerator, nDenominator);
    		if(nNumerator == nDenominator) // Rounding up
    			++nInches;
    		else if(nNumerator == 0)
    		{/*Do Nothing*/}
    		else
    		{
    			bFraction = true;
    	
    			if(nNumerator > 0)
    			{
    				if(nDenominator % nNumerator == 0)
    				{
    					nDenominator /= nNumerator;
    					nNumerator = 1;
    				}
    			}
    		}
    	}
    
    	if(bFraction)
    		strm << nFeet << "'-" << nInches << " " << nNumerator << "\\" << nDenominator << "\"";
    	else
    		strm << nFeet << "'-" << nInches << "\"";
    
    	return strm.str();
    }
    
    int main()
    {
    	double dValue = 0.0;
    	int nPrecision = 0;
    
    	std::cout << "Enter dimension (decimal feet) :\n";
    	std::cin >> dValue;
    	std::cout <<"\nEnter precision (1/ n):";
    	std::cin >> nPrecision;
    	
    	std::cout << "\nArchitectural string " << ArchitecturalFormat(dValue, nPrecision);
    
    	char c;
    	std::cin >> c;
    	return 0;
    }
    Last edited by MikeB; October 23rd, 2003 at 06:52 PM.

  14. #14
    Join Date
    Sep 2002
    Location
    14 39'19.65"N / 121 1'44.34"E
    Posts
    9,815
    However, I wonder why the compiler didn't choke at this (after all, ArchitecturalFormat() was supposed to return a std::string object, but it returned a function pointer (the address of strm.str()). Probably has to do with some overloaded pointer operator in std::string, but I'm to lazy to look into that now... One of the reasons why I avoid using std::string whenever possible, and use CString instead.

  15. #15
    Join Date
    Apr 1999
    Posts
    27,433
    Originally posted by gstercken
    However, I wonder why the compiler didn't choke at this (after all, ArchitecturalFormat() was supposed to return a std::string object
    It does...

    http://www.cplusplus.com/ref/iostrea...tream/str.html

    std::ostringstream::str() returns a std::string.

    Regards,

    Paul McKenzie

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center