I am writing my own big integer class in java without imports and need a method for doubling a number of any size that is represented by a string. The code I have for this now works, but begins to take a long time once the numbers get bigger and bigger. I essentially create two arrays: the main array and the countdown array which both start as the same thing. Then, I run a while loop and increment the main array up and increment the countdown array down. When the countdown array reaches "0", I terminate the loop and the result is a new array with the new number doubled in size. Then of course I have if statements checking whether the arrays need to change the ten's place, etc.... here's what I have... Is there any way I can make it more efficient and quick?
public static String doubleDecimalString (String main) {
String countdown = main;
String finalBuild = "";
boolean runLoop = true;
//if zero is supplied, skip all the nonsense and just return 0
//else, loop through and find the true double
//was having trobule getting single digits to double correctly so i had to hard code this for now.
if (main.equals("0")) {
return main;
} else if (main.equals("5")) {
return "10";
} else if (main.equals("6")) {
return "12";
} else if (main.equals("7")) {
return "14";
} else if (main.equals("8")) {
return "16";
} else if (main.equals("9")) {
return "18";
} else {
//Array for ORIGINAL NUMBER
int[] mainPiece = new int[main.length()+2];
int arrayLength = mainPiece.length;
for ( int i = 0; i < main.length(); i++ ) {
mainPiece[i+2] = Integer.parseInt(main.substring( i, i+1));
}
mainPiece[0] = -1;
mainPiece[1] = -1;
//Array for COUNTDOWN NUMBER
int[] countdownPiece = new int[main.length()+2];
for ( int i = 0; i < main.length(); i++ ) {
countdownPiece[i+2] = Integer.parseInt(main.substring( i, i+1));
}
countdownPiece[0] = -1;
countdownPiece[1] = -1;
while ( runLoop ) {
//Increment and decrement the two arrays
mainPiece[arrayLength-1] += 1;
countdownPiece[arrayLength-1] -= 1;
//UPDATE MAIN ARRAY
if ( mainPiece[arrayLength-1] == 10 ) {
for (int x = arrayLength-1; x > 0; x--) {
if ( (mainPiece[x] == 10) && (mainPiece[x-1] != 9) ) {
mainPiece[x] = 0;
mainPiece[x -1] += 1;
} else if ( (mainPiece[x] == 10) && (mainPiece[x-1] == 9) ) {
mainPiece[x] = 0;
mainPiece[x -1] += 1;
x = arrayLength;
}
if ( (mainPiece[2] == 10) ) {
mainPiece[1] = 1;
mainPiece[2] = 0;
}
}
} // end main array
//UPDATE SIDE ARRAY
if ( countdownPiece[arrayLength-1] == -1 ) {
for (int x = arrayLength-1; x > 0; x--) {
if ( (countdownPiece[x] == -1) && (countdownPiece[x-1] > 0) && (x > 1) ) {
countdownPiece[x] = 9;
countdownPiece[x -1] -= 1;
} else if ( (countdownPiece[x] == -1) && (countdownPiece[x-1] == 0) && (x > 1) ) {
countdownPiece[x] = 9;
countdownPiece[x -1] -= 1;
x = arrayLength;
}
}
} //end side array
//tests whether the pieces need to be switched to -1 for scanning
for (int x = 0; x < arrayLength - 1; x++) {
if ( (countdownPiece[x] == -1 ) && (countdownPiece[x+1] == 0 ) ) {
countdownPiece[x+1] = -1;
}
}
//if the side array has reached "0" then the loop will stop and the main array will return the new doubled value
if ( (countdownPiece[arrayLength-1] == -1) && (countdownPiece[arrayLength-2] == -1) ) {
break;
}
} //end while loop
//transform array into string
finalBuild = "";
for (int T = 0; T < arrayLength; T++) {
finalBuild += (mainPiece[T] != -1) ? mainPiece[T] : "";
}
return finalBuild;
}
}
How about something like this (it basically does a multiply by two and accounts for carries):
private String doubleNumber(String number)
{
int doubleDig = 0;
int carry = 0;
StringBuilder sb = new StringBuilder();
for (int i = number.length() - 1; i >= 0; --i)
{
char c = number.charAt(i);
int origNum = Character.getNumericValue(c);
doubleDig = origNum * 2 + carry;
carry = doubleDig / 10;
doubleDig = doubleDig % 10;
sb.append(doubleDig);
}
if (carry > 0)
{
sb.append(carry);
}
return sb.reverse().toString();
}
Obviously this only handles integers.
I would use StringBuilder or List to build your doubled value.
Use a carry variable to store the carry amount and initialize to 0.
Start at the least significant digit, double the digits and add the carry.
Then set the carry to digit / 10, then the digit to digit % 10
Append digit to your builder or list.
After you loop through all your digits, check if carry is > 0 and append if needed.
Reverse the StringBuilder or list and join and you have your answer.
public class Doubler {
public static void main(String[] args) {
System.out.println(doubleDec("9123123123087987342348798234298723948723987234982374928374239847239487.23233099"));
}
public static String doubleDec(String dec) {
StringBuilder builder = new StringBuilder();
int carry = 0;
for (int i = dec.length() - 1; i > -1 ; i--) {
char charDigit = dec.charAt(i);
if (charDigit == '.') {
builder.append(charDigit);
} else {
int digit = Character.getNumericValue(charDigit);
if (digit == -1) {
throw new IllegalStateException("Invalid character in decimal string.");
}
digit = digit * 2 + carry;
carry = digit / 10;
digit = digit % 10;
builder.append(digit);
}
}
if (carry != 0) {
builder.append(carry);
}
return builder.reverse().toString();
}
}
// 18246246246175974684697596468597447897447974469964749856748479694478974.46466198
Related
So, for class I have to code a program that determines how many positive integers are
1) Under 1,000,000
2) Have at least one 7 and a 9 in the number
3) Has to be done with the brute-force method.
While the answer is supposed to be 199,262, I keep getting 228530 due to duplicates, can someone take a look to see where I went wrong here? Thanks!
Similar problem but not the same: Java - numbers with at least one 7 and one 9 in its digit
boolean sevNine = false; // a combination of seven and nine in a number
boolean oneNine;
boolean oneSeven;
int counter = 0;
for (int i = 0; i<1000000; i++) //Runs numbers 1-1000000
{
oneSeven = false;
oneNine = false;
String number2 = " " + (i); //sets a nmber to a string
int length = number2.length() -1; //length goes up to the last character 0-j
for (int j= 0; j <= length; j++) //looking for the first 7 or 9 in string
{
char a = number2.charAt(j); //sets char to the next "letter"
if (a == '7' && oneSeven != true) //if the number is a 7 and there isnt already a seven
{
oneSeven = true; //now there is a seven,
for (int k = j+1; k <= length; k++) //checks from the next char up to the length for a 9
{
char b = number2.charAt(k);
if (b == '9')
{
sevNine = true;
}
}
}
else if (a == '9' && oneNine != true)
{
oneNine = true;
for (int l = j+1; l <= length; l++)
{
char b = number2.charAt(l);
if (b == '7')
{
sevNine = true;
}
}
}
if (sevNine == true)
{
counter++;
sevNine = false;
System.out.println(number2);
}
}
}
System.out.println(counter);
In Java 8 you can try:
public static void main(String[] args) {
final long count = IntStream.rangeClosed(0, 10_00_000)
.filter(i -> String.valueOf(i).contains("7") && String.valueOf(i).contains("9"))
.count();
System.out.println(count);
}
You are not breaking out of the loop once the sevNine is set to true and you increment the counter, so it keeps iterating over each digit on the same number even if it has already included the number... Just add a break statement to exit the for loop iterating over each digit once you increment the counter...
Here's the code.
public static void main(String[] args) {
boolean sevNine = false; // a combination of seven and nine in a number
boolean oneNine;
boolean oneSeven;
int counter = 0;
for (int i = 0; i < 1000000; i++) // Runs numbers 1-1000000
{
oneSeven = false;
oneNine = false;
String number2 = " " + (i); // sets a nmber to a string
int length = number2.length() - 1; // length goes up to the last character 0-j
for (int j = 0; j <= length; j++) // looking for the first 7 or 9 in string
{
char a = number2.charAt(j); // sets char to the next "letter"
if (a == '7' && oneSeven != true) // if the number is a 7 and there isnt already a seven
{
oneSeven = true; // now there is a seven,
for (int k = j + 1; k <= length; k++) // checks from the next char up to the length for a 9
{
char b = number2.charAt(k);
if (b == '9') {
sevNine = true;
}
}
} else if (a == '9' && oneNine != true) {
oneNine = true;
for (int l = j + 1; l <= length; l++) {
char b = number2.charAt(l);
if (b == '7') {
sevNine = true;
}
}
}
if (sevNine == true) {
counter++;
sevNine = false;
System.out.println(number2);
break;
}
}
}
System.out.println(counter);
}
If you run with the break statement, you should get 199262 as the resulting number.
My function does not return the correct answer. My task is to count the two numbers in an array that are the same and next to each other here is a sample:
array_1 = {1,2,2,3,4,4,2}; ans = 2
array_2 = {2,2,3,4,4}; ans = 2
array_3 = {1,1,1,1,1,1,1}; ans = 1
array_4 = {1,2,3,4,2}; ans = 0
Here is my function. Observed output is given as comments.
public class countClampsTest
{
public static void main(String[] args)
{
int array_1[] = {1,2,2,3,4,4,2}; // expected result: 2
int array_2[] = {2,2,3,4,4}; // expected result: 2
int array_3[] = {1,1,1,1,1,1,1}; // expected result: 1
int array_4[] = {1,2,3,4,2}; // expected result: 0
System.out.println(countClamps(array_1)); // Returns 2
System.out.println(countClamps(array_2)); // Returns 1
System.out.println(countClamps(array_3)); // Returns 1
System.out.println(countClamps(array_4)); // Returns 0
}
static int countClamps(int[] arr) {
int result = 0;
int nextNext = 0;
for (int current = 0; current < arr.length - 1; current++) {
for (int next = current; next <= current + 1; next++) {
nextNext = next + 1;
if(nextNext >= arr.length) {
nextNext = arr.length -1;
}
if (arr[current] == arr[next] && current != next) {
if(arr[next] != arr[nextNext]) {
result++;
} else if(arr[next] == arr[nextNext] && arr.length % 2 == 0) {
result = 1;
}
}
}
}
return result;
}
}
I see a few issues in your code.
In the test:
if (arr[current] == arr[next] && current != next) {
you compare current with next; you could obtain the same result by starting the next loop at current+1 instead of current:
for (int next = current+1; next <= current + 1; next++) {
nextNext = next + 1;
...
if (arr[current] == arr[next]) {
...
}
}
which makes the loop redundant: it's only executed once, so the code above is equivalent to:
int next = current+1;
nextNext = next + 1;
...
if (arr[current] == arr[next]) {
...
}
Now in your inner test:
if(arr[next] != arr[nextNext]) {
result++;
} else if(arr[next] == arr[nextNext] && arr.length % 2 == 0) {
result = 1;
}
You can see that the first part of the second condition is always true, so it's equivalent to:
if(arr[next] != arr[nextNext]) {
result++;
} else if(arr.length % 2 == 0) {
result = 1;
}
The remaining condition means that you reset result to 1 if the array has an even number of elements (why?).
at the end of the array, result will not be incremented if the last two elements are equal, which is why you don't get the correct result in the second case.
Here is my solution:
static int countClamps(int[] arr) {
int result = 0;
for (int i = 1; i < arr.length; ++i) {
if (arr[i] == arr[i-1]
&& (i == arr.length-1 || arr[i] != arr[i+1])) {
++result;
}
}
return result;
}
A possible solution is: Stop you loop still one iteration earlier: use current < arr.length - 2 (this will cause nextNext to be within the array always). After your outer loop, just compare the last two elements of the array. If they are equal, add 1 to result. Done.
Except if the array has length 0 or 1, you will need to treat that specially.
I've added an extra boolean to keep track of already counted duplicates after each other.
static int countClamps(int[] arr) {
int result = 0;
int prev = 0;
boolean same = false;
for(int i = 0; i < arr.length; i++) {
if (i == 0) {
prev = arr[i];
} else {
if (arr[i] == prev) {
if (!same) {
result++;
same = true;
}
} else {
prev = arr[i];
same = false;
}
}
}
return result;
}
Once you've found a pair skip an index in loop.
public static int pairs(int[] list){
int pairs = 0;
for(int x = 1; x < list.length; x++){
if(list[x] == list[x-1]){
pairs++;
x=x+1;}
}
return pairs;
}
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;
}
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));