MOD10
Kildeløs: Denne artikkelen mangler kildehenvisninger, og opplysningene i den kan dermed være vanskelige å verifisere. Kildeløst materiale kan bli fjernet. Helt uten kilder. (10. okt. 2015) |
MOD10 er forkortelse for Modulus 10-algoritmen, også kalt Luhn-algoritmen etter oppfinneren Hans Peter Luhn. Modulus-10 algoritmen benyttes blant annet som beregningsmetode for et kontrollsiffer i KID-numre på bankenes innbetalingsblanketter.
Et tenkt KID-nummer er 2345676. Det siste sifferet i KID-nummeret er et kontrollsiffer. I eksempelet over er dette sifferet 6. KID-nummeret uten kontrollsiffer er 234567.
Beregning av kontrollsiffer med Modulus 10-algoritmen
[rediger | rediger kilde]Hvert siffer i eksempelet over multipliseres med vekttallene 2, 1, 2, 1 osv., regnet fra høyre mot venstre.
- 7 × 2 = 14 ; 1 + 4 = 5
- 6 × 1 = 6
- 5 × 2 = 10 ; 1 + 0 = 1
- 4 × 1 = 4
- 3 × 2 = 6
- 2 × 1 = 2
Tverrsummen er 5 + 6 + 1 + 4 + 6 + 2 = 24.
I Modulus10 adderer man ikke produktene, men de enkelte siffer i produktene. Produktet 14 gir altså bidraget 1 + 4 til tverrsummen. Entallsifferet i tverrsummen (i dette tilfellet 4 [resultatet av (24 % 10)]) trekkes fra 10 og resultatet blir kontrollsifferet (i dette tilfellet 6). Dersom resultatet av dette blir 10, blir kontrollsifferet 0.
- 10 – 4 = kontrollsifferet 6
Komplett og gyldig KID-nummer i dette eksempelet er derfor 2345676.
Bakgrunn
[rediger | rediger kilde]Kontrollsifferet skal avdekke om det er gjort inntastingsfeil eller feil ved OCR-lesing. Denne algoritmen er best på å avdekke gale enkeltsifre, da ett enkelt siffer feil alltid vil gi et annet kontrollsiffer. Dersom flere sifre er feil, vil sjansene øke for at kontrollsifferet regnes ut til det samme og at feilen ikke oppdages. Om en tilfeldig tallrekke kontrolleres, er sjansen 10 % for at siste siffer stemmer med kontrollsiffer-algoritmen.
Denne algoritmen er også designet til å avdekke en ting til: Dersom to siffer har byttet plass, vil kontrollsifferet bli et annet. Derfor brukes vekttallene 21212121.. og så videre Denne typen feil er det noe økt sjanse for ved inntasting av lange KID-nummer.
Når det gjelder KID-nummer, kontrolleres også antall siffer det skal være, slik at et ekstra siffer eller et siffer for lite også gir feil KID.
Dersom et feil KID-nummer skulle slippe gjennom, er det to muligheter for mottakeren: Enten er KID-nummeret et annet gyldig nummer som er utstedt på en annen faktura, slik at betalingen knyttes til feil kunde, noe som kan være vanskelig å oppdage, og kan resultere i feil tilbakebetalinger. Den andre muligheten er at KID-nummeret ikke er tatt i bruk eller er en ugyldig KID. Dette vil mottakeren kunne avdekke, og vil kunne kontrollere nærmere hvem som har betalt manuelt. Jo kortere KID-nummer som benyttes (relativt til antall gyldige fakturaer), jo mer sannsynlig er det at feil som slipper gjennom resulterer i et annet benyttet nummer.
Lange KID-nummer som inneholder både kundenummer og fakturanummer regnes som meget sikre, siden feil i den ene eller den andre delen nesten alltid vil kunne oppdages. At feil i begge delene tilfeldigvis matcher en annens kundenummer/fakturanummer-kombinasjon er svært usannsynlig.
Implementasjoner i forskjellige programmeringspråk
[rediger | rediger kilde]PHP
[rediger | rediger kilde]$kid_u = "180986";
$kontrollsiffer = mod10($kid_u);
echo $kid_u . $kontrollsiffer;
function mod10($kid_u) {
$siffer = str_split(strrev($kid_u));
$sum = 0;
for($i = 0; $i < count($siffer); ++$i)
$sum += ( $i & 1 ) ? $siffer[$i] : tverrsum($siffer[$i] * 2);
$sum = (($sum == 0) ? 0 : 10 - substr($sum, -1));
if($sum == 10)
$sum=0;
return $sum;
}
function tverrsum($tall) {
return array_sum(str_split($tall));
}
Python
[rediger | rediger kilde]def mod10(kidnummer:int) -> int:
tverrsum = 0
faktor = 2
# Gå gjennom tallene i KID-nummeret i motsatt rekkefølge
for siffer in reversed(str(kidnummer)):
# Legg til bidraget av siffer ganget med faktor i tverrsummen
tverrsum += sum(int(j) for j in str(int(siffer) * faktor))
# Regn ut ny faktor. Rekkefølgen er 2, 1, 2, 1, 2, 1, ...
faktor = faktor % 2 + 1
return (10 - tverrsum % 10) % 10
Haskell
[rediger | rediger kilde]kid10 :: [Int] -> [Int]
kid10 nr = nr ++ [ctrl $ sum (map tv2 multi)]
where tv2 t = t `div` 10 + t `mod` 10
multi = zipWith (*) (reverse nr) (cycle [2,1])
ctrl k = (10 - (k `mod` 10)) `mod` 10
C#
[rediger | rediger kilde]//USAGE: Mod10("502114008060") --> 8. The controlnumber is 8.
public static int Mod10(string kid)
{
bool isOne = false;
int controlNumber = 0;
foreach (char number in kid.Reverse())
{
var intNumber = Int32.Parse(number.ToString());
var sum = isOne ? intNumber : 2 * intNumber;
if (sum > 9)
{
sum = (sum%10) + 1;
}
isOne = !isOne;
controlNumber += sum;
}
return (10 - (controlNumber % 10)) % 10 == 0 ? 0 : 10 - (controlNumber % 10) ;
}
Kotlin
[rediger | rediger kilde]fun validMod10(cid: String): Boolean {
return cid.toBigIntegerOrNull()?.let {
var checksum: Int = 0
for (i in cid.length - 1 downTo 0 step 2) {
checksum += cid[i] - '0'
}
for (i in cid.length - 2 downTo 0 step 2) {
val n: Int = (cid[i] - '0') * 2
checksum += if (n > 9) n - 9 else n
}
return checksum%10 == 0
} ?: false
}
Matlab
[rediger | rediger kilde]function checkNum = mod10CheckSum(num)
if length(num) == 1
numVec = fliplr(num2vec(num));
else
numVec = fliplr(num);
end
mult = 2.*ones(1,length(numVec));
mult(2:2:length(numVec)) = mult(2:2:length(numVec)) ./ 2;
sumOfProd = sum( numVec .* mult );
checkNum = mod( 10 - mod( sumOfProd,10 ) , 10 );
end % mod10CheckSum
%-------------------------------------------------------
function vec = num2vec(num)
% Hvis du ikke har laget en slik funksjon fra før av. Gjør om tall til vektor
maxPow = length(num2str(num));
vec = zeros(1,maxPow);
pow = maxPow - 1;
for i = 1:maxPow
vec(i) = floor( num/(10^pow) );
num = num - vec(i)*10^pow;
pow = pow - 1;
end
end % num2vec
Javascript
[rediger | rediger kilde]/* luhn 10 aka MOD10
* @v : input number as string
* @check : [true | false] Whether or not to get or check
* the given number. Default false
* @debug : [true | false] Print debug information. Default false
*
* Return boolean if check, else check digit.
* ****************************************************************/
function luhn10 (v, check, debug) {
let r, i,
a = v.replace(/[^\d]/g, '').split(''),
s = 0,
m = check ? 1 : 0
;
for (i = a.length - 1; i >= 0; --i) {
if ((m ^= 1))
if ((a[i] *= 2) > 9)
a[i] -= 9;
s += +a[i];
}
if ((r = (10 - s % 10)) === 10)
r = 0;
if (debug) {
console.log(
`${v} => ${s} % 10 -> ${r} `,
`${check ? (r === 0 ? 'OK' : 'BAD') : ''}`
);
}
return check ? r === 0 : r;
}
// Example:
// get check digit
result = luhn10 ('62512482');
// check value
result = luhn10 ('625124821', true);