Login [Register]
Don't have an account? Register now to chat, post, use our tools, and much more.
August 7, 2009
C++ Stream Precision

Say that you're writing a program that converts GPS NMEA strings into decimal coordinates. The output of your GPS receiver, grabbed by a serial-port input program, might look something like this:

Code:
$GPRMC,230632.000,A,4043.7187,N,07359.3728,W,0.23,189.48,070809,,*10

Of course, this is not particularly useful, so we will use strtok and some loop magic to create two variables, lat and lon. Here's how they'll be defined:

Code:
double lat, lon;
lat = strtod(lat_string,NULL)/100.0;
lon = strtod(lon_string,NULL)/100.0;
You'd expect that lat and long would contain 40.437187 and 73.593728 respectively, and you'd be correct. However, imagine your consternation when you try to use those numbers in a stream and suddenly your precision disappears:

Code:
std::cout << lat << ", " << lon << std::endl;
// Surprise! The output is "40.4372, 73.5937"

What happened? You might not know that along with a host of other attributes, like std::dec, std::hex, or std::oct, streams and stringstreams in C++ have an associated maximum decimal precision. In this case, you got caught in the trap of a default precision of four decimal places. The easy solution: simply set a nice large precision before your stream conversion:

Code:
std::cout.precision(10);
std::cout << lat << ", " << lon << std::endl;
// Whew. As it should be, the output is "40.437187, 73.593728"

In this case, that extra precision is the vital difference between reaching the town you meant to find and reaching your correct destination. Enjoy.
You can also inline it:


Code:
std::cout << std::setprecision(10) << lat


Also, I'm not familiar with the strtod() function, what does it do? Razz
Kllrnohj wrote:
You can also inline it:


Code:
std::cout << std::setprecision(10) << lat


Also, I'm not familiar with the strtod() function, what does it do? Razz
Converts a string to a double, strangely enough, Captain Sarcasm:
http://www.cplusplus.com/reference/clibrary/cstdlib/strtod/
KermMartian wrote:
Converts a string to a double, strangely enough, Captain Sarcasm:
http://www.cplusplus.com/reference/clibrary/cstdlib/strtod/


Huh, cool. Anyway, why were you talking about strtok then?
Kllrnohj wrote:
KermMartian wrote:
Converts a string to a double, strangely enough, Captain Sarcasm:
http://www.cplusplus.com/reference/clibrary/cstdlib/strtod/


Huh, cool. Anyway, why were you talking about strtok then?
Strtok was to pull apart the NMEA string at the commas to separate out GPS fix status, latitude, longitude, heading, ground speed, etc. Strtod was to use the numerical strings thus divided out and convert them to actual numeric types for further use. Smile
Why are you simply writing it to the console after you've parsed it? Or are you just using this as a pipe filter to pass on to some other app?
Kllrnohj wrote:
Why are you simply writing it to the console after you've parsed it? Or are you just using this as a pipe filter to pass on to some other app?
I'm using it to build queries to store latitude and longitude info into a MySQL db using the MySQL++ libs.
KermMartian wrote:
I'm using it to build queries to store latitude and longitude info into a MySQL db using the MySQL++ libs.


Uh, why? In case you didn't notice, there are already databases of lat/longs and their corresponding street addresses that you can use for free...
Kllrnohj wrote:
KermMartian wrote:
I'm using it to build queries to store latitude and longitude info into a MySQL db using the MySQL++ libs.


Uh, why? In case you didn't notice, there are already databases of lat/longs and their corresponding street addresses that you can use for free...
No, the latitude and longitude of the device at the current point in time. Other applications might want to immediately or later use the data of the last GPS fix for several purposes.
KermMartian wrote:
No, the latitude and longitude of the device at the current point in time. Other applications might want to immediately or later use the data of the last GPS fix for several purposes.


Just an FYI, but that isn't the sort of things databases are good for - far from it....
Kllrnohj wrote:
KermMartian wrote:
No, the latitude and longitude of the device at the current point in time. Other applications might want to immediately or later use the data of the last GPS fix for several purposes.


Just an FYI, but that isn't the sort of things databases are good for - far from it....
OK, so what do you suggest instead?
KermMartian wrote:
OK, so what do you suggest instead?


The typical approaches to sharing data across multiple processes. Depends on the platform, but there are plenty of IPC mechanisms out there - using a database to store a single data set that can rapidly change is going to be a major performance bottleneck and a waste of resources. You could even use RPC if you wanted.
March 5, 2010
OpenCV 2.0 and cvRetrieveFrame
In OpenCV 0.9.x, 1.0.x, and 1.1.x, the pair of functions cvGrabFrame() and cvRetrieveFrame() could be used to enqueue a frame into memory and access it in an OpenCV data structure, respectively. This method made it easy to hide some camera latency behind processing code, such that some processing could be performed on a frame while the next frame was being copied from the camera. The syntax to cvGrabFrame() and cvRetrieveFrame() was straightforward:


Code:
cvGrabFrame(capture);
IplImage* thisframe = cvRetrieveFrame(capture);


Fair enough. However, in OpenCV 2.0, released a few months ago, this throws strange errors; you can find various complaint threads around the 'net that talk about trying to compile and getting:


Code:
error: too few arguments to cvRetrieveFrame


I was stumped for an hour, and concerned that I wouldn't be able to use the function pair as I had hoped. None of the threads I found suggested anything more useful than downgrading my OpenCV. Eventually, I found the simple solution by poking through the OpenCV 2.0 source code:


Code:
IplImage* thisframe = cvRetrieveFrame(capture,1);


You should now be able to compile and run without errors.

OpenCV 2.0: cvShowImage Doesn't Update the Screen?
This is another simple OpenCV trick, and applies to 1.0 and 1.1 as well. The HighGUI system in OpenCV is an event-driven abstraction on top of the native windowing system, and contrary to my expectations, cvShowImage() simply copies the image specified into the window specified, but does not force the window to be redrawn. The function cvWaitKey() must be called in order for the event queue (including window redraws) to process; the argument is the number of milliseconds to wait, so I recommend something like:


Code:
cvWaitKey(10);


I tried smaller values, which seemed to not give the system enough time to actually redraw before the WaitKey delay ended. Keep in mind that using a value less than or equal to zero causes the system to wait indefinitely for a key. Cheers!
April 26, 2011
C++ Name Mangling/Demangling

When you compile a C or C++ program, it becomes necessary for the compiler/linker to generate unique names for your functions and class methods. You've probably seen these before, something horribly ugly like "_ZN3dsm13PythonTriggerISslE4FireERKSsRKlRl". Luckily, those aren't as cryptic as you might think. We could easily break down such a name (see the Wikipedia article about name mangling):


Code:
_ZN3dsm13PythonTriggerISslE4FireERKSsRKlRl

_ZN: starting delimiter
3 dsm: length 3, namespace dsm
13 PythonTrigger: length 13, class PythonTrigger
ISsl: instantiated template with two template types, std::string (Ss) and long (l)
E: End of class definition
4 Fire: method name, length 4, name Fire
E: End of method name definition
RKSs: first argument to function is a reference to a const std::string
RKl: second argument to function is a reference to a const long
Rl: third argument to function is a reference to a long


Simple enough, right? Luckily, you can make the process even faster with the c++filt tool:


Code:
kerm$ c++filt _ZN3dsm13PythonTriggerISslE4FireERKSsRKlRl
dsm::PythonTrigger<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, long>::Fire(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, long const&, long&)
Although this tips are pretty advanced for me and I don't get them, this topic seems very nice.
ScoutDavid wrote:
Although this tips are pretty advanced for me and I don't get them, this topic seems very nice.
Thanks very much. Unfortunately, I've been very much neglecting the topic; I hope to make amends for that by keeping it up-to-date for a while.
Not to hijack the thread or anything, but here's a rather interesting one I dealt recently:
Anonymous struct/union nesting

C allows you to define anonymous submembers of structs and pretend they don't exist in many cases. It's particularly useful if you want to have a couple ways to access the data in your struct. Consider the following structure:

Code:
struct names {
    union {
        char *raw[4];
        struct {
            char *en;
            char *es;
            char *fr;
            char *pt;
        };
    };
};

The two functions below will do exactly the same operations:

Code:
void f1(struct names *n) {
    n->en = "Joe";
    n->es = "Josť";
}
void f2(struct names *n) {
    n->raw[0] = "Joe";
    n->raw[1] = "Jose";
}

A possible case in which that might be useful would be if you wanted to normally set the members by name (as in f1 above), but also iterate through them in other cases:

Code:
void print_names(struct names *n) {
    int i;
    for (i=0; i < sizeof(n->raw) / sizeof(char *); i++) {
        if (n->raw[i] != NULL)
            puts(n->raw[i]);
    }
}

But what if you want to initialize such a struct? The usual bracketed declaration will work most of the time, but a single set of brackets will only initialize the outermost struct. The real issue is best demonstrated with code:

Code:
struct names n;
// Works, but wrong- assumes n.raw is aliased to the whole struct
n = {NULL};

// Correct
n = {{NULL}};

It's a bit easier to understand if we change the definition of our names struct:

Code:
struct names {
    int version;
    union {
        char *raw[4];
        // Omitted for brevity
    };
};

struct names n;
// Very wrong
n = {NULL};
// Works as expected
n = {0, {NULL}};

It gets exciting-looking when you have several levels of that sort of thing in one struct, then:

Code:
struct lc_names names = {{{NULL}}};
I like the openCV one.
graphmastur wrote:
I like the openCV one.
This is not a quality post up to Cemetech standards. Please do not spam to increase your postcount. Unlike many sites on the internet, we try to favor quality over quantity (or ideally, both Very Happy). Tari, that's an excellent and very thoroughly-written tip; thanks for sharing that. I'll definitely try that out...
Kind of simple thing i stumbled across, but you could do something like this in C.


Code:

#include <studio.h>

/* create a factorial of a number */

/* works for only small integers! */

/* TheEliteNoob */

int factorial(int n){ // n is what we get
   int t; // t is a temporary variable
   if(n<=1) return 1; // return 1 if num is 1 or a negative
        t = n * factorial(n-1); // get the factorial recrusivily
   return t; // return answer
}

int main(int argc, char *argv[]){
   printf("%d\n", factorial(7));
}

This is basically calling functions into printf and using them for displaying the results directly without a middle integer. Kind of an interesting quandary.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 2
» All times are GMT - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement