[doc] Comments & Readme

This commit is contained in:
Elf M. Sternberg 2015-08-06 13:40:14 -07:00
parent f7f6ef679d
commit e3bf7323fb
4 changed files with 48 additions and 71 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@
src/*.o src/*.o
tests/*.o tests/*.o
testrunner testrunner
cheapgmp

View File

@ -1,78 +1,38 @@
# Purpose # 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 The problem stated was:
written any C++ in 15 years, this was... entertaining.
# 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, I don't know C++. I haven't ever written C++ profesionally, and I
where "^" denotes power or exponent. For example, the sum of haven't actually *looked* at C++ since 1999 or so. As a professional,
2,4,8,16 is 30. What is the complexity? 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 It took about an hour of googling to get up to speed on things like
the underlying formula, production is simple. The requirements for the namespaces, containers, for_each, lambdas, and the like. I really like
code (that you determine both the base of your exponent collection, and the new unique\_ptr construction. That's very nice.
know how many you want) are difficult to discern from a simple reading
of the instructions.
If I'd allowed myself to use boost(), I've written this using the My basic solution degrades to 4th-grade mathematics: Break the
accumulate() function, but I'd have to figure out how to create a range multiplicand up into a list of single digits, multiply each digit
iterator. 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<t>::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.

BIN
cheapgmp

Binary file not shown.

View File

@ -4,21 +4,34 @@ using namespace std;
namespace cheapgmp { namespace cheapgmp {
namespace { 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()); gmrep res(new lmrep());
ulong rem = 0; ulong rem = 0;
for_each(in->rbegin(), in->rend(), [&rem, by](ulong &i) { for_each(multiplicand->rbegin(), multiplicand->rend(), [&rem, by](ulong &i) {
ulong t = (i * by) + rem ; ulong t = (i * multiplier) + rem ;
i = t % 10 ; i = t % 10 ;
rem = t / 10; rem = t / 10;
}); });
/* When out of list elements, drain the result diviso 10 until
the new result is complete */
while(rem > 0) { while(rem > 0) {
in->push_front(rem % 10); in->push_front(rem % 10);
rem = rem / 10; rem = rem / 10;
} }
} }
/* Given an integer, return a std::list<int> 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 makerep(const ulong in) {
gmrep res(new lmrep()); gmrep res(new lmrep());
if (in == 0) { if (in == 0) {
@ -35,6 +48,9 @@ namespace cheapgmp {
} }
} }
/* Perform the operation multiple times, to produce an exponential
result */
gmrep makepower(const ulong base, const ulong power) { gmrep makepower(const ulong base, const ulong power) {
if (power == 0) { if (power == 0) {
return makerep(base == 0 ? 0 : 1); return makerep(base == 0 ? 0 : 1);