I’m presenting a C++ application that uses the header-file-only Boost libraries, in this case Multiprecision. The link to the Boost documentation for this library is at the bottom of this post.
#include <algorithm>#include <iostream>#include <iomanip>#include <stdexcept>#include <filesystem>#include <string>#include <boost/multiprecision/cpp_int.hpp>using std::cout;using std::cerr;using std::left;using std::right;using std::setw;using std::fixed;using std::stoi;using std::string;using std::filesystem::path;using std::invalid_argument;using boost::multiprecision::cpp_int;void factorial(cpp_int n) {cpp_int a = 1;cout << right << setw(4) << fixed << n;while ( n > 0 ) {a = a * n;n--;}cout << left << "! = " << a << "\n";}int main(int argc, char *argv[]) {string appname = path(argv[0]).stem();if (argc == 1) {cout << appname << " can be invoked with one or more integer arguments.\n";cout << "Example: " << appname << " 10 20 30 40 50 60 70 80 90 100\n";}int index{1};try {for (; index < argc; factorial(stoi(argv[index++])));}catch(invalid_argument ia) {index--;cerr << apname << " invalid argument: " << argv[index] << "\n";return -1;}return 0;}
General Description
You’ve seen this code before, but in a far simpler code format than this. This version of the application has a try/catch block at lines 43 and 46 to catch an exception that stoi will throw if it’s given a non-numeric argument to parse. The catch statement explicitly catches an invalid argument and will print out what caused the application to stop. This is a lot better than the core dump it performed before this. Furthermore, if you call this application without any arguments it will give you several lines of help (at least, I hope they’re helpful). I’ve pulled a little bit of C++ slight-of-hand here by using std::filesystem::path to pull out the name of the application, or at least the name it was invoked by. This is an old trick in bash scripts and Python, but I’m using functionality from the C++ 17 standard.
How to Build
Building this is a one-liner:
g++ -std=c++20 SimpleFactorial.cpp -o SimpleFactorial
You’ll note that I didn’t use the -static
switch. Since there were no specific Boost libraries to link, I decided to just build a regular Linux application that will dynamically link against standard Linux C and C++ libraries. Those are common to every modern Linux distribution.
Sample Runs
The first example shows what happens when you invoke SimpleFactorial without any arguments.
~ ./SimpleFactorial SimpleFactorial can be invoked with one or more integer arguments.Example: SimpleFactorial 10 20 30 40 50 60 70 80 90 100
So what happens if we invoke that example?
~ ./SimpleFactorial 10 20 30 40 50 60 70 80 90 100 10! = 3628800 20! = 2432902008176640000 30! = 265252859812191058636308480000000 40! = 815915283247897734345611269596115894272000000000 50! = 30414093201713378043612608166064768844377641568960512000000000000 60! = 8320987112741390144276341183223364380754172606361245952449277696409600000000000000 70! = 11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000 80! = 71569457046263802294811533723186532165584657342365752577109445058227039255480148842668944867280814080000000000000000000 90! = 1485715964481761497309522733620825737885569961284688766942216863704985393094065876545992131370884059645617234469978112000000000000000000000 100! = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
What happens if we invoke SimpleFactorial with bad input data?
~ ./SimpleFactorial 10 20 foo 10! = 3628800 20! = 2432902008176640000SimpleFactorial invalid argument: foo
There’s another “hidden” feature of the application. What happens if you rename SimpleFactorial to something else, invoking it differently than it’s original name? What if you rename your source and build the application as something else? That’s where the path function comes into play. Let’s see what happens if we change the name of the application by way of a soft link.
~ ln -s SimpleFactorial foo~ ./foofoo can be invoked with one or more integer arguments.Example: foo 10 20 30 40 50 60 70 80 90 100
What happens when we have an error with this new name?
~ ./foo barfoo invalid argument: bar
This capability doesn’t seem all that important, but for more complex applications it comes in quite handy when you’re chasing down errors from within a long log file.
If you’re wondering why I didn’t use Boost’s Program Options, it’s because I didn’t understand the documentation well enough to learn how to pass an arbitrary number of arguments to the application. Maybe later…
Link: https://www.boost.org/doc/libs/1_80_0/libs/multiprecision/doc/html/index.html
You must be logged in to post a comment.