Check if string is following ISBN-13 in Java - java

Im trying to check if a string (important that it is a string) that im reading is correct accoring to the rules of ISBN-13. I found a formula
For example, the ISBN-13 check digit of 978-0-306-40615-?
is calculated as follows:
s = 9×1 + 7×3 + 8×1 + 0×3 + 3×1 + 0×3 + 6×1 + 4×3 + 0×1 + 6×3 + 1×1 + 5×3
= 9 + 21 + 8 + 0 + 3 + 0 + 6 + 12 + 0 + 18 + 1 + 15
= 93
93 / 10 = 9 remainder 3
10 – 3 = 7`
My problem is i don't know how to multiply one number with 1 and every other with 3 ? Im guessing a for-loop but i don't know how to start.

You could "simply" use regular expressions:
ISBN(-1(?:(0)|3))?:?\x20+(?(1)(?(2)(?:(?=.{13}$)\d{1,5}([ -])\d{1,7}\3\d{1,6}\3(?:\d|x)$)|(?:(?=.{17}$)97(?:8|9)([ -])\d{1,5}\4\d{1,7}\4\d{1,6}\4\d$))|(?(.{13}$)(?:\d{1,5}([ -])\d{1,7}\5\d{1,6}\5(?:\d|x)$)|(?:(?=.{17}$)97(?:8|9)([ -])\d{1,5}\6\d{1,7}\6\d{1,6}\6\d$)))

You have 6 pairs of (even,odd) numbers, so go through them pairwise.
for (i = 0; i < 6; i++) {
even += array[2*i];
odd += array[2*i+1]*3;
}
checkbit = 10 - (even+odd)%10;

assuming your inputString is ascii:
int odd = 0;
int even = 0;
char[] c = (inputString + "00").replaceAll("[\\-]", "").toCharArray();
for (int i = 0; i < (c.length - 1) / 2; ++i) {
odd += c[2 * i] - 48;
even += c[2 * i + 1] - 48;
}
int result = 10 - (odd + 3 * even) % 10;

This seems to work effectively and is clear.
// Calculates the isbn13 check digit for the 1st 12 digits in the string.
private char isbn13CheckDigit(String str) {
// Sum of the 12 digits.
int sum = 0;
// Digits counted.
int digits = 0;
// Start multiplier at 1. Alternates between 1 and 3.
int multiplier = 1;
// Treat just the 1st 12 digits of the string.
for (int i = 0; i < str.length() && digits < 12; i++) {
// Pull out that character.
char c = str.charAt(i);
// Is it a digit?
if ('0' <= c && c <= '9') {
// Keep the sum.
sum += multiplier * (c - '0');
// Flip multiplier between 1 and 3 by flipping the 2^1 bit.
multiplier ^= 2;
// Count the digits.
digits += 1;
}
}
// What is the check digit?
int checkDigit = (10 - (sum % 10)) % 10;
// Give it back to them in character form.
return (char) (checkDigit + '0');
}
NB: Edited to correctly handle the 0 check digit. See Wikipedia International Standard Book Number for example isbn with check digit of 0.
Paul

Similar, with loop and awful char-to-string-to-int conversions ;]
boolean isISBN13(String s){
String ss = s.replaceAll("[^\\d]", "");
if(ss.length()!=13)
return false;
int sum=0, multi=1;
for(int i=0; i<ss.length()-1; ++i){
sum += multi * Integer.parseInt(String.valueOf(ss.charAt(i)));
multi = (multi+2)%4; //1 or 3
}
return (Integer.parseInt(String.valueOf(ss.charAt(ss.length()))) == (10 - sum%10));
}

Related

Using modulo and integer division to confirm an account number

I am new to Java and currently working on a small class assignment. The question is as follows:
Write a program that determines whether a bank account number with 10 digits or fewer passes a validation test; it requires that we extract the digits, right to left by:
Using the modulo operator to extract the right most digit
Using integer division to remove the right-most digit from the account number to obtain a new number without it.
Beginning with the 2nd right-most digit, moving right to left, double every other digit. If it produces a value greater than 9, subtract 9 from that value.
Form the sum of all products(new digits) and the unchanged digits.
if the sum doesn't end in 0, its invalid.
Check the validity of 5113 4765 12 and 65 1234 1234
Here is my code:
long account = Long.parseLong(JOptionPane.showInputDialog( null, "Enter account number: " ));
int sum = 0;
long digit;
//5113476512
//6512341234
String str_number = String.valueOf(account);
digit = account % 10;
account /= 10;
for(int i = str_number.length() -2; i >= 0; i --){
digit = account % 10;
account /= 10;
// account%=10;
// sum += digit;
digit *= 2;
if (digit > 9){
digit -= 9;
}
sum += digit;
}
// for(int x = 0; x < digit.length; x ++){
// sum += digit[x];
// }
if (sum % 10 != 0){
JOptionPane.showMessageDialog(null, "Account number invalid");
}
else{
JOptionPane.showMessageDialog(null, "Account number valid");
}
JOptionPane.showMessageDialog(null, sum);
But I feel it doesn't follow the requirements and might not be correct. Only one of the account numbers returns valid although I'm not sure if that is supposed to be so or not. Any ideas on how to go about this?
The following implementation using a boolean flag to detect the other number shows that both account numbers are invalid:
public static boolean isValid(long acc) {
System.out.print(acc + " -> "); // debug print
int sum = 0;
boolean other = false;
while (acc > 0) {
int digit = (int) (acc % 10);
acc /= 10;
if (other) {
digit *= 2;
if (digit > 9) digit -= 9;
}
System.out.print(digit + " "); // debug print
sum += digit;
other = !other;
}
System.out.println("sum = " + sum); // debug print
return sum % 10 == 0;
}
Tests:
System.out.println(isValid(5113476512L));
System.out.println(isValid(6512341234L));
Output:
5113476512 -> 2 2 5 3 7 8 3 2 1 1 sum = 34
false
6512341234 -> 4 6 2 2 4 6 2 2 5 3 sum = 36
false

is there an algorithm to reverse a chosen part of a number? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I want to reverse a number but in a way that user chooses
user determine a range which we should reverse digits in that range
for example we want reverse of 123456 and digit range is 2 to 4 which includes {2,3,4}
so user answer would be 143256
I want a solution which does not use arrays and string.
It would be my pleasure to know your ideas..
Reversing part of a number or entire number is not a math operation that can be done with Integers/Longs, so you can use Strings.
Convert your number to a StringBuilder, there is a reverse() method there.
You can cut the String with substring() method also. After cutting and reversing, concatenate again.
EDIT: It can be done with just numbers that way:
Step 1 — Isolate the last digit in number:
lastDigit = number % 10
Step 2 — Append lastDigit to reverse
reverse = (reverse * 10) + lastDigit
Step 3 - Remove last digit from number
number = number / 10
Step 4 - Iterate this process
while (number > 0)
Source: https://medium.com/#ManBearPigCode/how-to-reverse-a-number-mathematically-97c556626ec6
public static int reverseFonction(int startRange, int endRange, int number) {
String numberString = String.valueOf(number);
int numberLength = numberString.length();
if(startRange > numberLength -1 ||
endRange > numberLength - 1 ||
endRange <= startRange ||
startRange < 1) {
return number;
}else {
String string1 = StringUtils.substring(0, startRange -1);
String string2 = StringUtils.substring(startRange, endRange-1);
String string3 = StringUtils.substring(endRange, numberLength -1);
String string2_reversed = "";
for(int i= numberLength-1; i>=0; i--) {
string2_reversed += string2.charAt(i);
}
String finalNumberString = string1 + string2_reversed + string3;
return Integer.parseInt(finalNumberString);
}
}
int N = 123456;
int start = 2;
int end = 4;
start--; // making offset as index position
end--; // making offset as index position
String numString = String.valueOf(N);
char[] array = numString.toCharArray();
while(start<end){
char temp = array[start];
// swap to reverse
array[start] = array[end];
array[end] = temp;
start++;
end--;
}
String resNum ="";
for (char ch: array) {
resNum += ch;
}
System.out.println(Integer.parseInt(resNum));
Assuming that numbers are non-strings, then this example uses a long as it holds more digits.
long n = 123456789L;
System.out.println(n + " " + reverse(n, 1, 9));
n = 1;
System.out.println(n + " " + reverse(n, 1, 1));
n = 11123567111L;
System.out.println(n + " " + reverse(n, 4, 8));
n = 23;
System.out.println(n + " " + reverse(n, 1, 2));
public static long reverse(long n, int s, int e) {
StringBuilder sb = new StringBuilder();
String str = Long.toString(n);
if (s < 1 || e > str.length() || s > e) {
System.out.println("Improper indices provided");
return -1;
}
return Long.parseLong(str.substring(0, s-1)
+ new StringBuilder(str.substring(s-1, e)).reverse()
+ str.substring(e));
}
The range is specified according to what you asked. However, normal ranges in Java are zero based and [s,e) where s is included and e is excluded.
Since you updated your question to state that Strings and arrays may not be used, here is a math based alternative.
long v = 111112456788888L; // number to process
int s = 6; // starting point of reversible section
int e = 10;// ending point of reversible section
// total digits in number
int digits = (int) Math.log10(v) + 1;
// divisor of the tail part
long tdiv = (long) Math.pow(10, digits - e);
// divisor of the center part.
long cdiv = (long) Math.pow(10, e - s + 1);
long tail = v % tdiv;
v /= tdiv;
long ctr = v % cdiv;
v /= cdiv;
// reverse the middle section.
long rev = 0;
while (ctr > 0) {
rev = rev * 10 + ctr % 10;
ctr /= 10;
}
long result = ((v * cdiv) + rev) * tdiv + tail;
System.out.println(result);

Want to print last sentence

You must deliver exactly N kilograms of sugar to a candy store. The sugar made in the sugar factory is contained in a bag. The bag has 3 kg bag and 5 kg bag.
I try to carry as little bags as possible. For example, when you need to deliver 18 kilograms of sugar, you can take 6 bags of 3 kilograms, but if you deliver 3 kilograms and 3 kilograms, you can deliver a smaller number of bags.
Write a program to find out the number of bags you should take when you have to deliver exactly N kilograms of sugar.
(3<=N<=5000 AND If you can not make exactly N kilograms, print -1.)
In case of only 4 or 7 , it is not divided so I made it to print -1.
And to get the minimum bag, I used the code below.
But when I run this, the case if it is not divided by 5 or 3, the bottom sentence should be printed out but it is not working.
I want to know how does it works. Thank you.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int N = input.nextInt();
if (N % 5 == 0) {
System.out.println(N / 5);
} else if (N == 4 || N == 7) {
System.out.println(-1);
} else
for (int i = 1; (N - 3 * i) % 5 != 0; i++) {
if ((N - 3 * i) % 5 == 0)
System.out.println(i + (N - 3 * i) / 5);
break;
}
}
}
Looks there is a logic issue with your solution. Try the following :
boolean isPossible = true;
if (N % 5 == 0) {
System.out.println("You need : " + (N / 5) + " bags");
} else {
int diff = 0;
for (int i = N; i > 0 && N >= 0; i--) {
if (N % 5 != 0) {
diff = N % 5;
N = N - diff;
} else {
if (diff % 3 == 0) {
System.out.println("You need : " + (N / 5 + diff / 3) + " bags");
isPossible = true;
break;
} else {
N = N - 5;
diff = diff + 5;
}
}
}
}
if (N <= 0 || !isPossible)
System.out.println(-1);
Logic is explained below :
Basically here we find the modulus of N with 5 and check if the
remainder (in the example diff) is a multiple of 3.
If the remainder (diff) is not a multiple of 3 then we reduce N by
5 and increase diff by 5. This continues until we have found a match (isPossible) or else if not found -1 is printed out.
So as far as I understand, you're trying to use the smallest amount of 3kg bags in the last for loop and you want to break out as soon as the remainder is divisible by 5kgs.
(int i = 1; (N - 3 * i) % 5 != 0; i++)
Could you not have the middle part as i < 5?
(int i = 1; i < 5; i++)
Also, you could get rid of the if condition
if (N % 5 == 0) {
part by starting i at 0, so you account for the case N is divisible by 5:
(int i = 0; i < 5; i++)
Scanner input = new Scanner(System.in);
int N = input.nextInt();
int sum = 0;
boolean isFound = false;
for (int i = 0; i < N / 2; i++) {
for (int j = 0; j < N / 2; j++) {
if ((5 * i) + (3 * j) == N) {
sum = i + j;
isFound = true;
}
}
}
if (isFound ) {
System.out.println("You require " + sum + " bags");
} else {
System.out.println(-1);
}
Explanation:
The above code aims to find the possible combinations of the sum of the factors of 3 and 5 that give the number, i.e N:
For example:
N = 32
For each iteration, the following condition is checked.
if((5 * i) + (3 * j) == N)
The check continues until the smallest numbers that satisfy the condition are found.
5*0 + 3*0 = 0 which is not equal to 32
5*0 + 3*1 = 3 which is not equal to 32
5*0 + 3*2 = 6 which is not equal to 32
.
.
5*1 + 3*0 = 5 which is not equal to 32
5*1 + 3*1 = 8 which is not equal to 32
5*1 + 3*2 = 11 which is not equal to 32
5*1 + 3*4 = 17 which is not equal to 32
.
.
5*4 + 3*0 = 20 which is not equal to 32
5*4 + 3*1 = 23 which is not equal to 32
5*4 + 3*2 = 26 which is not equal to 32
5*4 + 3*3 = 29 which is not equal to 32
5*4 + 3*4 = 32
In this case, i=4 and j=4, i.e sum of bags required (i+j) = 8
isFound is set to true to indicate that the combination is found.
If no combination is found, isFound remains to be false, and -1 is printed.

Multiplying Using Bitwise Shift Operators Giving TLE

Question
Given N and M, write an equation using left shift operators whose
result will be equal to the product N * M.
Input : First line has 0 < T ≤ 50000 denoting number of test cases.
Next T lines have two integers 0 < N, M ≤ 10¹⁶.
Output : For each test case print an equation for N * M resembling
(N << p1) + (N << p2)+ ...+(N << pk) where p1 ≥ p2 ≥ ... ≥ pk
and k is minimum.
SAMPLE INPUT SAMPLE OUTPUT
2
2 1 (2<<0)
2 3 (2<<1) + (2<<0)
Time Limit: 1.0 sec
My Solution 1st approach
int dig = (int)(Math.floor(Math.log10(m)/Math.log10(2))+1);
boolean flag = false;
for(long i = dig; i>=0; --i) {
if(((m>>(i-1l)) & 1l) == 1l) {
if(flag)
System.out.print(" + ("+n+ "<<"+(i-1)+")");
else {
System.out.print("("+n+"<<"+(i-1)+")");
flag = true;
}
}
}
Second Approach
boolean[] arr = new boolean[dig];
int i = dig-1;
while(m > 0) {
if((m&1) == 1 ) {
arr[i] = true;
}
i--;
m = m>>1l;
}
int j = dig-1;
for( i = 0; i < dig; ++i) {
if(arr[i]) {
if(flag)
System.out.print(" + ("+n+"<<"+j+")");
else {
System.out.print("("+n+"<<"+j+")");
flag = true;
}
}
j--;
}
In both cases I am getting 5 correct out of 8 and rest 3 are TLE why?
I don't actually see anything in both of your approaches preventing some ten-thousands of products of numbers up to 57 bit to be represented as Strings in one second:
TLE may be due to System.out.print() taking an inordinate amount of time.
That said, use a utility like
/** builds <code>n * m</code> in the form
* <code>(n<<p1) + (n<<p2) + ... + (n<<pk)</code>
* using left shift.
* #param n (0 < multiplicand <= 10**16)
* #param m 0 < multiplier <= 10**16
* #return a verbose <code>String</code> for <code>n * m</code>
*/
static String verboseBinaryProduct(Object n, long m) {
int shift = Long.SIZE - Long.numberOfLeadingZeros(m) - 1;
final long highest = 1 << shift;
final StringBuilder binary = new StringBuilder(42);
final String chatter = ") + (" + n + "<<";
final long rest = highest - 1;
while (true) {
if (0 != (highest & m))
binary.append(chatter).append(shift);
if (0 == (rest & m)) {
binary.append(')');
return binary.substring(4);
}
m <<= 1;
shift -= 1;
}
}
and System.out.println(verboseBinaryProduct(n, m));.

Incorrect modulo results in Java

I'm trying to run some elliptic curve results in java, but the modulo operator doesn't seem to output the right results.
int a = 17;
double previousx = 4;
double previousy = 14;
double xnew;
double ynew;
double sigma;
double convert;
for (int i = 1; i < 10; i++) {
convert = 0;
for (int j = 0; i<60; j++) {
if (((2 * previousy * j) % 59) == 1) {
convert = j;
break;
}
}
sigma = ((3 * Math.pow(previousx, 2) + a) * convert) % 59;
xnew = ((sigma * sigma) - (2 * previousx)) % 59;
ynew = (sigma * (previousx - xnew) - previousy) % 59;
System.out.println((Math.pow(2, i)) + "x P: " + xnew + "," + ynew + " Sigma:" + sigma);
previousx = xnew;
previousy = ynew;
}
output of the first iteration:
2.0x P: 8.0,-57.0 Sigma:55.0
8 and 55 are correct, but -57 mod 59 = 2 and not -57. How do I fix this?
8 and 55 are correct, but -57 mod 59 = 2 and not -57. How do I fix this?
The % operator in Java isn't modulus - it's the remainder operator. It's behaving entirely correctly according to the language specification. When you suspect that Java is misbehaving, it's always worth checking the specification to see whether it's actually your expectations which are incorrect.
If you want a modulus operator, you just need to check whether the result is negative, and if so add the divisor again:
int remainder = (2 * previousy * j) % 59;
int modulus = remainder < 0 ? remainder + 59 : remainder;
if (modulus == 1) {
...
}
Alternatively, in your case:
int remainder = (2 * previousy * j) % 59;
if (remainder == 1 || remainder == -58) {
...
}
... and adjust the rest of your uses of % as appropriate too, of course.
Additionally, as Stijn de Witt mentioned, it looks like you've got a typo in your inner loop condition.
It looks to me like you have a typo in the inner loop:
for (int j = 0 ; i<60 ; j++)
It says i<60 in a loop that is iterating over j...
I'd try fixing that.
As to the original question... Can you reduce your test case? If you maintain that modulo is not working correctly for some numbers then why not make a single statement that does a modulo on those numbers and prints the results?

Categories