Luhn의 알고리즘 - 신용 카드 확인 - GO

17063 단어 gocomputerscience
저장소 확인
repo

설명은 HarvardX의 CS50 과정에서 가져왔으며 GO의 알고리즘은 제 접근 방식입니다. 그것은 단지 수학을 사용합니다.

GO에서 신용 카드를 확인하기 위한 IBM의 Hans Peter Luhn 알고리즘
물론 신용(또는 직불) 카드는 상품 및 서비스 비용을 지불할 수 있는 플라스틱 카드입니다. 그 카드에 인쇄된 번호는 데이터베이스 어딘가에 저장되어 있으므로 카드를 사용하여 무언가를 구매할 때 채권자는 누구에게 청구할지 알 수 있습니다. 이 세상에는 신용카드를 사용하는 사람들이 많기 때문에 그 숫자가 꽤 ​​깁니다. American Express는 15자리 숫자를 사용하고 MasterCard는 16자리 숫자를 사용하며 Visa는 13자리 및 16자리 숫자를 사용합니다. 그리고 그것들은 이진수가 아닌 10진수(0부터 9까지)입니다. 예를 들어 American Express는 10^15 = 1,000,000,000,000,000개의 고유한 카드를 인쇄할 수 있습니다. (그건, 음, 천조입니다.)

사실, 그것은 약간 과장입니다. 왜냐하면 신용 카드 번호에는 실제로 어떤 구조가 있기 때문입니다. 모든 American Express 번호는 34 또는 37로 시작합니다. 대부분의 마스터 카드 번호는 51, 52, 53, 54 또는 55로 시작합니다(이 문제와 관련하여 관심을 두지 않을 다른 잠재적인 시작 번호도 있음). 모든 Visa 번호는 4로 시작합니다. 그러나 신용 카드 번호에는 적어도 하나의 번호와 다른 번호 사이의 수학적 관계인 "체크섬"이 내장되어 있습니다. 이 체크섬을 사용하면 컴퓨터(또는 수학을 좋아하는 사람)가 데이터베이스를 쿼리할 필요 없이 느릴 수 있는 사기 숫자가 아닐지라도 오타(예: 전치)를 감지할 수 있습니다. 물론 부정직한 수학자도 수학적 제약을 존중하는 가짜 숫자를 확실히 만들 수 있으므로 더 엄격한 검사를 위해서는 데이터베이스 조회가 여전히 필요합니다.
Luhn의 알고리즘

그래서 비밀 공식은 무엇입니까? 대부분의 카드는 IBM의 Hans Peter Luhn이 발명한 알고리즘을 사용합니다. Luhn의 알고리즘에 따르면 다음과 같이 신용 카드 번호가 (구문적으로) 유효한지 확인할 수 있습니다.

Multiply every other digit by 2, starting with the number’s second-to-last digit, and then add those products’ digits together.
Add the sum to the sum of the digits that weren’t multiplied by 2.
If the total’s last digit is 0 (or, put more formally, if the total modulo 10 is congruent to 0), the number is valid!

다소 혼란스럽기 때문에 David's Visa: 4003600000000014를 예로 들어 보겠습니다.

For the sake of discussion, let’s first underline every other digit, starting with the number’s second-to-last digit:

4003600000000014

Okay, let’s multiply each of the underlined digits by 2:

1•2 + 0•2 + 0•2 + 0•2 + 0•2 + 6•2 + 0•2 + 4•2

That gives us:

2 + 0 + 0 + 0 + 0 + 12 + 0 + 8

Now let’s add those products’ digits (i.e., not the products themselves) together:

2 + 0 + 0 + 0 + 0 + 1 + 2 + 0 + 8 = 13

Now let’s add that sum (13) to the sum of the digits that weren’t multiplied by 2 (starting from the end):

13 + 4 + 0 + 0 + 0 + 0 + 0 + 3 + 0 = 20

Yup, the last digit in that sum (20) is a 0, so David’s card is legit!

따라서 신용 카드 번호를 확인하는 것은 어렵지 않지만 손으로 ​​하는 일은 다소 지루합니다.

package main

import (
    "fmt"
    "strconv"
)

// 4003600000000014 - VISA
// it doesn't use arrays or struct
// pure mathematic solution

func main() {
    // get card number
    var cardNumber int = -1
    for cardNumber == -1 {
        cardNumber = getCardNumer()
    }

    // get the number of digits from the card
    numDigits := getNumberDigitsCard(cardNumber)

    // AUX VARIABLES ---------------------------
    // aux vars for iterate through the card number
    mod := 10
    divider := 1
    // aux for know the ieration, because it goes from right to left
    var generalOdd bool = (numDigits % 2) != 0
    // aux var for iterate one yes - one no
    odd := generalOdd
    // accumulators
    ac1 := 0 // special - the one that will be multiple by 2
    ac2 := 0 // odds - start from the second digit

    // ITERATE CARD NUMBER
    for cardNumber > divider {

        // get the digit from the right
        var currentVal int = (cardNumber % mod) / divider

        // move one digit to the left
        mod = mod * 10
        divider = divider * 10

        // LOGIC FROM Hans Peter Luhn ALGORITHM
        // make the sum step from digits
        if odd {
            if !generalOdd {
                ac1 = ac1 + specialSum(currentVal)
            } else {
                ac1 = ac1 + currentVal
            }
        } else {
            if generalOdd {
                ac2 = ac2 + specialSum(currentVal)
            } else {
                ac2 = ac2 + currentVal
            }
        }
        odd = !odd
    }
    var result int = ac1 + ac2

    // CHECK THE RESULT
    // compare the info given from the credit cards
    var cardType string = checkResult(result, numDigits, cardNumber)
    fmt.Println(cardType)
}

func getCardNumer() int {
    // get the value
    var str string = ""
    fmt.Print("Enter a card number: ")
    fmt.Scanf("%s", &str)

    // convert value
    cardNumber, err := strconv.Atoi(str)

    // handle error if no number was provided
    if err != nil {
        fmt.Println("Enter only numbers")
        return -1
    }

    return cardNumber
}

func getNumberDigitsCard(card int) (numDigits int) {
    divider := 10
    // because is an int, will delete the decimals from each division
    for card != 0 {
        card = card / divider
        numDigits += 1
    }
    return
}

// SPECIAL SUM
// because the log says if multiple by 2 is equal to a number with two digits
// we should sum the two digits from the number
func specialSum(num int) int {
    if num < 5 {
        return num * 2
    } else {
        num = num * 2
        var n1 int = num % 10
        var n2 int = num / 10
        return n1 + n2
    }
}

// CHECK THE RESULT
// compare the info given from the credit cards
func checkResult(result, numDigits, cardNumber int) string {
    if (result % 10) == 0 {
        var divisor int = 1
        for i := 0; i < numDigits-2; i++ {
            divisor = 10 * divisor
        }
        var firstDigits int = cardNumber / divisor
        var firstDigit = firstDigits / 10
        if firstDigits == 34 || firstDigits == 37 {
            if numDigits == 15 {
                return "AMEX"
            } else {
                return "INVALID"
            }
        } else if firstDigits == 51 || firstDigits == 52 || firstDigits == 53 || firstDigits == 54 || firstDigits == 55 {
            if numDigits == 16 {
                return "MASTERCARD"
            } else {
                return "INVALID"
            }
        } else if firstDigit == 4 {
            if numDigits == 13 || numDigits == 16 {
                return "VISA"
            } else {
                return "INVALID"
            }
        }
    }
    return "INVALID"
}

좋은 웹페이지 즐겨찾기