Programming Forums

Programming Forums (http://www.programmingforums.org/forumindex.php)
-   C++ (http://www.programmingforums.org/forum15.html)
-   -   Is there a better way to do this? (http://www.programmingforums.org/showthread.php?t=14574)

peaceofpi Nov 24th, 2007 2:05 PM

Is there a better way to do this?
 
I'm recreating whatever things from algebra/trigonometry that I can think of as a learning exercise. I wanted to post the whole thing for feedback but I don't know how that'd go in this board (it is for support after all).

This function turns a degree measure into degrees, minutes, and seconds. It works fine but I want to know if there's a better way to put the results in one place rather than three stringstreams and three strings. I want the function to return a string because there are three numbers as an answer.

:

  1. string deg2dms(double deg)
  2. {
  3.         double n = deg;
  4.         int degrees = (int)n;
  5.         n -= degrees;
  6.         n *= 60.0;
  7.         int minutes = (int)n;
  8.         n -= minutes;
  9.         n *= 60.0;
  10.         int seconds = (int)n;
  11.         if ( (n - seconds) >= 0.5 )
  12.                 seconds += 1;
  13.  
  14.         stringstream degss;
  15.         stringstream minss;
  16.         stringstream secss;
  17.         string degstr;
  18.         string minstr;
  19.         string secstr;
  20.         degss << degrees;
  21.         minss << minutes;
  22.         secss << seconds;
  23.         degss >> degstr;
  24.         minss >> minstr;
  25.         secss >> secstr;
  26.         return degstr + " " + minstr + " " + secstr;
  27. }


DaWei Nov 24th, 2007 3:18 PM

Re: Is there a better way to do this?
 
The use of stringstreams, in this instance, amounts to a presentation issue. You have to deal with that, make the conversions, fiddlefart around, and convert back to presentation.

Your code doesn't look half bad, but you're expecting all your operations to work properly and magically. Get a life. Things don't always work out. Test for success and take appropriate actions if something fails.

Anything less is the action of an unemployable newbie or a schlock. Choose your category. Your potential employer is entitled to disagree.

Arla Nov 24th, 2007 3:22 PM

Re: Is there a better way to do this?
 
Personally I'd probably create a structure to house the three separate values and return that from the function. Stringing them together to return just means you end up with an amalgamated text string that you would then probably need to deconstruct to use elsewhere.

Jessehk Nov 24th, 2007 4:26 PM

Re: Is there a better way to do this?
 
Some people might think this is overcomplicated, but if you have Boost I like the Tuple library. It's specifically designed to make returning multple values from a function easier.

:

  1. #include <iostream>
  2.  
  3. #include <boost/tuple/tuple.hpp>
  4.  
  5. typedef boost::tuple<int, int, int> ResultType;
  6.  
  7. ResultType deg2dms( double deg ) {
  8.     double n = deg;
  9.  
  10.     int degrees = static_cast<int>( n );
  11.     n -= degrees;
  12.     n *= 60.0;
  13.  
  14.     int minutes = static_cast<int>( n );
  15.     n -= minutes;
  16.     n *= 60.0;
  17.  
  18.     int seconds = static_cast<int>( n );
  19.     if ( (n - seconds) >= 0.5 )
  20.         seconds += 1;
  21.  
  22.     return ResultType( degrees, minutes, seconds );
  23. }
  24.  
  25. int main() {
  26.     ResultType result = deg2dms( 34.5 );
  27.  
  28.     //Access each element
  29.     //In this case, we're accessing the degrees
  30.     std::cout << result.get<0>() << std::endl;
  31.  
  32.     // Or, Something like this
  33.     #define DEGREES 0
  34.     #define MINUTES 1
  35.     #define SECONDS 2
  36.     std::cout << result.get<MINUTES>() << std::endl;
  37. }


I copied your algorithm, but converted it to use static_cast's instead. I can't comment on the algorithm itself. :)

peaceofpi Nov 25th, 2007 12:16 AM

Re: Is there a better way to do this?
 
Quote:

Originally Posted by DaWei
Your code doesn't look half bad

DaWei + praise = ?!

Quote:

Originally Posted by DaWei
(rest of it)

Phew, I thought I did a good job for a second! ;)

Quote:

Originally Posted by Arla
Personally I'd probably create a structure to house the three separate values and return that from the function.

I'll see what I can do with that, but it's not making complete sense yet.

Jesse: Boost is nice (although I haven't gotten it to work yet) but I want to make something I can carry with me anywhere.

Arla Nov 25th, 2007 12:26 AM

Re: Is there a better way to do this?
 
Having done a bit of websurfing (sorry I use C# so didn't want to post code as my syntax would probably be a bit off) this site

http://www.cplusplus.com/doc/tutorial/classes.html

Seemed to have some good information on what I was meaning, create a class, with three int's in it (Degrees, Minutes and Seconds) and then have the function return your new class as it's result.

peaceofpi Nov 25th, 2007 12:45 AM

Re: Is there a better way to do this?
 
Well, I understand what you mean, but you can't return a class instance as a function result. Jesse's answer is basically what I want, but I was hoping for a solution within the standard headers.

edit: By the way, Jesse, I tried out the boost solution. It gave errors so I played around with the code (I've never used tuples or boost so it was guesswork) till it was satisfied:

:

  1. typedef boost::tuples::tuple<int,int,int> tuple;
  2.  
  3. tuple deg2dms( double deg )
  4. {
  5.         double n = deg;
  6.  
  7.         int degrees = static_cast<int>( n );
  8.         n -= degrees;
  9.         n *= 60.0;
  10.  
  11.         int minutes = static_cast<int>( n );
  12.         n -= minutes;
  13.         n *= 60.0;
  14.  
  15.         int seconds = static_cast<int>( n );
  16.         if ( (n - seconds) >= 0.5 )
  17.                 seconds += 1;
  18.  
  19.         return tuple(degrees, minutes, seconds);
  20. }


Can't cout<<deg2dms(x); though, apparently there's no << for tuples.

Jessehk Nov 25th, 2007 9:30 AM

Re: Is there a better way to do this?
 
Quote:

Originally Posted by peaceofpi (Post 137485)

Can't cout<<deg2dms(x); though, apparently there's no << for tuples.

:

  1. #include "boost/tuple/tuple_io.hpp"


Which defines an operator<< that outputs things in the form
:

(x y z)

But if you really want to do it with standard headers, you should just make a custom struct and return it -- basically what Arla suggested.

Jessehk Nov 25th, 2007 10:05 AM

Re: Is there a better way to do this?
 
Quote:

Originally Posted by peaceofpi (Post 137485)
Well, I understand what you mean, but you can't return a class instance as a function result.

Hold on a second. What do you mean?

:

  1. #include <iostream>
  2.  
  3. class Heading {
  4. private:
  5.     int degrees_;
  6.     int minutes_;
  7.     int seconds_;
  8. public:
  9.     Heading( int degrees, int minutes, int seconds );
  10.  
  11.     int degrees() const { return degrees_; }
  12.     int minutes() const { return minutes_; }
  13.     int seconds() const { return seconds_; }
  14. };
  15.  
  16. std::ostream &operator<<( std::ostream &os, const Heading &heading ) {
  17.     os << "(" << heading.degrees() << ", " << heading.minutes() << ", " << heading.seconds() << ")";
  18.     return os;
  19. }
  20.  
  21. Heading::Heading( int degrees, int minutes, int seconds ) :
  22.     degrees_( degrees ),
  23.     minutes_( minutes ),
  24.     seconds_( seconds ) {}
  25.  
  26. Heading testFunction() {
  27.     return Heading( 33, 5, 2 );
  28. }
  29.  
  30. int main() {
  31.     Heading heading = testFunction();
  32.  
  33.     std::cout << heading << std::endl;
  34. }


:

$ ./example
(33, 5, 2)


You are copying the instance on the return from the function (which does add overhead), but the same thing happens with Boost.Tuple. The only reason to use Boost.Tuple in this case in convenience.

peaceofpi Nov 25th, 2007 12:09 PM

Re: Is there a better way to do this?
 
Quote:

Originally Posted by Jessehk (Post 137502)
:

  1. #include "boost/tuple/tuple_io.hpp"


That helps!

Oops, operator<< slipped my mind.

:

  1. using namespace boost::tuples;
  2. tuple<int,string,int,string,int,string> deg2dms(double deg)
  3. {
  4.         double n = deg;
  5.  
  6.         int degrees = static_cast<int>(n);
  7.         n -= degrees;
  8.         n *= 60.0;
  9.  
  10.         int minutes = static_cast<int>(n);
  11.         n -= minutes;
  12.         n *= 60.0;
  13.  
  14.         int seconds = static_cast<int>(n);
  15.         if ( (n - seconds) >= 0.5 )
  16.                 seconds += 1;
  17.  
  18.         tuple<int,string,int,string,int,string> dms
  19.         (degrees,"degrees,",minutes,"minutes,",seconds,"seconds");
  20.         return dms;
  21. }



All times are GMT -5. The time now is 3:15 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC