diff --git a/.gitignore b/.gitignore index 65c3a75..f1dd8b8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ src/*.o tests/*.o testrunner +cheapgmp diff --git a/README.md b/README.md index d011f78..0b6071c 100644 --- a/README.md +++ b/README.md @@ -1,78 +1,38 @@ # Purpose -Prove I'm not an idiot. +This was a résumé test question given to someone else, who had brought +it to the August 7th, 2015 Beer && Coding, in the hopes that we would +help him solve it. We were not successful, although I did get pretty +far on my own with a solution written in Scheme. -As an exercise, I decided to do this homework in C++. As I haven't -written any C++ in 15 years, this was... entertaining. +The problem stated was: -# Task #1 + Given a number (assume base 10) less than 10,000, write a program in + C++ that will reverse the digits of that number, calculate the + original number to the power of the new number, and print it out. + You may not use Boost, GMP, or any library other than that provide + by the C++ Standard Library. - Write a function which computes the some [sic] of q, q^2, q^3, … q^n, - where "^" denotes power or exponent. For example, the sum of - 2,4,8,16 is 30. What is the complexity? +I don't know C++. I haven't ever written C++ profesionally, and I +haven't actually *looked* at C++ since 1999 or so. As a professional, +I'm aware of what's going on in the zeitgeist, and at my job at Spiral +Genetics I interacted with two very talented C++ developers a lot, so I +was aware of things like the emerging C++ Standard Library and RAII and +so forth. I didn't know what they *meant*, but I had heard them. I've +also been aware of the emerging standards in C++11 and C++14, mostly +thanks to Slashdot, Lobsters, and their ilk (don't read the comments, +don't **ever** read the comments), so I'd *heard* about auto_ptr and +C++11 lambdas and the like. -The complexity is linear. This is a basic sigma function, once you know -the underlying formula, production is simple. The requirements for the -code (that you determine both the base of your exponent collection, and -know how many you want) are difficult to discern from a simple reading -of the instructions. +It took about an hour of googling to get up to speed on things like +namespaces, containers, for_each, lambdas, and the like. I really like +the new unique\_ptr construction. That's very nice. -If I'd allowed myself to use boost(), I've written this using the -accumulate() function, but I'd have to figure out how to create a range -iterator. +My basic solution degrades to 4th-grade mathematics: Break the +multiplicand up into a list of single digits, multiply each digit +with the multiplier, then redistribute the values up the tens, hundreds, +etc. etc. This solution is not particularly fast or space-efficient, +but it has the virtue of being comprehensible by any ten-year-old. -# Task #2 - - Write a function GetMax(Node list), which finds the maximum integer - value in the list - -In order to make this at all interesting, I set myself the task of -learning how to create function templates, which we didn't have back in -1999. It turned out to be relatively straightforward, although the -"typename" declarator in the template before std::list::iterator is a -bit of cargo-cult I got from compiler's warnings; I really need to go -back and read some of Alexandrescu's books, especially since I got them -all for free after spotting a typo in one back in 1997 or so. - -I've provided a Makefile and unit tests using the Aeryn C++ Test -Framework. It was a framework chosen at random from a list I found -after searching for "C++ Test Frameworks," I can't comment on its -quality, but it did the job. It looked familiar enough compared to -JUnit or Mocha. - -# Commentary - -It's been a long time since I wrote C++. The syntactical noise of C++ -annoys me a bit since I've started writing in "An elegant language for a -more civilized time," and I'm so far out of experience with it that the -modern paradigm of Resource Allocation Is Initialization and all of the -wonderful new toys like auto, unique_ptr, lambdas and the like would -take me a month or two to catch up. - -If I'd written this in Javascript they'd have been one-liners: - - exponentialSum = (base, count) => - _.reduce(_.range(1, count + 1), ((m, v) => return m + Math.pow(base, v)), 0); - - largestValue = _.max; - -or: - - largestValue = (list) => Math.max.apply(Math, list); - -I'm pretty sure that the functions I wrote have simple equivalents in -some library somewhere. Boost seems to have just about everything. - -The Makefile is just something I pulled out of an old project and -cleaned up for the purposes of this exercise. - -Total time spent: Approximately 75 minutes. - -# Addenda - -The [sic] in the original task description is a bit of a snark. That -and the instruction to "Please use of of [sic] Java/C++/C#/Javascript" -ought to be professionally embarrassing to someone seeking viable, -self-respecting candidates. diff --git a/cheapgmp b/cheapgmp deleted file mode 100755 index 6320c49..0000000 Binary files a/cheapgmp and /dev/null differ diff --git a/src/cheapgmp.cpp b/src/cheapgmp.cpp index 20cc480..f232a34 100644 --- a/src/cheapgmp.cpp +++ b/src/cheapgmp.cpp @@ -4,20 +4,33 @@ using namespace std; namespace cheapgmp { namespace { - void multiply(gmrep &in, ulong by) { + + /* Given a list representing a decimal number as a multiplicand, + multiply each digit by a multiplier, leaving in its place the + remainder modulo 10 of the result, and using result diviso 10 + as a carryover to the 10^(n+1) slot */ + + void multiply(gmrep &multiplicand, ulong multiplier) { gmrep res(new lmrep()); ulong rem = 0; - for_each(in->rbegin(), in->rend(), [&rem, by](ulong &i) { - ulong t = (i * by) + rem ; + for_each(multiplicand->rbegin(), multiplicand->rend(), [&rem, by](ulong &i) { + ulong t = (i * multiplier) + rem ; i = t % 10 ; rem = t / 10; }); + + /* When out of list elements, drain the result diviso 10 until + the new result is complete */ while(rem > 0) { in->push_front(rem % 10); rem = rem / 10; } } + + /* Given an integer, return a std::list in which each node + represents a decimal placement, i.e the end() is the ones, + end().prev() is the tens, etc. */ gmrep makerep(const ulong in) { gmrep res(new lmrep()); @@ -34,6 +47,9 @@ namespace cheapgmp { return res; } } + + /* Perform the operation multiple times, to produce an exponential + result */ gmrep makepower(const ulong base, const ulong power) { if (power == 0) {