I tried to check the validation of credit card using Luhn algorithm, which works as the following steps:
Double every second digit from right to left. If doubling of a digit results in a two-digit number, add up the two digits to get a single-digit number.
2 * 2 = 4
2 * 2 = 4
4 * 2 = 8
1 * 2 = 2
6 * 2 = 12 (1 + 2 = 3)
5 * 2 = 10 (1 + 0 = 1)
8 * 2 = 16 (1 + 6 = 7)
4 * 2 = 8
Now add all single-digit numbers from Step 1.
4 + 4 + 8 + 2 + 3 + 1 + 7 + 8 = 37
Add all digits in the odd places from right to left in the card number.
6 + 6 + 0 + 8 + 0 + 7 + 8 + 3 = 38
Sum the results from Step 2 and Step 3.
37 + 38 = 75
If the result from Step 4 is divisible by 10, the card number is valid; otherwise, it is invalid. For example, the number 4388576018402626 is invalid, but the number 4388576018410707 is valid.
Simply, my program always displays valid for everything that I input. Even if it's a valid number and the result of sumOfOddPlace and sumOfDoubleEvenPlace methods are equal to zero. Any help is appreciated.
import java.util.Scanner;
public class CreditCardValidation {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int count = 0;
long array[] = new long [16];
do
{
count = 0;
array = new long [16];
System.out.print("Enter your Credit Card Number : ");
long number = in.nextLong();
for (int i = 0; number != 0; i++) {
array[i] = number % 10;
number = number / 10;
count++;
}
}
while(count < 13);
if ((array[count - 1] == 4) || (array[count - 1] == 5) || (array[count - 1] == 3 && array[count - 2] == 7)){
if (isValid(array) == true) {
System.out.println("\n The Credit Card Number is Valid. ");
} else {
System.out.println("\n The Credit Card Number is Invalid. ");
}
} else{
System.out.println("\n The Credit Card Number is Invalid. ");
}
}
public static boolean isValid(long[] array) {
int total = sumOfDoubleEvenPlace(array) + sumOfOddPlace(array);
if ((total % 10 == 0)) {
for (int i=0; i< array.length; i++){
System.out.println(array[i]);}
return true;
} else {
for (int i=0; i< array.length; i++){
System.out.println(array[i]);}
return false;
}
}
public static int getDigit(int number) {
if (number <= 9) {
return number;
} else {
int firstDigit = number % 10;
int secondDigit = (int) (number / 10);
return firstDigit + secondDigit;
}
}
public static int sumOfOddPlace(long[] array) {
int result = 0;
for (int i=0; i< array.length; i++)
{
while (array[i] > 0) {
result += (int) (array[i] % 10);
array[i] = array[i] / 100;
}}
System.out.println("\n The sum of odd place is " + result);
return result;
}
public static int sumOfDoubleEvenPlace(long[] array) {
int result = 0;
long temp = 0;
for (int i=0; i< array.length; i++){
while (array[i] > 0) {
temp = array[i] % 100;
result += getDigit((int) (temp / 10) * 2);
array[i] = array[i] / 100;
}
}
System.out.println("\n The sum of double even place is " + result);
return result;
}
}
You can freely import the following code:
public class Luhn
{
public static boolean Check(String ccNumber)
{
int sum = 0;
boolean alternate = false;
for (int i = ccNumber.length() - 1; i >= 0; i--)
{
int n = Integer.parseInt(ccNumber.substring(i, i + 1));
if (alternate)
{
n *= 2;
if (n > 9)
{
n = (n % 10) + 1;
}
}
sum += n;
alternate = !alternate;
}
return (sum % 10 == 0);
}
}
Link reference: https://github.com/jduke32/gnuc-credit-card-checker/blob/master/CCCheckerPro/src/com/gnuc/java/ccc/Luhn.java
Google and Wikipedia are your friends. Instead of long-array I would use int-array. On Wikipedia following java code is published (together with detailed explanation of Luhn algorithm):
public static boolean check(int[] digits) {
int sum = 0;
int length = digits.length;
for (int i = 0; i < length; i++) {
// get digits in reverse order
int digit = digits[length - i - 1];
// every 2nd number multiply with 2
if (i % 2 == 1) {
digit *= 2;
}
sum += digit > 9 ? digit - 9 : digit;
}
return sum % 10 == 0;
}
You should work on your input processing code. I suggest you to study following solution:
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
boolean repeat;
List<Integer> digits = new ArrayList<Integer>();
do {
repeat = false;
System.out.print("Enter your Credit Card Number : ");
String input = in.next();
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (c < '0' || c > '9') {
repeat = true;
digits.clear();
break;
} else {
digits.add(Integer.valueOf(c - '0'));
}
}
} while (repeat);
int[] array = new int[digits.size()];
for (int i = 0; i < array.length; i++) {
array[i] = Integer.valueOf(digits.get(i));
}
boolean valid = check(array);
System.out.println("Valid: " + valid);
}
I took a stab at this with Java 8:
public static boolean luhn(String cc) {
final boolean[] dbl = {false};
return cc
.chars()
.map(c -> Character.digit((char) c, 10))
.map(i -> ((dbl[0] = !dbl[0])) ? (((i*2)>9) ? (i*2)-9 : i*2) : i)
.sum() % 10 == 0;
}
Add the line
.replaceAll("\\s+", "")
Before
.chars()
If you want to handle whitespace.
Seems to produce identical results to
return LuhnCheckDigit.LUHN_CHECK_DIGIT.isValid(cc);
From Apache's commons-validator.
There are two ways to split up your int into List<Integer>
Use %10 as you are using and store it into a List
Convert to a String and then take the numeric values
Here are a couple of quick examples
public static void main(String[] args) throws Exception {
final int num = 12345;
final List<Integer> nums1 = splitInt(num);
final List<Integer> nums2 = splitString(num);
System.out.println(nums1);
System.out.println(nums2);
}
private static List<Integer> splitInt(int num) {
final List<Integer> ints = new ArrayList<>();
while (num > 0) {
ints.add(0, num % 10);
num /= 10;
}
return ints;
}
private static List<Integer> splitString(int num) {
final List<Integer> ints = new ArrayList<>();
for (final char c : Integer.toString(num).toCharArray()) {
ints.add(Character.getNumericValue(c));
}
return ints;
}
I'll use 5 digit card numbers for simplicity. Let's say your card number is 12345; if I read the code correctly, you store in array the individual digits:
array[] = {1, 2, 3, 4, 5}
Since you already have the digits, in sumOfOddPlace you should do something like
public static int sumOfOddPlace(long[] array) {
int result = 0;
for (int i = 1; i < array.length; i += 2) {
result += array[i];
}
return result;
}
And in sumOfDoubleEvenPlace:
public static int sumOfDoubleEvenPlace(long[] array) {
int result = 0;
for (int i = 0; i < array.length; i += 2) {
result += getDigit(2 * array[i]);
}
return result;
}
this is the luhn algorithm implementation which I use for only 16 digit Credit Card Number
if(ccnum.length()==16){
char[] c = ccnum.toCharArray();
int[] cint = new int[16];
for(int i=0;i<16;i++){
if(i%2==1){
cint[i] = Integer.parseInt(String.valueOf(c[i]))*2;
if(cint[i] >9)
cint[i]=1+cint[i]%10;
}
else
cint[i] = Integer.parseInt(String.valueOf(c[i]));
}
int sum=0;
for(int i=0;i<16;i++){
sum+=cint[i];
}
if(sum%10==0)
result.setText("Card is Valid");
else
result.setText("Card is Invalid");
}else
result.setText("Card is Invalid");
If you want to make it use on any number replace all 16 with your input number length.
It will work for Visa number given in the question.(I tested it)
Here's my implementation of the Luhn Formula.
/**
* Runs the Luhn Equation on a user inputed CCN, which in turn
* determines if it is a valid card number.
* #param c A user inputed CCN.
* #param cn The check number for the card.
* #return If the card is valid based on the Luhn Equation.
*/
public boolean luhn (String c, char cn)
{
String card = c;
String checkString = "" + cn;
int check = Integer.valueOf(checkString);
//Drop the last digit.
card = card.substring(0, ( card.length() - 1 ) );
//Reverse the digits.
String cardrev = new StringBuilder(card).reverse().toString();
//Store it in an int array.
char[] cardArray = cardrev.toCharArray();
int[] cardWorking = new int[cardArray.length];
int addedNumbers = 0;
for (int i = 0; i < cardArray.length; i++)
{
cardWorking[i] = Character.getNumericValue( cardArray[i] );
}
//Double odd positioned digits (which are really even in our case, since index starts at 0).
for (int j = 0; j < cardWorking.length; j++)
{
if ( (j % 2) == 0)
{
cardWorking[j] = cardWorking[j] * 2;
}
}
//Subtract 9 from digits larger than 9.
for (int k = 0; k < cardWorking.length; k++)
{
if (cardWorking[k] > 9)
{
cardWorking[k] = cardWorking[k] - 9;
}
}
//Add all the numbers together.
for (int l = 0; l < cardWorking.length; l++)
{
addedNumbers += cardWorking[l];
}
//Finally, check if the number we got from adding all the other numbers
//when divided by ten has a remainder equal to the check number.
if (addedNumbers % 10 == check)
{
return true;
}
else
{
return false;
}
}
I pass in the card as c which I get from a Scanner and store in card, and for cn I pass in checkNumber = card.charAt( (card.length() - 1) );.
Okay, this can be solved with a type conversions to string and some Java 8
stuff. Don't forget numbers and the characters representing numbers are not the same. '1' != 1
public static int[] longToIntArray(long cardNumber){
return Long.toString(cardNumber).chars()
.map(x -> x - '0') //converts char to int
.toArray(); //converts to int array
}
You can now use this method to perform the luhn algorithm:
public static int luhnCardValidator(int cardNumbers[]) {
int sum = 0, nxtDigit;
for (int i = 0; i<cardNumbers.length; i++) {
if (i % 2 == 0)
nxtDigit = (nxtDigit > 4) ? (nxtDigit * 2 - 10) + 1 : nxtDigit * 2;
sum += nxtDigit;
}
return (sum % 10);
}
private static int luhnAlgorithm(String number){
int n=0;
for(int i = 0; i<number.length(); i++){
int x = Integer.parseInt(""+number.charAt(i));
n += (x*Math.pow(2, i%2))%10;
if (x>=5 && i%2==1) n++;
}
return n%10;
}
public class Creditcard {
public static void main(String args[]){
Scanner sc=new Scanner(System.in);
String cardno = sc.nextLine();
if(checkType(cardno).equals("U")) //checking for unknown type
System.out.println("UNKNOWN");
else
checkValid(cardno); //validation
}
private static String checkType(String S)
{
int AM=Integer.parseInt(S.substring(0,2));
int D=Integer.parseInt(S.substring(0,4)),d=0;
for(int i=S.length()-1;i>=0;i--)
{
if(S.charAt(i)==' ')
continue;
else
d++;
}
if((AM==34 || AM==37) && d==15)
System.out.println("AMEX");
else if(D==6011 && d==16)
System.out.println("Discover");
else if(AM>=51 && AM<=55 && d==16)
System.out.println("MasterCard");
else if(((S.charAt(0)-'0')==4)&&(d==13 || d==16))
System.out.println("Visa");
else
return "U";
return "";
}
private static void checkValid(String S) // S--> cardno
{
int i,d=0,sum=0,card[]=new int[S.length()];
for(i=S.length()-1;i>=0;i--)
{
if(S.charAt(i)==' ')
continue;
else
card[d++]=S.charAt(i)-'0';
}
for(i=0;i<d;i++)
{
if(i%2!=0)
{
card[i]=card[i]*2;
if(card[i]>9)
sum+=digSum(card[i]);
else
sum+=card[i];
}
else
sum+=card[i];
}
if(sum%10==0)
System.out.println("Valid");
else
System.out.println("Invalid");
}
public static int digSum(int n)
{
int sum=0;
while(n>0)
{
sum+=n%10;
n/=10;
}
return sum;
}
}
Here is the implementation of Luhn algorithm.
public class LuhnAlgorithm {
/**
* Returns true if given card number is valid
*
* #param cardNum Card number
* #return true if card number is valid else false
*/
private static boolean checkLuhn(String cardNum) {
int cardlength = cardNum.length();
int evenSum = 0, oddSum = 0, sum;
for (int i = cardlength - 1; i >= 0; i--) {
System.out.println(cardNum.charAt(i));
int digit = Character.getNumericValue(cardNum.charAt(i));
if (i % 2 == 0) {
int multiplyByTwo = digit * 2;
if (multiplyByTwo > 9) {
/* Add two digits to handle cases that make two digits after doubling */
String mul = String.valueOf(multiplyByTwo);
multiplyByTwo = Character.getNumericValue(mul.charAt(0)) + Character.getNumericValue(mul.charAt(1));
}
evenSum += multiplyByTwo;
} else {
oddSum += digit;
}
}
sum = evenSum + oddSum;
if (sum % 10 == 0) {
System.out.println("valid card");
return true;
} else {
System.out.println("invalid card");
return false;
}
}
public static void main(String[] args) {
String cardNum = "4071690065031703";
System.out.println(checkLuhn(cardNum));
}
}
public class LuhnAlgorithm {
/**
* Returns true if given card number is valid
*
* #param cardNum Card number
* #return true if card number is valid else false
*/
private static boolean checkLuhn(String cardNum) {
int cardlength = cardNum.length();
int evenSum = 0, oddSum = 0, sum;
for (int i = cardlength - 1; i >= 0; i--) {
System.out.println(cardNum.charAt(i));
int digit = Character.getNumericValue(cardNum.charAt(i));
if (i % 2 == 0) {
int multiplyByTwo = digit * 2;
if (multiplyByTwo > 9) {
/* Add two digits to handle cases that make two digits after doubling */
String mul = String.valueOf(multiplyByTwo);
multiplyByTwo = Character.getNumericValue(mul.charAt(0)) + Character.getNumericValue(mul.charAt(1));
}
evenSum += multiplyByTwo;
} else {
oddSum += digit;
}
}
sum = evenSum + oddSum;
if (sum % 10 == 0) {
System.out.println("valid card");
return true;
} else {
System.out.println("invalid card");
return false;
}
}
public static void main(String[] args) {
String cardNum = "8112189875";
System.out.println(checkLuhn(cardNum));
}
}
Hope it may works.
const options = {
method: 'GET',
headers: {Accept: 'application/json', 'X-Api-Key': '[APIkey]'}
};
fetch('https://api.epaytools.com/Tools/luhn?number=[CardNumber]&metaData=true', options)
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.error(err));
Related
Below is a Archive PROBLEM from SPOJ. Sample testCase is passing, but I am getting W/A on submission. I am missing some testCase(testCases). Need help to figure out what case I am missing and/or what I am doing wrong here.
Ada the Ladybug is playing Game of Divisors against her friend Velvet Mite Vinit. The game has following rules. There is a pile of N stones between them. The player who's on move can pick at least 1 an at most σ(N) stones (where σ(N) stands for number of divisors of N). Obviously, N changes after each move. The one who won't get any stones (N == 0) loses.
As Ada the Ladybug is a lady, so she moves first. Can you decide who will be the winner? Assume that both players play optimally.
Input
The first line of input will contain 1 ≤ T ≤ 10^5, the number of test-cases.
The next T lines will contain 1 ≤ N ≤ 2*10^7, the number of stones which are initially in pile.
Output
Output the name of winner, so either "Ada" or "Vinit".
Sample Input:
8
1
3
5
6
11
1000001
1000000
29
Sample Output:
Ada
Vinit
Ada
Ada
Vinit
Vinit
Ada
Ada
CODE
import java.io.*;
public class Main
{
public static int max_size = 2 * (int)Math.pow(10,7) + 1;
//public static int max_size = 25;
//public static int max_size = 2 * (int)Math.pow(10,6) + 1;
public static boolean[] dp = new boolean[max_size];
public static int[] lastPrimeDivisor = new int[max_size];
public static int[] numOfDivisors = new int[max_size];
public static void main(String[] args) throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
preprocess();
int t = Integer.parseInt(br.readLine());
while(t > 0)
{
int n = Integer.parseInt(br.readLine());
if(dp[n] == true)
System.out.println("Ada");
else
System.out.println("Vinit");
t--;
}
}
public static void markLastPrimeDivisor()
{
for(int i = 0 ; i < max_size ; i++)
{
lastPrimeDivisor[i] = 1;
}
for(int i = 2 ; i < max_size ; i += 2)
{
lastPrimeDivisor[i] = 2;
}
int o = (int)Math.sqrt(max_size);
for(int i = 3 ; i < max_size; i++)
{
if(lastPrimeDivisor[i] != 1)
{
continue;
}
lastPrimeDivisor[i] = i;
if(i <= o)
{
for(int j = i * i ; j < max_size ; j += 2 * i)
{
lastPrimeDivisor[j] = i;
}
}
}
/*for(int i = 1 ; i < max_size ; i++)
System.out.println("last prime of " + i + " is " + lastPrimeDivisor[i]);*/
}
public static void countDivisors(int num)
{
int original = num;
int result = 1;
int currDivisorCount = 1;
int currDivisor = lastPrimeDivisor[num];
int nextDivisor;
while(currDivisor != 1)
{
num = num / currDivisor;
nextDivisor = lastPrimeDivisor[num];
if(nextDivisor == currDivisor)
{
currDivisorCount++;
}
else
{
result = result * (currDivisorCount + 1);
currDivisorCount = 1;
currDivisor = nextDivisor;
}
}
if(num != 1)
{
result = result * (currDivisorCount + 1);
}
//System.out.println("result for num : " + original + ", " + result);
numOfDivisors[original] = result;
}
public static void countAllDivisors()
{
markLastPrimeDivisor();
for(int i = 2 ; i < max_size ; i++)
{
countDivisors(i);
//System.out.println("num of divisors of " + i + " = " + numOfDivisors[i]);
}
}
public static void preprocess()
{
countAllDivisors();
dp[0] = dp[1] = dp[2] = true;
for(int i = 3 ; i < max_size ; i++)
{
int flag = 0;
int limit = numOfDivisors[i];
//If for any i - j, we get false,for playing optimally
//the current opponent will choose to take j stones out of the
//pile as for i - j stones, the other player is not winning.
for(int j = 1 ; j <= limit; j++)
{
if(dp[i - j] == false)
{
dp[i] = true;
flag = 1;
break;
}
}
if(flag == 0)
dp[i] = false;
}
}
}
There is a subtle bug in your countDivisors() function. It assumes
that lastPrimeDivisor[num] – as the name indicates – returns the
largest prime factor of the given argument.
However, that is not the case. For example, lastPrimeDivisor[num] = 2
for all even numbers, or lastPrimeDivisor[7 * 89] = 7.
The reason is that in
public static void markLastPrimeDivisor()
{
// ...
for(int i = 3 ; i < max_size; i++)
{
// ...
if(i <= o)
{
for(int j = i * i ; j < max_size ; j += 2 * i)
{
lastPrimeDivisor[j] = i;
}
}
}
}
only array elements starting at i * i are updated.
So lastPrimeDivisor[num] is in fact some prime divisor of num, but not
necessarily the largest. As a consequence, numOfDivisors[55447] is computed
as 8 instead of the correct value 6.
Therefore in countDivisors(), the exponent of a prime factor in num
must be determined explicitly by repeated division.
Then you can use that the divisors function is multiplicative. This leads to
the following implementation:
public static void countAllDivisors() {
// Fill the `somePrimeDivisor` array:
computePrimeDivisors();
numOfDivisors[1] = 1;
for (int num = 2 ; num < max_size ; num++) {
int divisor = somePrimeDivisor[num];
if (divisor == num) {
// `num` is a prime
numOfDivisors[num] = 2;
} else {
int n = num / divisor;
int count = 1;
while (n % divisor == 0) {
count++;
n /= divisor;
}
// `divisor^count` contributes to `count + 1` in the number of divisors,
// now use multiplicative property:
numOfDivisors[num] = (count + 1) * numOfDivisors[n];
}
}
}
I'm writing a Java program that will play a game.
Basically you choose the no. of players and rounds, then the program shows you what every player should say, in order, considering the following rules:
-assuming the players are standing in a circle, they start counting one-by-one clockwise until someone reaches a number (larger than 10) made of only the same digit. For example 11, 22, 33, .. , 444 etc, then they start counting counter clockwise
E.g.: P9: 9; P10: 10; P11: 11; P12: 13; P11: 14 etc (P10 = Player 10)
-when the get to a number that is multiple of 7, contains 7 or the sum of the digits is 7, they say "Boltz"
E.g.: P1: 13; P2: Boltz (instead of 14); P3: 15; P4 Boltz (16); P5: Boltz (17); P6:18 etc
I have the code in Java, but i can't seem to get the switching from clockwise turns to counterclockwise at numbers made up from only one digit
Can you please help me on SameDigits function? Thank you!
import java.util.Scanner;
public class Boltz {
private static Scanner keyboard;
public static void main(String[] args) {
keyboard = new Scanner(System.in);
int nPlayers = 0;
int nRounds = 0;
int currentPlayer = 0;
int sum = 0;
int x = 0;
boolean isSameDigit = true;
System.out.print("Cati jucatori sunt? ");
nPlayers = keyboard.nextInt();
System.out.print("Cate runde sunt? ");
nRounds = keyboard.nextInt();
System.out.print("Jucatori: " + nPlayers + "; Runde: " + nRounds + "\n");
for (x = 1; x <= nPlayers * nRounds; x++) {
isSameDigit = SameDigits(currentPlayer);
if (currentPlayer < nPlayers && isSameDigit == false) {
currentPlayer++;
} else {
currentPlayer = 1;
}
if (currentPlayer > 1 && isSameDigit == true) {
currentPlayer--;
} else {
currentPlayer = nPlayers;
}
sum = digitSum(x);
if (x % 7 == 0 || String.valueOf(x).contains("7") || sum == 7) {
System.out.println("P:" + currentPlayer + " Boltz");
} else {
System.out.println("P:" + currentPlayer + " " + x);
}
}
}
public static int digitSum(int num) {
int suma = 0;
while (num > 0) {
suma = suma + num % 10;
num = num / 10;
}
return suma;
}
public static boolean SameDigits(int num) {
int add = 0, add2 = 0;
while (num > 0) {
add = add + num % 10;
add2 = add2 + add % 10;
num = num / 10;
}
if (add == add2) {
return true;
} else {
return false;
}
}
}
If I understand you correctly, you want SameDigits to return true if the number is all the same digits and false otherwise. Single-digit numbers should also return true. This should do it:
public static boolean SameDigits(int num) {
if (num < 0) return false; // or something else?
int onesDigit = num % 10;
num /= 10;
while (num > 0) {
if (onesDigit != num % 10) return false; // fail if digits differ
num /= 10;
}
return true;
}
P.S. You should conform to Java naming conventions and name your methods starting with a lower-case letter (sameDigits instead of SameDigits).
That would be something like:
public static boolean sameDigits(int number) {
//speical case
if (number < 10)
return false;
String string = String.valueOf(number);
for (int i = 1; i <= 9; i++) {
if (string.replaceAll(String.valueOf(i), "").length() == 0)
return true;
}
return false;
}
I'd use a regular expression. This one checks whether a String consists of a single digit, followed by one or more repetitions of the same digit.
public static boolean sameDigits(int arg) {
return Integer.toString(arg).matches("(\\d)\\1+");
}
In my code, I want charSum to return 'X' if the remainder is 10 when the sum of 9 digits is divided by 9. I tried both charSum = 'X' and charSum = (char) 88 and neither works. Something in my algorithm must be wrong. Please help.
public static char getCheckSum(String isbn) {
int sum = 0;
for (int i = 0; i < isbn.length(); i++) {
int[] num = new int[isbn.length()];
num[i] = Character.getNumericValue(isbn.charAt(i));
sum = sum + num[i];
}
int last = (sum % 11);
char charSum;
if (last == 10){
charSum = 'X';
} else {
charSum = (char) (last + 48);
}
return charSum;
}
public static String formatISBNWithHyphens(String isbn) {
// original isbn: 123456789
// possible new isbn: 1-234-56789-X
char isbn10 = getCheckSum(isbn);
String isbn10Str = isbn + Character.toString(isbn10);
// char[] c = new char[isbn10Str.length()]; *leaving this here for future learning.
String[] cStr = new String[isbn10Str.length()];
String isbnStr = "";
for (int i = 0; i < isbn10Str.length(); i++){
cStr[i] = Character.toString(isbn10Str.charAt(i));
// c[i] = isbn10Str.charAt(i); *leaving this here for future learning.
if (i == 0 || i == 3 || i == 8 ) {
cStr[i] += '-';
}
isbnStr += cStr[i];
}
return isbnStr;
}
It works fine. If I run it with 933456789 (the sum of which is 54, so 54 % 11 = 10), the getCheckSum() method returns X as expected.
However, this does not seem like the correct way to calculate an ISBN-10 checksum. According to Wikipedia:
The 2001 edition of the official manual of the International ISBN
Agency says that the ISBN-10 check digit – which is the last digit of
the ten-digit ISBN – must range from 0 to 10 (the symbol X is used for
10), and must be such that the sum of all the ten digits, each
multiplied by its (integer) weight, descending from 10 to 1, is a
multiple of 11.
I've implemented it according to the specification as follows:
public static char getCheckDigit(String isbn) {
if (isbn == null || !isbn.matches("[0-9]{9,}")) {
throw new IllegalArgumentException("Illegal ISBN value");
}
int sum = 0;
for (int i = 0; i < 9; i++) {
sum += ((10 - i) * Character.digit(isbn.charAt(i), 10));
}
int check = ((11 - (sum % 11)) % 11);
return check == 10 ? 'X' : Character.forDigit(check, 10);
}
Applied to a couple of ISBN values I found on the same Wikipedia page:
getCheckDigit("097522980"); // --> returns 'X'
getCheckDigit("094339604"); // --> returns '2'
getCheckDigit("999215810"); // --> returns '7'
public class HelloWorld{
public static char getCheckSum(String isbn) {
int sum = 0;
for (int i = 0; i < isbn.length(); i++) {
int[] num = new int[isbn.length()];
num[i] = Character.getNumericValue(isbn.charAt(i));
System.out.println(num[i]);
sum = sum + num[i];
System.out.println(sum);
}
int last = (sum % 11);
char charSum;
if (last == 10){
charSum = 'X';
} else {
charSum = (char) (last + 48);
}
return charSum;
}
public static void main(String []args){
String isbn="123456787";
// possible new isbn: 1-234-56789-X
char isbn10 = getCheckSum(isbn);
System.out.println(isbn10);
}
}
it's working fine :)
I'm trying to implement a luhn formula in my java servlet application. I tried other 'valid' credit cards numbers scattering in the internet and didn't work. I just want to know if I got it correctly. Any help would be appreaciate!
public static boolean luhn(String input){
char[] creditCard = input.toCharArray();
int checkSum = 0;
boolean alternate = false;
for (int i = creditCard.length - 1; i >= 0; i --){
int m = (int)Integer.parseInt(Character.toString(creditCard[i]));
if (alternate){
m *= 2;
if (m > 9){
m = (m & 10) + 1;
}
}
checkSum += m;
alternate = true;
}
if ( (checkSum % 10) == 0){
return true;
}else{
return false;
}
}
here the working code
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
boolean repeat;
List<Integer> digits = new ArrayList<Integer>();
do {
repeat = false;
System.out.print("Enter your Credit Card Number : ");
String input = in.next();
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (c < '0' || c > '9') {
repeat = true;
digits.clear();
break;
} else {
digits.add(Integer.valueOf(c - '0'));
}
}
} while (repeat);
int[] array = new int[digits.size()];
for (int i = 0; i < array.length; i++) {
array[i] = Integer.valueOf(digits.get(i));
}
boolean valid = check(array);
System.out.println("Valid: " + valid);
}
to check for luhn algo
public static boolean check(int[] digits) {
int sum = 0;
int length = digits.length;
for (int i = 0; i < length; i++) {
// get digits in reverse order
int digit = digits[length - i - 1];
// every 2nd number multiply with 2
if (i % 2 == 1) {
digit *= 2;
}
sum += digit > 9 ? digit - 9 : digit;
}
return sum % 10 == 0;
}
or a more refracted program might be as below
import java.util.Scanner;
public class Luhn {
private static Scanner input;
public static void main(String... args) {
input = new Scanner(System.in);
System.out.print("Enter number to validate:\n");
String pnr = input.nextLine();
boolean result = luhn(pnr);
printMessage(result);
input.close();
}
static boolean luhn(String pnr){
// this only works if you are certain all input will be at least 10 characters
int extraChars = pnr.length() - 10;
if (extraChars < 0) {
throw new IllegalArgumentException("Number length must be at least 10 characters!");
}
pnr = pnr.substring(extraChars, 10 + extraChars);
int sum = 0;
for (int i = 0; i < pnr.length(); i++){
char tmp = pnr.charAt(i);
int num = tmp - '0';
int product;
if (i % 2 != 0){
product = num * 1;
}
else{
product = num * 2;
}
if (product > 9)
product -= 9;
sum+= product;
}
return (sum % 10 == 0);
}
private static void printMessage(boolean valid) {
if (valid){
System.out.print("Valid!\r");
}
else{
System.out.print("Invalid!");
}
}
}
First of all this is a school project about credit card number validations.
Basically I am trying to convert a long int (the CC number) into a vector so I can manipulate each digit as required. I am doing it by using the %10 way. Since this will end up with my vector having the number from right to left (backwards), I am setting the vector in increments starting from ccNum.size()-1 and working backwards so that the values in the vector are in the same order as the user input.
The problem is that first values that are processed (so the last 9 or so digits of input) are being put in the vector incorrectly. I've tried restructuring the loop, copying into an array and then reversing it into the vector, and various other things that my mind just can't keep track of. I tried to comment my code as best as I could to outline what is going on, here it is:
public static void main(String[] args) {
long creditCardNumber = 0;
Vector<Integer> ccNum = new Vector<Integer>(13,3);
Vector<Integer> oddNum = new Vector<Integer>(6,1);
Vector<Integer> evenNum = new Vector<Integer>(6,1);
creditCardNumber = getInput(creditCardNumber);
int size = getSize(creditCardNumber);
//Pre-populate the vector so that I can add values starting from behind
//this makes it so that the credit card number isn't backwards. I also
//did it so that it matches the size of the input to prevent false values
//Yes, I verified the getSize method works.
for (int k = 0; k < size; k++) {
ccNum.add(k);
}
//I made a copy of the variable so I don't screw it up in the loop
long ccNumber = creditCardNumber;
//THIS IS WHERE THE PROBLEM IS.
for (int j = 0; ccNumber > 0; j++){
//on the first iteration, set the final index of ccNum array to
//final value of input using %10
if (j == 0){
ccNum.set(ccNum.size() - 1, (int) ccNumber % 10);
ccNumber /= 10;
//This just prints the value of ccNumber afterwards so that I can
//keep track of whats going on and make sure everything is "working"
System.out.println(ccNumber);
} else {
//Here I am continuously setting the values going backwards
//I end up with the same amount of values as the input but some
//are wrong
ccNum.set(ccNum.size() - (j+1), (int) ccNumber % 10);
ccNumber /= 10;
System.out.println(ccNumber);
}
}
//Here is where I print out all the values in the ccNum vector.
for (int l = 0; l < size; l++) {
System.out.print(ccNum.get(l));
}
System.out.println("");
for (int i = 0; i < ccNum.size() - 1; i ++) {
if (i % 2 == 0) {
evenNum.add(getDigit(ccNum.get(i)));
} else {
oddNum.add(ccNum.get(i));
}
}
int prefix = getPrefix(ccNum);
int sumEven = sumOfDoubleEvenPlace(evenNum);
int sumOdd = sumOfOddPlace(oddNum);
if (isValid(ccNum, sumEven, sumOdd, size, prefix)) {
System.out.printf("%d: is valid", creditCardNumber);
} else {
System.out.printf("%d: is invalid", creditCardNumber);
}
}
private static int sumOfOddPlace(Vector<Integer> oddNum) {
int sum = 0;
for (int i = 0; i < oddNum.size() - 1; i++) {
sum += oddNum.get(i);
}
return sum;
}
private static int sumOfDoubleEvenPlace(Vector<Integer> evenNum) {
int sum = 0;
for (int i = 0; i < evenNum.size() - 1; i++) {
sum += evenNum.get(i);
}
return sum;
}
private static int getDigit(int x) {
int y = x*2;
if (y < 10) {
return y;
} else {
int sum = 0;
while (y > 0) {
sum += y % 10;
y /= 10;
}
return sum;
}
}
private static int getPrefix(Vector<Integer> ccNum) {
if (ccNum.get(0) == 4) {
return 4;
} else if (ccNum.get(0) == 5) {
return 5;
} else if (ccNum.get(0) == 6) {
return 6;
} else if (ccNum.get(0) == 3 && ccNum.get(1) == 7) {
return 37;
} else {
return 0;
}
}
private static int getSize(long creditCardNumber) {
int size = (int)(Math.log10(creditCardNumber)+1);
return size;
}
private static long getInput(long creditCardNumber){
Scanner input = new Scanner(System.in);
System.out.print("Enter a credit card number: ");
creditCardNumber = input.nextLong();
input.close();
return creditCardNumber;
}
private static boolean isValid(Vector<Integer> ccNum, int sumEven, int sumOdd, int size, int prefix) {
if (size < 13 || size > 16) {
return false;
} else if (prefixMatched(prefix) == false) {
return false;
} else if ((sumEven + sumOdd) % 10 != 0) {
return false;
} else {
return true;
}
}
private static boolean prefixMatched(int prefix) {
if (prefix == 4 || prefix == 5 || prefix == 6 || prefix == 37) {
return true;
} else {
return false;
}
}
Here is the output:
Enter a credit card number: 4388576018410707
438857601841070
43885760184107
4388576018410
438857601841
43885760184
4388576018
438857601
43885760
4388576
438857
43885
4388
438
43
4
0
438857601249-2-16-3
4388576018410707: is invalid
As You can see, the first half of the number comes out correctly (the last half to be looped). If anybody has a solution that'd be awesome.
For future reference for other people who may get stuck - this is what i ended up doing, looks cleaner as well, Thanks for the help everyone.
public class CreditCardNumberValidation {
public static void main(String[] args) {
long creditCardNumber = 0;
//Using ArrayLists because it makes it easier to manipulate data later
ArrayList<Integer> ccNum = new ArrayList<Integer>();
ArrayList<Integer> oddNum = new ArrayList<Integer>();
ArrayList<Integer> evenNum = new ArrayList<Integer>();
//Getting input in different method to clean up the code
creditCardNumber = getInput(creditCardNumber);
int size = getSize(creditCardNumber);
//Split creditCardNumber into separate integers and store in ArrayList
long ccNumber = creditCardNumber;
for (int j = 0; ccNumber > 0; j++){
ccNum.add((int) (ccNumber % 10));
ccNumber /= 10;
}
//Reverse the collection so that the numbers are in order
Collections.reverse(ccNum);
//Using the main List, even and odd numbers are sorted
for (int i = 0; i < ccNum.size(); i ++) {
if (i % 2 == 0) {
evenNum.add(getDigit(ccNum.get(i)));
} else {
oddNum.add(ccNum.get(i));
}
}
int prefix = getPrefix(ccNum);
int sumEven = sumOfDoubleEvenPlace(evenNum);
int sumOdd = sumOfOddPlace(oddNum);
if (isValid(ccNum, sumEven, sumOdd, size, prefix)) {
System.out.printf("%d is valid", creditCardNumber);
} else {
System.out.printf("%d is invalid", creditCardNumber);
}
}
private static int sumOfOddPlace(ArrayList<Integer> oddNum) {
int sum = 0;
for (int i = 0; i < oddNum.size(); i++) {
sum += oddNum.get(i);
}
return sum;
}
private static int sumOfDoubleEvenPlace(ArrayList<Integer> evenNum) {
int sum = 0;
for (int i = 0; i < evenNum.size(); i++) {
sum += evenNum.get(i);
}
return sum;
}
private static int getDigit(int x) {
int y = x*2;
if (y < 10) {
return y;
} else {
int sum = 0;
while (y > 0) {
sum += y % 10;
y /= 10;
}
return sum;
}
}
private static int getPrefix(ArrayList<Integer> ccNum) {
if (ccNum.get(0) == 4) {
return 4;
} else if (ccNum.get(0) == 5) {
return 5;
} else if (ccNum.get(0) == 6) {
return 6;
} else if (ccNum.get(0) == 3 && ccNum.get(1) == 7) {
return 37;
} else {
return 0;
}
}
private static int getSize(long creditCardNumber) {
//Easy way of getting the size of an integer without modifying it
return (int)(Math.log10(creditCardNumber)+1);
}
private static long getInput(long creditCardNumber){
Scanner input = new Scanner(System.in);
System.out.print("Enter a credit card number: ");
creditCardNumber = input.nextLong();
input.close();
return creditCardNumber;
}
private static boolean isValid(ArrayList<Integer> ccNum, int sumEven, int sumOdd, int size, int prefix) {
// Check size, prefix, and sum, if all tests pass return true
if (size < 13 || size > 16) {
return false;
} else if (prefixMatched(prefix) == false) {
return false;
} else if ((sumEven + sumOdd) % 10 != 0) {
return false;
} else {
return true;
}
}
private static boolean prefixMatched(int prefix) {
if (prefix == 4 || prefix == 5 || prefix == 6 || prefix == 37) {
return true;
} else {
return false;
}
}
}
Try to replace
(int) ccNumber % 10
by
(int) (ccNumber % 10)
If you cast to int first and then do the modulo 10, it won't work when the int value overflows.
I recomend you using ArrayList like in my listing. My function returns simple arraylist of integers that was in Long.
public List<Integer>getCardNumbers(Long longCardNumber){
String cardNumber = longCardNumber.toString();
List<Integer> intCardNumberList = new ArrayList<Integer>();
for(int i=0;i<cardNumber.length();i++){
intCardNumberList.add(Integer.parseInt(String.valueOf(cardNumber.charAt(i))));
}
return intCardNumberList;
}