Wolfram Computation Meets Knowledge

Mathematica Q&A: Computing Freight-Container Check Digits

Got questions about Mathematica? The Wolfram Blog has answers! We’ll regularly answer selected questions from users around the web. You can submit your question directly to the Q&A Team using this form.

This week’s question comes from Adri, an engineer:

How can I calculate the check digit in freight container codes like MSKU3881107?

We had to start with some quick research for this question: it turns out that freight (shipping) container identification is covered by the ISO 6346 standard (Wikipedia). Under ISO 6346, each container is labeled with an 11-digit code (four letters + seven numerals) in which the last digit is a “check” digit that is computed from the other 10 digits, according to a fixed rule. For example, in MSKU3881107, the final “7” is the check digit.

The rule specified by ISO 6346 for computing the check digit is designed so most accidental changes or misreadings of a single digit in a code will also change the check digit. This means you can use the check digit to catch most such errors; whenever you see a code, you calculate the check digit yourself and see if it matches up with the one in the code.

The calculation of the check digit can be described in three steps. In the first step, the four letters are replaced with corresponding numbers. The letters A through Z correspond to the numbers 10 through 38, with all multiples of 11 skipped:

Replacing the letters with corresponding numbers

Letters → Numbers

Here are the first 10 Characters of the code “MSKU3881107”:

Take[Characters["MSKU3881107”], 10] // InputForm

{"M", "S", "K", "U", "3", "8", "8", "1", "1", "0'"}

Applying the replacement rules above, you get these 10 numbers:

Take[Characters[

{24, 30, 21, 32, 3, 8, 8, 1, 1, 0}

(ToExpression converts text characters like “3” into numbers like 3.)

In the second step, the 10 numbers are multiplied by successive powers of two and added together. Here are the successive powers of two:

2^Range[0, 9]

{1, 2, 4, 8, 16, 32, 64, 128, 256, 512}

The multiplication followed by addition is simply a Dot product:

Dot[{24, 30, 21, 32, 3, 8, 8, 1, 1, 0}, 2^Range[0, 9]]

1624

In the third step, you take the remainder when dividing by 11, and if the result is 10, it is taken to be zero (though by convention, codes that give either zero or 10 are not normally used). The final result is the check digit:

Mod[1624, 11]

7

As you can see, this check digit agrees with the last digit of the original freight code MSKU3881107.

You might as well wrap this up into a function. Here’s one that supports two different interfaces. The first version accepts a list of numbers like {24, 30, 21, 32, 3, 8, 8, 1, 1, 0} and applies steps 2 and 3:

FreightCodeCheckDigit[nums_List] := Mod[Dot[nums, 2^Range[0, 9]], 11]

The second version accepts a text string like “PONU2079674” and applies step 1, then simply calls the first version to apply steps 2 and 3:

FreightCodeCheckDigit[s_String] /; 10 ≤ StringLength [s] ≤ 11 := FreightCodeCheckDigit[ToExpression[Take[Characters[s], 10] /. letterRules]]

Note that, by means of a Condition (/;), the string s is allowed to have either 10 digits (for a code without a check digit) or 11 digits (for a code that already includes a check digit). The result is the same either way:

{FreightCodeCheckDigit["PONU207967"], FreightCodeCheckDigit["PONU2079674"]}

{4, 4}

Here’s a related function that checks whether a freight code has the correct check digit:

Checking whether a freight code has the correct check digit

Test a few freight codes:

Map[ValidFreightCodeQ, {"PONU2079674", "PONU2079675", "XONU2079674", "ABCD123456"}]

{True, False, False, False}

This answers the original question. It’s interesting to investigate how well the check digit works at detecting small errors in container codes.

Suppose you change the nth digit in a container code from a to a different value b. The contribution (modulo 11) of the nth digit to the value of the check digit changes from Mod[a 2^n, 11] to Mod[b 2^n, 11]. The contribution of all the other digits stays the same.

You can use the function FindInstance to check whether there are any possible values of a, b, and n such that Mod[a 2^n, 11] == Mod[b2^n, 11]. For numerical digits you can assume 0 ≤ a ≤ 9, 0 ≤ b ≤ 9, and 4 ≤ n ≤ 9 , and you get:

FindInstance[{0≤a≤9, 0≤b≤9, 4≤n≤9, a≠b, Mod[a2^n, 11] == Mod[b2^n, 11]}, {a, b, n}, Integers]

{}

This means that a change to any single numerical digit is guaranteed to change the check digit.

What about the four letters? Here you can assume 10 ≤ a ≤ 38, Mod[a, 11] ≠ 0, 10 ≤ b ≤ 38, Mod[b, 11] ≠ 0, and 0 ≤ n ≤ 3, and you get:

FindInstance[{10≤a≤38, Mod[a, 11]≠ 0, 10≤b≤38, Mod[b, 11]≠0, 0≤n≤3, a≠b, Mod[a2^n, 11] ==Mod[b2^n, 11]}, {a,b,n}, Integers]

{{a → 10, b → 21, n → 0}}

This means that the check digit can sometimes fail to detect a change to one of the four letters in the container code. For example, these two codes differ by one letter despite having the same check digit:

{FreightCodeCheckDigit["ABCU123123"], FreightCodeCheckDigit["KBCU123123"]}

{7, 7}

The only changes to one of the four letters that will “fool” the check digit are those that, according to letterRules above, differ exactly by a multiple of 11, such as “A” → 10 and “K” → 21. This means most accidental changes to a single letter will still be caught.

Another possible accidental change would be swapping exactly two of the numeric digits in a code—something like “ABCD123456” → “ABCD623451”. Can you work out whether a change like this can ever fool the check digit? What about if codes with check digits of 0 (or 10) are allowed?

If you have a question you’d like answered in this blog, you can submit it to the Q&A Team using this form. For daily bite-sized Mathematica tips, follow our @MathematicaTip Twitter feed (or follow using RSS).

Click here to download this post as a Computable Document Format (CDF) file.

Comments

Join the discussion

!Please enter your comment (at least 5 characters).

!Please enter your name.

!Please enter a valid email address.

5 comments

  1. Couple comments: Typically one looks at the two main types of errors: single-digit errors (which you examined) and transposition errors (…xy… -> …yx…).

    When working in base 10 there is a remarkable method (based on the group of symmetries of the pentagon) that catches ALL single-digit errors and ALL transposition errors. That is discussed in Chapter 16 of my book Mathematica in Action.

    Another intriguing topic is the addition of check-digits that not only catch errors, but also CORRECT them. Such codes (with two check-digits) are (sometimes) possible.

    Stan Wagon

    Reply
  2. Very cool! Thanks for sharing the insight!

    Reply
  3. information on the fit is good enough to increase my knowledge further

    Reply
  4. Thanks for the answer, I have been studying it for years, I found the modulo 11 function but not the powers of 2 part.
    Nice to see you use a check on a container number from the company where I have been working 25 years. Maybe I have seen it once!

    Reply
  5. I truly appreciate the computation being made here. It was also my problem to determine the ability of the check digit to work in detecting some container code errors. I have been studying the formula for a while now but I just learned how the check digit is impacted by a change in the numerical digit.

    Reply