To convert an ASCII string to an integer value, you cannot get much faster than what atoi
is doing, but you may be able to speed it up by implementing a conversion function that you use inline. The version below increments the pointer past the digits scanned, so it doesn't match atoi
semantics, but it should help improve parser efficiency, illustrated below. (Error checking is obviously lacking, so add it if you need it.)
static inline int my_parsing_atoi(const char *&s) {
if (s) {
bool neg = false;
int val = 0;
if (*s == '-') { neg = true; ++s; }
for (;isdigit(*s);++s) val = 10*val + (*s - '0');
return neg ? -val : val;
}
return 0;
}
const char *p = input_line;
if (p) {
p += strspn(p, " ");
while (*p) {
int value1 = my_parsing_atoi(p);
p += strspn(p, " ");
}
}
Make sure you have profiled your code properly so that you know that your routine is compute bound and not I/O bound. Most of the time, you will be I/O bound, and the suggestions below are ways to mitigate it.
If you are using the C or C++ file reading routines, such as fread
or fstream
, you should be getting buffered reads which should already be pretty efficient, but you can try to use underlying OS calls, such as POSIX read
, to read the files in larger blocks at a time to speed up file reading efficiency. To be really fancy, you can perform an asynchronous read of your file while you are processing it, either by using threads, or by using aio_read
. You can even use mmap
, and that will remove some data copying overhead, but if the file is extremely large, you will need to manage the map so that you munmap
the portions of the file that have been scanned and mmap
in the new portion to be scanned.
I benchmarked my parse routine above and the OP's routine using code that looked like this:
clock_t before_real;
clock_t after_real;
struct tms before;
struct tms after;
std::vector<char *> numbers;
make_numbers(numbers);
before_real = times(&before);
for (int i = 0; i < numbers.size(); ++i) {
parse(numbers[i]);
}
after_real = times(&after);
std::cout << "user: " << after.tms_utime - before.tms_utime
<< std::endl;
std::cout << "real: " << after_real - before_real
<< std::endl;
The difference between real
and user
is that real
is wall clock time, while user
is actual time spent by the OS running the process (so context switches are not counted against the running time).
My tests had my routine running almost twice as fast as the OP's routine (compiled with g++ -O3
on a 64 bit Linux system).