Wednesday, February 4, 2015

Euler Zero: DOA

Well, that didn't take long.

I've been doing a lot of template metaprogramming over the past few years. They can be useful in some circumstances, but when working (playing) with them on my own time it was primarily as 1) a challenge to see how far I could push them (without the compiler dying, as it did when template metaprogramming was proven Turing-complete), and 2) a source of amusement, like Sudoku. Although I'd been following the evolution of the C++14 Standard pretty closely (especially constexpr), for some reason I really didn't give much thought to it when I decided to write a zero-runtime solution for every Project Euler problem. I was just thinking in terms of templates and metaprogramming, rather than thinking about the undertaking as a whole in the context of all the Project Euler problems. Until Problem 2.

Problem 2 is extremely easy: Calculate the sum of all even Fibonacci numbers less than four million. Well, an iterative solution is easy. However, we can't really use an equally straightforward (but less efficient) recursive solution with a depth of 4,000,000 (actually, ~3.52M). After thinking about different ways to accomplish this with template metaprogramming (all of which are essentially ugly workarounds to the fact that all C++ TMP looping basically boils down to recursion of some sort), I decided I would just go the easy route and use the relaxations on constexpr in C++14.

And that was the nail in the coffin for Euler Zero. Initially, simply using constexpr functions felt almost...dirty, like I was cheating. It was just too easy. But after thinking about it, I thought "WTF am I doing wasting my time on template metaprogramming when it's effectively dead, killed by N3652" (more on this in a later post). So, my whole idea about presenting each solution as two files - one I could use as a check for correctness and a zero-runtime TMP solution now seems to me to be a colossal waste of time. With the relaxations on constexpr functions, any problem with parameters, constraints and definitions fixed at compile-time can be expressed as a series of constexpr functions with a zero-runtime solution. No template metaprogramming needed (or wanted).

So while the Project Euler problems may still be interesting or fun to solve in their own right, finding a zero-runtime solution in C++ is no longer of any interest to me whatsoever as a separate challenge: finding a correct solution is by definition a zero-runtime solution if you express it using constexpr. As a bonus, it's a hell of a lot cleaner and easier to understand than an equivalent TMP solution. Just to illustrate the point, soutions for problems 2 and 3 follow. As promised, both solutions will be preceded by a spoiler alert.

I'm not even going to bother posting each solution twice (verification implementation and zero-runtime implementation) - it is exactly the same code for each one. So here's the spoiler alert, for the last time on this blog:

***SPOILER ALERT***
Solution to a Project Euler problem follows: If you have not already done so, read this post before continuing. If you are working through the Project Euler problems and wish to solve them on your own (in C++), you might want to stop reading now if you have any self-respect. You've been given fair notice.

Problem 002
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.

Solution:

constexpr unsigned SumEvenFibs(const unsigned lim)
{
  unsigned sum = 0;
    
    unsigned prev2 = 1;
    unsigned prev1 = 1;
    unsigned next  = 2;
    while (prev1 < lim){
        if (!(prev1 & 1)){
            sum += prev1;
        }
        prev2 = prev1;
        prev1 = next;
        next = prev1 + prev2;
    }
  return sum;
}


const unsigned long sum = SumEvenFibs(4000000);
/*
#include <iostream>

int main()
{
  std::cout << sum << "\n";
}

*/
Take the code for Problem 2 and paste it into Matt Godbolt's excellent compiler explorer at https://gcc.godbolt.org/. Select "x86 clang 3.4.1" as the compiler (gcc does not yet support relaxations on constexpr, expected in GCC 5; expected in VC++ sometime before never "if all goes well"). Use the following command line options:
    --std=c++1y -Wall -pedantic -S

The Assembly output window will show:

1  sum:
2      .quad   4613732               # 0x466664
And there's your (zero-runtime) answer. To compile under gcc or MSVC to verify, just remove the constexpr specifier and uncomment main().


 
Problem 003
What is the largest prime factor of the number 600851475143 ?

Solution:

constexpr unsigned long LargestPrimeFactor(unsigned long long n)
{
    unsigned long lpf     = 0;
    unsigned long divisor = 2;

    while (n > 1){
        while(0 == (n % divisor)){
            if (divisor > lpf){
                lpf = divisor;
            }
            n /= divisor;
        }
        ++divisor;
        if ((divisor*divisor) > n){
            if (n > 1){
                if (n > lpf){
                    lpf = n;
                }
                break;
            }
        }
    }
    return lpf;
}

const unsigned long lpf = LargestPrimeFactor(600851475143);

/*
#include <iostream>
int main()
{
    std::cout << lpf << "\n";
    return 0;
}
*/
Take the code for Problem 3 and paste it into https://gcc.godbolt.org/ as with Problem 2 (same compiler and options).

The Assembly output window will show:

1  lpf:
2      .quad    6857            # 0x1ac9
Again, there's your answer.

Euler Zero, R.I.P.

Tuesday, February 3, 2015

Don't Call Me Dave

Actually, almost everybody in my life calls me Dave, not David. Notable exceptions are my mother, my bird, and (usually when she’s angry) my wife. Everyone else calls me Dave. It’s how I introduce myself to others, so I’m obviously fine with someone calling me that. However, “someone” does not include computers, or software. I do not introduce myself to them. At most, I authenticate my identity to them. I find casual familiarity from a non-sentient object or a computer program to be somewhat off-putting, to say the least.

I do not want to be greeted with an artificially cheerful “Hi Dave!” when I log into an application or a web site. I want my computers and software to be cold, calculating, distant. Completely inhuman. All business, all the time. When I validate my credentials, I want any acknowledgement (if there is any) to be something along the lines of “Currently logged in as (username).” Better yet, just a terse response only if I get the password wrong. A lack of notification about authentication failure is all that is necessary to know that I have successfully logged in.

My parents have a name for the GPS unit in their car because it – sorry, she – talks to them when giving directions. For my part, I do not ever want to hear a pre-programmed voice saying “You’ve got mail!” emanate from my computer: the “New Mail” indicator next to my Inbox is sufficient. Large numbers of people apparently enjoy this synthetic interaction, most noticeably with smartphone user interfaces programmed to speak – to the point that they even converse with the device (“Hey Cortana, nice misdial”, “I hope I never need 911, Siri, because you suck”). It seems to me that this kind of personalization of (or relationship with) an inanimate object is tantamount to making breakfast for a blow-up doll.

A computer is simply a tool, essentially no different than a microwave oven or a hammer. Do we really need a talking GPS? Can’t we just glance at it like any other dashboard indicator, like a speedometer? Or is that the road we’re on, the road to talking hammers and speedometers?

Hammer: “Nice swing, Dave! Your best yet! You really flushed that nail!”

Speedometer (screaming): “Holy shit Dave! You’re going way too fast! We’re all going to diiiiiiiieee!!!

Are we now that starved for human interaction that any kind of substitute, no matter how artificial, is something we crave?

Washing Machine: Hi Dave! You do realize that selecting Extra Rinse will use more water, thereby affecting your water bill? Please say “Extra Rinse” to confirm, “Regular” to-
Me: Extra rinse.
WM: I’m sorry, Dave, I didn’t quite get that. Please say “Extra Rinse” to-
Me: EXTRA RINSE
WM: I’m sorry, Dave, I didn’t quite get that. Let’s try again. Please say “Extra Rinse,” “Regular,” or “Cancel.”
Me: Fuck it, I’m not doing laundry. I’ll wear dirty clothes.
WM: I’m sorry, Dave, I didn’t quite get that. Let’s try again. You are now at the Main Menu. Please say-
Me: (kicks washing machine, walks out)
WM: I’m sorry, Dave, I didn’t quite get that.

One morning I will walk into my kitchen, only to be greeted by an appliance saying “Hi, Dave! Your toast is ready!” When that morning comes – and it will, my friend, probably sooner than you think – I am going to unplug my toaster pseudo-pal, walk into the bathroom and draw myself a bath. When the tub is sufficiently full, I am going to take my talking toastmaking unwanted would-be buddy, with its faux-friendly unrelenting perkiness (“Good morning Dave! I’ve burned your toast!”), plug it back in, and drop it right into the tub with me.

Or, I could just change my login name. But that would mean the machines have already won.