Multiplying a numeric string in java - java

I'm a beginner in programming and I've been doing the Project Euler programming problems to practice, I've been able to make my way so far, but this time I had to ask for help. Without spoilers, the problem I'm trying to solve consists of finding the sum of the digits of a very large number, so I can't hold it in an int or a double. So I made this method to multiply two strings containing a numeric value.
private static String multiply(String a, String b) {
// No, I'm not checking if the strings are numeric
int subTotal = 1, extra = 0;
String waitingString = "";
StringBuilder number1 = new StringBuilder(a);
StringBuilder number2 = new StringBuilder(b);
List<String> numbers = new ArrayList<String>();
// The reason I reverse the numbers is the for() loops
// I don't want to count down through the numbers, that
// would just confuse me more.
number1.reverse();
number2.reverse();
for (int i = 0; i < number1.length(); i++) {
waitingString = "";
subTotal = Character.getNumericValue(number1.charAt(i));
for (int j = 0; j < number2.length(); j++) {
subTotal *= Character.getNumericValue(number2.charAt(j));
subTotal += extra;
char[] temp = String.valueOf(subTotal).toCharArray();
waitingString = temp[temp.length - 1] + waitingString;
if (subTotal >= 10 || ((j == number2.length() - 1) && (String.valueOf(subTotal).length() > 1))) {
extra = Integer.parseInt(String.valueOf(subTotal).substring(0, temp.length - 1));
} else {
extra = 0;
}
subTotal = Character.getNumericValue(number1.charAt(i));
}
for (int k = 0; k < i; k++) {
waitingString += "0";
}
waitingString = extra + "" + waitingString;
numbers.add(waitingString);
}
// sumAll() is not the problem just in case you were wondering.
// Because as you've read the code, I'm passing a List<String>
// to it and as I was trying to find the error I printed the list
// before everything to check the values and the error was already
// there, 3 of the values are wrong.
return sumAll(numbers);
}
When testing I'm multiplying this number by itself: 1125899906842624. The result should be 1267650600228229401496703205376. But I'm getting 1267650600228229401607703205376. That's a difference of 111000000000. I've been trying to find the error for 2 days and i just can't.
I'm not looking for alternative or better ways to do this, I just can't find the error in my code that adds more than it should.
If you need to see the rest of the code I can provide it and please don't mind spelling/grammar errors, english is not my native language.

Without trying to run this or look at it under a debugger: it looks like you're setting up an extra variable which is a carry, i.e. the value which should get added to the next product as you move to the left (in your original numbers, not the reversed ones). One problem I can see is that if the last product in your inner loop produces something greater than or equal to 10, you compute extra; but then when you go the next outer loop, extra still has that value and gets added to subTotal when it shouldn't be. Try adding the statement extra = 0; at the beginning of your outer loop, and before the inner loop starts. That may fix the problem.
P.S. You're making a lot of extra work for yourself by representing the subTotal as a string and working with it. While I understand why you'd want to use strings for the two multiplicands and the product, subTotal is the product of two single digits with a carry added, and it can never be greater than 89. So you should never have to convert it to a string and work with the string. Thus, instead of
char[] temp = String.valueOf(subTotal).toCharArray();
waitingString = temp[temp.length - 1] + waitingString;
you could say
waitingString = String.valueOf(subTotal % 10) + waitingString;
or something similar (subTotal % 10 gives the remainder when subTotal is divided by 10, and is therefore the last digit of subTotal); and instead of the complex code to compute extra, just say
extra = subTotal / 10;
which divides by 10 and throws away the remainder. You shouldn't be computing String.valueOf(subTotal) at all.
PPS. Don't worry about the answers that tell you to use BigInteger. If you were doing a real programming project, that's what you'd use. But for someone learning how to program, I think that writing a program to compute the product of two numbers, the long way, is a good learning tool.

As someone commented, this would probably be a job for the BigInteger class. Just say
BigInteger intA = new BigInteger(a)
BigInteger intB = new BigInteger(b)
and then call
intA.multiply(intB)
and that will get you a BigInteger containing the result.

I would use BigInteger like this
private static String multiply(String a, String b) {
if (a == null || b == null) {
if (b != null) return b;
return a;
}
BigInteger v = new BigInteger(a, 10);
if (v != null) {
BigInteger t = new BigInteger(b, 10);
if (t != null) {
BigInteger r = v.multiply(t);
return r.toString();
}
}
return "";
}
public static void main(String[] args) {
String result = multiply("1125899906842624", "1125899906842624");
String good = "1267650600228229401496703205376";
System.out.println(result.equals(good));
}
Which prints true when I run it.

Related

Optimizing adding zero padding in a number

I'm practicing on how to optimize codes so any suggestion would be much appreciated. I have this method that adds zero padding to a number when its being incremented. The code are as follows:
public class CommonAlgorithm {
NumberRetrieve retrieve;
public long incrementNumber(CommonNumber t) {
CommonNumberFacade facade = new CommonNumberFacade(retrieve.apply(t));
String number = facade.getGeneratedNumber();
Long num = Long.parseLong(number);
num++;
String result = "";
if (String.valueOf(num).length() < number.length()) {
int length = number.length() - String.valueOf(num).length();
String zero = "";
for (int i = 0; i < length; i++) {
zero += "0";
}
result = zero + num;
} else {
result = String.valueOf(num);
}
return Long.parseLong(t.getPrefix()+result);
}
}
Are there more ways to optimize the code above?
Just in case anyone asks for the purpose of the function, the premise goes like this:
The function returns a number that is composed of the following: a 'prefix' and a 'number'. These two are concatenated to each other after the number has been incremented by 1. However, I realized that if the value of the number has zero padding in it, those zeroes will be disappear once they are converted into a long data type. Therefore if the following values are applied:
prefix = 123
number = 000001
The return value will be 1232 instead of 123000002. That is the problem that the function above is solving. I can't change the return type of the facade.generatedNumber() function into long as I need to return that String return type somewhere in my project eventually. I hope you could give a couple of suggestions
You can simplify your if-else statement as follows:
StringBuilder sb = new StringBulder();
String numStr = String.valueOf(num);
for (int i = numStr.length(); i < number.length(); i++) {
sb.append('0');
}
sb.append(numStr);
String result = sb.toString();
A few simple things:
You use String objects to build your results, like zero and result. Those could be StringBuilder objects. That would clearly express your intent to build strings!
You could look into using String.format()
You are invoking String.valueOf(num); three times, for the same num. You could do that once initially, and reuse that value, instead of computing it repeatedly.
Use the numerical primitive type long instead of the Object wrapper Long.
long num = Long.parseLong(number);
num++;
Place the string representation of num in its own variable.
String numStr = String.valueOf(num);
Zero padding to keep the number of original digits is only needed for increments for negative numbers, and then only for carries / digits '0'. This means that the zeroes should go after the sign.
String +, += is costly, use a StringBuilder:
StringBuilder sb = new StringBuilder(number.length());
Optimal is a relative, it would be okay to do:
long num = Long.parseLong(number);
++num;
String paddedNumStr = numStr.length >= number.length() ? numStr
: String.format("%" + number.length() + "d", num);
Using an if-expression as heuristic optimisation for 95% of the cases.

Need help: Something is not functioning right in my loop. I believe the result + result string is causing issues?

I'm doing this specific exercise here:
Question:
Given a non-empty string and an int N, return the string made starting with char 0, and then every Nth char of the string. So if N is 3, use char 0, 3, 6, ... and so on. N is 1 or more.
e.g:
everyNth("Miracle", 2) → "Mrce"
My code:
public String everyNth(String str, int n) {
int a = 0; String result= "";
for (int i=0;i<str.length();i++) {
if (str.charAt(i) % n == 0) {
result = result + str.charAt(i);
a++;
}
}
return result;
}
I can't figure out how to fix my code given what my plan was:
1. Move result to String result
2. Run a loop and only move the data if modular = 0
But instead of getting Mrce, I'm getting rl
I don't need an easier solution, I just want to understand what is going on wrong and how to make it work.
Exercise Ref: https://codingbat.com/prob/p196441
I don't know how to advise you without telling you the answer, which is fairly simple. You want every nth character. So this,
if (str.charAt(i) % n == 0) {
should just be
if (i % n == 0) {
With just that change (and your provided input), I get (as expected)
Mrce
However, we can indeed make it easier by incrementing by n on each loop iteration. Thus eliminating the need for testing if i is divisible by n. We can also make the method static. And I would prefer a StringBuilder. Like,
public static String everyNth(String str, int n) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i += n) {
sb.append(str.charAt(i));
}
return sb.toString();
}

Leading Zeros in Java output

I have a file (Multiply.txt) that contains comma-separated pairs of integers, one pair per line. I want to multiply the second element of each pair by the least power of 2 necessary to yield a result greater than or equal to the first element of the pair, and print each result. For example, given a line containing "13,8", I want to multiply 8 by 21 to yield 16, and print that.
Given this input file
13,8
17,16
My program prints this output:
0
16
0
32
Instead, I expect
16
32
How can I avoid printing the two zeroes? Here's my program:
/* Sample code to read in test cases:*/
import java.io.*;
public class Multiples_of_a_Number {
public static void main (String[] args) throws IOException {
File file = new File("multiple.txt");
BufferedReader buffer = new BufferedReader(new FileReader(file));
String line;
while ((line = buffer.readLine()) != null) {
line = line.trim();
String[] power = line.split(",");
int[] myPower = new int[power.length];
for (int i = 0; i < power.length; i++) {
String numberAsString = power[i];
myPower[i] = Integer.parseInt(numberAsString);
System.out.println(Multiply(myPower));
}
}
}
public static int Multiply(int[] n){
int t= 0;
for (int i = 0; i < n.length; i++) {
if(n[1] <= n[0]){
t = n[1] * 2;
}else {
}
}
/*while (n.length < n.length-1) {
t = (int) Math.pow(n.length, 2);
}*/
return t;
}
}
If the only thing you want to do is not display zeroes, then just only display when it's not zero:
System.out.println(Multiply(myPower));
with
int result = Multiply(myPower);
if (result > 0) //or != if you work with negatives
{
System.out.println(result);
}
Though I'd personally highly recommend reviewing your code.
You have at least three flaws in your program:
The inner loop in method main() is inappropriate. You don't (seem to) want to process each number individually; rather, you want to process the second element of the pair in light of the first, one time. You are getting four lines of output instead of two because of this problem.
Method Multiply() does not account for the possibility that the second number is already greater than the first (i.e. the case in which you must multiply by 20 == 1). In this case it returns 0. One possible fix would be to initializing local variable t to n[1] instead of to 0.
The implementation of Multiply() seems more broadly to be just wrong, however. It is unclear why you are looping over the elements of n (or at least why you are starting the loop at element 0), and it will not produce a result greater than n[0] if n[1] is less than n[0] / 2. I suspect what you want to do is initialize t to n[1] and then double it as many times as necessary to increase the result above n[0]. That's not at all what you actually are doing.

Reversal of an Integer to check for Palindromic Number

I've looked at a few different stack questions and googled, but nothing I've read really has dealt with reversal of integers, but just strings.
So right now my code may or may not work at all, and it may be the dumbest thing you've ever seen, and that's okay and corrections are welcomed, but from what I hope my code will be doing is going through 100 - 999 multiplying the two ints and then checking whether it's palindromic or not. The if with reverse.equals(sum) is totally pseudocode and obviously won't work, however I can't figure out how to do a check for a palindromic int. Is there a simple way to do this? I've read some pretty lengthy and complicated ways, but I'm sure there's gotta be a simple way. Maybe not. :/. Anyway, here's my code.
public class PalandromicNum {
public static void main(String[] args){
int numOne = 100;
int numTwo = 100;
int toteVal;
int counter = 1000;
int sum = 0;
int finalSum = 0;
for(int i=0; i<counter; i++){
toteVal = numOne * numTwo;
numTwo++;
if(numTwo == 999){
numOne++;
numTwo = 100;
}
if(toteVal < sum){
sum += toteVal;
if(reverse.equals(sum)){
finalSum = sum;
System.out.println(finalSum);
}
}
}
}
}
Thanks again in advance!
This is on my phone so sorry for any errors.
Convert your number to a String and:
public static boolean isPalindrome(String str)
{
// base recursive case
if (str.length <= 1) {
return true;
}
// test the first and last characters
char firstChar = str.charAt(0);
char lastChar = str.charAt(str.length - 1) // subtract 1 as indexes are 0 based
if (!firstChar.equals(lastChar)) {
return false;
}
// if the string is longer than 2 chars and both are equal then recursively call with a shorter version
// start at 2nd char, end at char before last
return isPalindrome(str.substring(1,str.length);
}
Reversing integers is quite easy. Remember mod 10 gives u last digit. Loop over it, chopping off last digit of the number one at a time and adding it to reverse to new number. Then its matter of simple integer equality
int rev = 0;
int n = sum;
while(n)
{
rev = rev*10 + n%10;
n /= 10;
}
if(sum==rev)
//palindrome
else
//no no no no.
You can create a function named isPalindrome to check whether a number is a palindrome.
Use this function in your code.
You just need to pass the number you want to check into this function.
If the result is true, then the number is a palindrome.
Else, it is not a palindrome.
public static boolean isPalindrome(int number) {
int palindrome = number; // copied number into variable
int reverse = 0;
while (palindrome != 0) {
int remainder = palindrome % 10;
reverse = reverse * 10 + remainder;
palindrome = palindrome / 10;
}
// if original and reverse of number is equal means
// number is palindrome in Java
if (number == reverse) {
return true;
}
return false;
}
}
I believe that this code should help you out if you are trying to find out how many palindromes are between 100-999. Of course, it will count palindromes twice since it looks at both permutations of the palindromes. If I were you I would start creating methods to complete a majority of your work as it makes debugging much easier.
int total = 100;
StringBuilder stringSumForward;
StringBuilder stringSumBackward;
int numberOfPals = 0;
for(int i = 100; i < 999; i++){
for(int j = 100; j < 999; j++){
total = i * j;
stringSumForward = new StringBuilder(String.valueOf(total));
stringSumBackward = new StringBuilder(String.valueOf(total)).reverse();
if(stringSumForward.toString().equals(stringSumBackward.toString())){
numberOfPals++;
}
}
}

Using for loop to get the Hamming distance between 2 strings

In this task i need to get the Hamming distance (the Hamming distance between two strings of equal length is the number of positions at which the corresponding symbols are different - from Wikipedia) between the two strings sequence1 and sequence2.
First i made 2 new strings which is the 2 original strings but both with lowered case to make comparing easier. Then i resorted to using the for loop and if to compare the 2 strings. For any differences in characters in these 2 pair of string, the loop would add 1 to an int x = 0. The returns of the method will be the value of this x.
public static int getHammingDistance(String sequence1, String sequence2) {
int a = 0;
String sequenceX = sequence1.toLowerCase();
String sequenceY = sequence2.toLowerCase();
for (int x = 0; x < sequenceX.length(); x++) {
for (int y = 0; y < sequenceY.length(); y++) {
if (sequenceX.charAt(x) == sequenceY.charAt(y)) {
a += 0;
} else if (sequenceX.charAt(x) != sequenceY.charAt(y)) {
a += 1;
}
}
}
return a;
}
So does the code looks good and functional enough? Anything i could to fix or to optimize the code? Thanks in advance. I'm a huge noob so pardon me if i asked anything silly
From my point the following implementation would be ok:
public static int getHammingDistance(String sequence1, String sequence2) {
char[] s1 = sequence1.toCharArray();
char[] s2 = sequence2.toCharArray();
int shorter = Math.min(s1.length, s2.length);
int longest = Math.max(s1.length, s2.length);
int result = 0;
for (int i=0; i<shorter; i++) {
if (s1[i] != s2[i]) result++;
}
result += longest - shorter;
return result;
}
uses array, what avoids the invocation of two method (charAt) for each single char that needs to be compared;
avoid exception when one string is longer than the other.
your code is completely off.
as you said yourself, the distance is the number of places where the strings differ - so you should only have 1 loop, going over both strings at once. instead you have 2 nested loops that compare every index in string a to every index in string b.
also, writing an if condition that results in a+=0 is a waste of time.
try this instead:
for (int x = 0; x < sequenceX.length(); x++) { //both are of the same length
if (sequenceX.charAt(x) != sequenceY.charAt(x)) {
a += 1;
}
}
also, this is still a naive approach which will probbaly not work with complex unicode characters (where 2 characters can be logically equal yet not have the same character code)
public static int getHammingDistance(String sequenceX, String sequenceY) {
int a = 0;
// String sequenceX = sequence1.toLowerCase();
//String sequenceY = sequence2.toLowerCase();
if (sequenceX.length() != sequenceY.length()) {
return -1; //input strings should be of equal length
}
for (int i = 0; i < sequenceX.length(); i++) {
if (sequenceX.charAt(i) != sequenceY.charAt(i)) {
a++;
}
}
return a;
}
Your code is OK, however I'd suggest you the following improvements.
do not use charAt() of string. Get char array from string using toCharArray() before loop and then work with this array. This is more readable and more effective.
The structure
if (sequenceX.charAt(x) == sequenceY.charAt(y)) {
a += 0;
} else if (sequenceX.charAt(x) != sequenceY.charAt(y)) {
a += 1;
}
looks redundant. Fix it to:
if (sequenceX.charAt(x) == sequenceY.charAt(y)) {
a += 0;
} else {
a += 1;
}
Moreover taking into account that I recommended you to work with array change it to something like:
a += seqx[x] == seqY[x] ? 0 : 1
less code less bugs...
EDIT: as mentionded by #radai you do not need if/else structure at all: adding 0 to a is redundant.

Categories