Tell me more ×
Mathematics Stack Exchange is a question and answer site for people studying math at any level and professionals in related fields. It's 100% free, no registration required.

Ok so my maths maybe not so good, but here is my question

So I am using the following

<?php
function LuhnCalc($number) {
      $chars = array_reverse(str_split($number, 1));
      $odd = array_intersect_key($chars, array_fill_keys(range(1, count($chars), 2), null));
      $even = array_intersect_key($chars, array_fill_keys(range(0, count($chars), 2), null));
      $even = array_map(function($n) { return ($n >= 5)?2 * $n - 9:2 * $n; }, $even);
      $total = array_sum($odd) + array_sum($even);
      return ((floor($total / 10) + 1) * 10 - $total) % 10;
    }
    print LuhnCalc($_GET['num']);
?>

however it seems that BPAY which is version 5 of MOD 10 which for the record I cant find what the documentation for. seems to not be the same as MOD10

the following numbers where tested 2005, 1597, 3651, 0584, 9675

bPAY

2005 = 20052
1597 = 15976
3651 = 36514
0584 = 05840
9675 = 96752

MY CODE

2005 = 20057 
1597 = 15974 
3651 = 36517 
0584 = 05843 
9675 = 96752

as you can see none, of them match the BPAY numbers

share|improve this question
1  
Could you clarify what your question is - are you asking why two sets of numbers don't come out the same? Should we interpret your tables as having inputs in the left column and outputs in the right? What does your function actually do - for those of us who don't know PHP code - and what is it supposed to do (I'm guessing this)? Also, modules are an algebraic structure in mathematics, and are not really related to modular arithmetic despite the name. – anon Jun 21 '12 at 0:42
(Also posted on SO one week ago: stackoverflow.com/questions/11024309/…) – anon Jun 21 '12 at 0:42
Yes it was posted and was suggested to post it on here, yes I do need the numbers to match and I need to know how to make them match – RussellHarrower Jun 21 '12 at 1:49
If you want to make this a math question and you can generate more checksums yourself, you should generate many more checksums (and if possible related together, e.g. 2004,2005,2006,2014,2015,2016,2105,3005,1005,...). As it is there is definitely not enough data to work with. – Generic Human Jun 23 '12 at 14:48

closed as off topic by Will Jagy, sdcvvc, t.b., John Wordsworth, William Aug 29 '12 at 21:57

Questions on Mathematics Stack Exchange are expected to relate to math within the scope defined in the FAQ. Consider editing the question or leaving comments for improvement if you believe the question can be reworded to fit within the scope. Read more about closed questions here.

2 Answers

Your code is a correct, if somewhat cumbersome, implementation of the Luhn check digit algorithm.

However, as described by Nick Adams' answer to your cross-post of this question on Stack Overflow, the check digits used by BPay are not calculated using Luhn's method.

Instead, what they appear to be using is a weighted sum modulo 10, with the weight of each digit given by its position in the number, starting at 1 for the leftmost digit and counting up. That is, if the digits of the original number are $a_1 a_2 \dots a_n$, the check digit will be $$c = (1 \cdot a_1 + 2 \cdot a_2 + \dotsb + n \cdot a_n) \bmod 10.$$

Here's one way to calculate this check digit in PHP code (which should give the same results as Nick Adams' code):

function BPayCheckDigit ($number) {
    	$n = strlen($number);
    	$sum = 0;
    	for ($i = 0; $i < $n; $i++) {
    		$sum += ($i + 1) * $number{$i};
    	}
    	return $sum % 10;
}

By the way, this check digit formula has a number of weaknesses compared to Luhn's method:

  • Since the weights are counted from the left, the presence or absence of leading zeros affects the checksum. Thus, you need to make sure that your numbers are actually stored and manipulated as strings, or pad them to the correct length before the checksum calculation.

  • Unlike in the Luhn method, verifying the checksum requires treating the check digit separately from the other digits, rather than just including it in the calculation and checking that the result comes out zero. (That is, unless the length of the numbers just happens to be nine digits including the check digit, in which case the ninth digit is assigned the weight $9 \equiv -1 \bmod 10$ and the match does work out right.)

  • For even-numbered digits, this checksum cannot detect the addition or subtraction of 5 from the digit. For digits whose weight is a multiple of 5, the checksum cannot detect the addition or subtraction of any even number. In particular, digits whose weight is a multiple of 10 are not checked at all (although I believe the checksum is not intended for numbers that long anyway)!

share|improve this answer

For me the obvious oddity here is in the two range declarations. It looks like you want to produce one array of odd and and one array of even digits to intersect against. So you will want [1,3,5,7,9] and [0,2,4,6,8]. Instead you are producing only [1,3] and [0,2,4] for the range is limited by 4=count($chars) both times.

So I suspect what you want is

range(1, 9, 2)

and

range(0, 8, 2)

respectively.

EDIT: I did not run the code but in my head and even there couldn't come up with your final digits. As was said in the comments, you may need to clarify what you want to do so people can help you

share|improve this answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.