C++: Using the Luhn Algorithm to Validate the CheckSum in the Personnummer Supplied in User Input

The Swedish Personnummer uses a variant of the Luhn Algorithm to generate a checksum (technically, a check digit) value that is is appended to the end of the personnummer. So, forexample, the nine-digit number YYMMDD-SSS would become YYMMDD-SSSC with the tenth digit being the checksum.

The model for generating the checksum is created by multiplying the alternating digits by a 2 or a 1 and, then, adding the sum of the products. In the nine-digit series, this means 212121212. So, for example, the number 010214-010 would become (0x2) + (1×1) + (0x2) + (2×1) + (1×2) + (4×1) + (0x2) + (1×1) + (0x2). When the product is greater than nine, the sum of those numbers is added. So, for example, 2×7 = 14 –> 1 + 4 = 5 and, thus, our result would be five for that single instance of digit.

The last number in the sum is then subtracted from 10 to create the checksum number. So, for example, 46 –> 6 and 10-6 = 4, and 4 becomes our checksum value.

Below is an C++ program to validate the checksum for the provided personnumer, given in the user-input. PersonnummerSet is merely a struct of ints that I’ve created in a header file, so that it can be referenced by other libraries (either by direct assignment to type or pointer). StringMagic is another header file that uses std::string.erase/std::remove to remove the ‘-‘ character from the input (Swedish Personnummers are always written as YYMMDD-SSSC.)

#include <cstring> // Replacing the old and busted with the new hotness.
#include <iomanip>
#include <iostream>
#include <cstdio> // Replacing the old and busted with the new hotness.
#include "Personnummerset.h"
#include "StringMagic.h"

class Personnummer
{
public:
    /**
     *  The PersonNumber is a property of type PersonnnummerSet, which is used to process the digits
     *  from the personnummer provided.
     */
    PersonnummerSet PersonNumber {};

    /**
     *  Initializes a new instance of the <see cref="Personnummer" /> class.
     * @param number - The converted long from the user's input.
     */
    explicit Personnummer(long number)
    {
        // We separate the three digit serial to future-proof for deriving sex of the individual in future checks.
        this->PersonNumber.Year = static_cast<int>(number / 100000000 % 100);   // First 2 integers     (0&1)
        this->PersonNumber.Month = static_cast<int>(number / 1000000 % 100);    // Second 2 integers    (2&3)
        this->PersonNumber.Day = static_cast<int>(number / 10000 % 100);        // Third 2 integers     (4&5)
        this->PersonNumber.SerialNumber = static_cast<int>(number / 100 % 100); // Fourth 2 integers    (6&7)
        this->PersonNumber.Sex = static_cast<int>(number / 10 % 10);            // First 1 integer      (8)
        this->PersonNumber.CheckSum = static_cast<int>(number % 10);            // Second 1 integer     (9)
    }

public:
    /**
     *  Generates the Luhn Algorithm checksum and compares that from the checksum given from the user's input.
     * @return A boolean indicating of the calculated checksum matches the provided checksum.
     */
    bool ValidateCheckSum()
    {
        return this->PersonNumber.CheckSum == this->GenerateChecksum();
    }

private:
    /**
     * This is a variation of the Luhn Algorithm, which is used to generate the checksum from the
     * first nine digits of the personnummer. Each value in the first nine digits is multiplied by
     * either a 2 or a 1. See: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2773709/figure/Fig1/
    */
    int GenerateChecksum()
    {
        int firstCheck;
        int fifthCheck;
        int seventhCheck;
        int ninthCheck;
        int firstYear = PersonNumber.Year > 9 ? PersonNumber.Year / 10 % 10 : 0;
        int secondYear = PersonNumber.Year%10;
        int firstMonth = PersonNumber.Month > 9 ? PersonNumber.Month / 10 % 10 : 0;
        int secondMonth = PersonNumber.Month%10;
        int firstDay = PersonNumber.Day > 9 ? PersonNumber.Day / 10 % 10 : 0;
        int secondDay = PersonNumber.Day%10;
        int firstSerial = PersonNumber.SerialNumber/10%10;
        int secondSerial = PersonNumber.SerialNumber%10;

        int firstYearDigit = firstYear * 2;
        if (firstYearDigit > 9)
        {
            int firstSum = firstYearDigit/10%10;
            int secondSum = firstYearDigit%10;
            firstCheck = firstSum + secondSum;
        }
        else
        {
            firstCheck = firstYearDigit;
        }

        int secondCheck = secondYear * 1;
        int thirdCheck = firstMonth * 2;
        int fourthCheck = secondMonth * 1;
        int firstDayCheck = firstDay * 2;
        if(firstDayCheck > 9)
        {
            int firstSum = firstDayCheck/10%10;
            int secondSum = firstDayCheck%10;
            fifthCheck = firstSum + secondSum;
        }
        else
        {
            fifthCheck = firstDayCheck;
        }

        int sixthCheck = secondDay * 1;
        int firstDigitRandom = firstSerial * 2;
        if (firstDigitRandom > 9)
        {
            int firstSum = firstDigitRandom/10%10;
            int secondSum = firstDigitRandom%10;
            seventhCheck = firstSum + secondSum;
        }
        else
        {
            seventhCheck = firstDigitRandom;
        }

        int eighthCheck = secondSerial * 1;
        int sexCheck = PersonNumber.Sex * 2;
        if(sexCheck > 9)
        {
            int firstSum = sexCheck/10%10;
            int secondSum = sexCheck%10;
            ninthCheck = firstSum + secondSum;
        }
        else
        {
            ninthCheck = sexCheck;
        }

        int sum = firstCheck + secondCheck + thirdCheck + fourthCheck + fifthCheck + sixthCheck + seventhCheck + eighthCheck + ninthCheck;
        int lastOfSum = sum%10;
        int checkSum = 10 - lastOfSum;
        return checkSum;

    }
};

int main()
{
    std::string user_input;
    std::cout << "Enter Personnummer (YYMMDD-SSSC): " << std::endl;
    std::cin >> user_input;

    // Necessary or the long conversion treats '-' or '+' as a delimiter.
    // NOTE: People aged over 99 will always have '+' in their personnummer.
    if(user_input.find('-') != std::string::npos)
    {
        StringMagic::RemoveDashFromString(user_input);
    }
    else if (user_input.find('+') != std::string::npos)
    {
        StringMagic::RemovePlusFromString(user_input);
    }

    // Smart-pointers are the future...
    std::unique_ptr<Personnummer> personNumber (new Personnummer(std::stol(user_input)));
    std::cout << std::boolalpha;
    std::cout << "CheckSum Passes: " << personNumber->ValidateCheckSum() << std::endl;

    personNumber.reset();
}

The above code can be used to validate almost any personnummer – save for those individuals whom are over 99 years of age, as the separator changes from ‘-‘ to ‘+’.

…and that’s about the extent of fun with Swedish Personnummers in C++ that this post will cover.

Thanks for coming to this NERDTalk™ and happy programming!

Jag älskar Östergötland!

O.k., so there’s a long and sorted history about moving to Sweden that I don’t really want to go into in this post. All I can say is that I was hired back in March and the visa application still hasn’t been submitted, as of yet. Le sigh…

Anyways, I decided to take a trip to visit the team I’m joining and see my would-be home in person during it’s summer months – having recently been there during winter.

Linköping, itself, reminds me a lot of the biggest town in the area that I grew up in, with it’s parallelism in university and night-life. Norrköping reminds me of the smaller town in the area that I grew up in, as well. They’re nowhere near the same, don’t get me wrong, but there’s semblances that are familiar and – in that effect – like being home, to some degree.

First things, first, though: On the way to Linköping, I discovered that Amsterdam has a take a book, leave a book library within it. Can I just say that I ♥ that Amsterdam does this?

In Linköping, the hotel I stayed at, Park Hotel i Fawlty Towers, was amazeballs. Amaze. Balls. I liken it to Michabelle Inn (also in the area that I grew up in) but Park Hotel is so much “better” for a variety of reasons, the staff and the location being the principal reasons. The Park Hotel is in a building constructed in the 1880’s and is across the street from Linköping’s Resecentrum and Central Station.








Yes, I did try to play the piano a few times but, sadly, it was out of tune – not that it was an inherently bad thing. I think the only “negative” aspect of staying at the Park Hotel, if I had to name but one, was that the old-timey phone didn’t work. If it did, I’d have been in heaven.

Also, shout-out to the fabulously awesome Hannele for being… …well, so fabulously awesome!

Now, it’s important to note that the day that I landed, almost everything was empty and/or closed. Why is that you might ask? Was everyone off on their summer holidays, already? Nope. I straight-up landed on a football (soccer, for my American friends) play-off day for the World Cup (VM-finalen) and Sweden had just won against Switzerland.



The first thing to do, the next day, was to go off to the future work site and see everyone. I can’t show you any photos of the work site, itself, but I can show you some photos from within the building.





The first weekend, I decided I needed to properly check out Norrköping. So, it was off to the train I went and about a twenty minute ride later, I was I at my destination. It has to be said that the countryside in Östergötland is absolutely beautiful.




The next weekend, I walked around Linköping for quite a long time (over 16k steps, if I recall correctly). One of the first stops was Trädgårdsförenningen, which is a public park/garden that is absolutely brilliant and worth the walk around, if you ever get the chance.






Also, whilst traipsing around the city, I found the local library. As far as town libraries go, it’s pretty impressive.






…and got a library card. Yes, I am a nerd. I prefer to be one, thank you very much. 🙂

Even though I’m the furtherest from religious as one could possibly get, I have to check out churches in the areas I visit, namely for the appreciation of the sheer age of some of them and the items that they contain. And, so, Linköping Cathedral was naturally my next stop.















And, of course, I had to visit the Art of the Brick exhibit. 🙂











Oh, you wanted MOAR miscellaneous photos that I took while I was there? Well, why didn’t you say so!

O.k., I think I’ve pictured you out, maybe? The sadder part is there’s a lot of photos that failed to upload; so, there’s a lot that didn’t make it to this post. Very much sad face with the internets that are not currently agreeing with the uploading and what-nots.

All of that aside, I really love the Östergötland area and will – hopefully – be able to move there sometime soon. I’m still teetering as to whether Linköping or Norrköping would be more worthwhile to move to but I think someone *cough* Hannele *cough* may have ultimately influenced my decision. Time’s still ticking away, though, so there’s no emphatic need to make a decision as to which to move to, just yet. What I can tell you is that I’ve definitively ruled-out Linghem as one of the options, fairly easily. 🙂

Until next time… …whenever that may be.