comments already cover most of the issue. I probably shouldn't reward such a badly-asked question with an answer, but I was curious about a couple things and tried them out.
On a standard install of 64bit Ubuntu 15.04:
$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 31440
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 65536
cpu time (seconds, -t) unlimited
max user processes (-u) 31440
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
Growing the stack to more than 64MiB will generate a segfault. I could increase the stack limit if I really wanted to, but it would be better to change the program.
$ bc -l
sqrt(65536*1024/8)
2896.30937574009865994585
$ for ((i=2894 ; i < 2899 ; i++)); do
echo $i;
printf '%s\n' "$i" 10000 | ./a.out || break;
echo;
done # extra echo because your code fails to print a newline
2894
21
2895
21
2896
Segmentation fault (core dumped)
Your system seems to have a default stack limit of 2M (5072*8 is just under, 5082*8 is just over).
C++ doesn't support variable-length arrays the way ISO C99 does. However, GNU C++ does support it. It's not a good idea for big arrays.
The C++ way to do this would be with a std::vector
, and emulate the 2D array by doing the index calculation yourself. (Don't make a vector of vectors unless you need some rows longer than others)
When filling the array, if the inner loop is over columns (i.e. the inner loop varies the 2nd index), gcc can auto-vectorize it (use -march=native
). Just interchanging for
lines, rather than changing the assignment, has the desired effect.
Unfortunately, it doesn't run faster for large problems, because memory is the bottleneck. (imul
with a throughput of one 64bit result per cycle can saturate main memory just fine. You'd get a speedup if your matrix fit in cache.)
Of course, for this algorithm, actually storing the multiplication table in a 2D array is not useful at all. Generate values on the fly and compare / increment. If you want to be able to answer repeated queries about the frequency of other numbers, loop and increment hashtable[i*j]
. Use a std::unordered_map
for the hash table.
Since multiplication has special properties, you can take advantage of this to compute the number of ways that i*j can be equal to x. Factor x into its prime factors, then count the ways these prime factors can be split into two groups. Don't forget to account for duplicates, e.g. 2*2*2*7 has (2*2) * (2*7) as one of its possible arrangements, but it doesn't matter which of the three 2s is grouped with the 7.
The brute force method is useful for testing the factoring method, which I will leave as an exercise for the reader.