Performance issue in String to Number conversion - java

I have space separated string containing numbers in between like:
"abc123 ws32wd3 y3tg43 5tga89 a1a"
I have to parse the string to get the numbers from each token and then sum up all the digits extracted from tokens. I have written below code, but what I think is, if there is huge string, then there might be performance issue.
So, my questions are:
How can we improve the performance in below code?
Do we have another way to write the below code to solve the problem?
Code:
public class TestSum {
public static int doSum(String str){
String[] sArray = str.split(" ");
char[] chr = null;
String temp;
String number = "";
int sum=0;
for(String s : sArray){
chr = s.toCharArray();
for(char c : chr){
temp = String.valueOf(c);
if(isNum(temp)){
number = number + temp;
}
}
sum = sum + Integer.parseInt(number);
number="";
}
return sum;
}
public static boolean isNum(String nStr){
try{
Integer.parseInt(nStr);
return true;
}catch(NumberFormatException nfe){
return false;
}
}
public static void main(String[] args) {
System.out.println("Sum is "+ TestSum.doSum("abc123 ws32wd3 y3tg43 5tga89 a1a"));
}
}

This is the fastest I could think of:
public static int getSum(String str)
{
int sum = 0;
int exp = 1;
for (int i = str.length() - 1; i >= 0; i--)
{
final char c = str.charAt(i);
if (c >= '0' && c <= '9')
{
sum += (c - '0') * exp;
exp *= 10;
}
else
{
exp = 1;
}
}
return sum;
}
It iterates through string from right to left. Thanks to that, when it "sees" a digit it can add appropriate value, depending on the decimal position "seen" in the number.
Benchmark using Caliper
Results are different than in davecom's benchmark:
AUTHOR RUNTIME (NS) HOW MANY TIMES FASTER THAN JUNS
-----------------------------------------------------------
Adam 66.221 600
Old 579.873 70
Prabhakaran 20,012.750 2 (2x faster than Juns)
Juns 39,681.074 1

You can start improving the speed of the code by eliminating your isNum() method and using the built in Character.isDigit() method.
You may be able to further improve the speed by using a regular expression to extract the numbers out of each token instead of doing it with the loops.
Best of luck.
EDIT
Comparing the performance of some of the answers here, it would seem that #Prabhakaran's answer is slower than the original, while #OldCurmudgeon's is faster, and #Adam Stelmaszczyk's is the fastest :
import java.util.*;
public class TestSum {
public static int doSum(String str){
String[] sArray = str.split(" ");
char[] chr = null;
String temp;
String number = "";
int sum=0;
for(String s : sArray){
chr = s.toCharArray();
for(char c : chr){
temp = String.valueOf(c);
if(isNum(temp)){
number = number + temp;
}
}
sum = sum + Integer.parseInt(number);
number="";
}
return sum;
}
public static boolean isNum(String nStr){
try{
Integer.parseInt(nStr);
return true;
}catch(NumberFormatException nfe){
return false;
}
}
public static void testSum1(){
String str = "abc123 ws32wd3 y3tg43 5tga89 a1a";
str = str.replaceAll("[^0-9]+", " ");
List<String> asList = Arrays.asList(str.trim().split(" "));
int sum=0;
for (String string : asList) {
sum+=Integer.parseInt(string);
}
System.out.println(sum);
}
public static int doSum2(String str) {
int sum = 0;
// -1 means not started.
int start = -1;
for ( int i = 0; i < str.length(); i++ ) {
char ch = str.charAt(i);
if ( Character.isDigit(ch)) {
if ( start == -1 ) {
// Start of a number.
start = i;
}
} else {
if ( start != -1 ) {
// End of a number.
sum += Integer.parseInt(str.substring(start, i));
start = -1;
}
}
}
if ( start != -1 ) {
// A number at the end of the string.
sum += Integer.parseInt(str.substring(start, str.length()));
}
return sum;
}
public static int getSum(String str) {
int sum = 0;
int exp = 1;
for (int i = str.length() - 1; i >= 0; i--) {
final char c = str.charAt(i);
if (c >= '0' && c <= '9'){
sum += (c - '0') * exp;
exp *= 10;
}
else{
exp = 1;
}
}
return sum;
}
public static void main(String[] args) {
long startTime = System.nanoTime();
TestSum.testSum1();
long endTime = System.nanoTime();
System.out.println("testSum1 took " + (endTime - startTime) + " nanoseconds");
startTime = System.nanoTime();
System.out.println(TestSum.doSum("abc123 ws32wd3 y3tg43 5tga89 a1a"));
endTime = System.nanoTime();
System.out.println("doSum took " + (endTime - startTime) + " nanoseconds");
startTime = System.nanoTime();
System.out.println(TestSum.doSum2("abc123 ws32wd3 y3tg43 5tga89 a1a"));
endTime = System.nanoTime();
System.out.println("doSum2 took " + (endTime - startTime) + " nanoseconds");
startTime = System.nanoTime();
System.out.println(TestSum.getSum("abc123 ws32wd3 y3tg43 5tga89 a1a"));
endTime = System.nanoTime();
System.out.println("getSum took " + (endTime - startTime) + " nanoseconds");
}
}
Here is the output
Davids-MacBook-Air:desktop dave$ javac TestSum.java
Davids-MacBook-Air:desktop dave$ java TestSum
299
testSum1 took 1790000 nanoseconds
1379
doSum took 373000 nanoseconds
299
doSum2 took 173000 nanoseconds
299
getSum took 45000 nanoseconds

For maximum performance you could try something like this:
public static int doSum(String str) {
int sum = 0;
// -1 means not started.
int start = -1;
for ( int i = 0; i < str.length(); i++ ) {
char ch = str.charAt(i);
if ( Character.isDigit(ch)) {
if ( start == -1 ) {
// Start of a number.
start = i;
}
} else {
if ( start != -1 ) {
// End of a number.
sum += Integer.parseInt(str.substring(start, i));
start = -1;
}
}
}
if ( start != -1 ) {
// A number at the end of the string.
sum += Integer.parseInt(str.substring(start, str.length()));
}
return sum;
}
prints 299 which my calculator confirms is 123+32+3+3+43+5+89+1

String str = "abc123 ws32wd3 y3tg43 5tga89 a1a";
str = str.replaceAll("[^0-9]+", " ");
List<String> asList = Arrays.asList(str.trim().split(" "));
int sum=0;
for (String string : asList) {
sum+=Integer.parseInt(string);
}
System.out.println(asList);
System.out.println(sum);
Output
str = [123, 32, 3, 3, 43, 5, 89, 1]
sum = 299

Easier solution would be parse that string with regex \d finding digits, and then go through the new string (which contains only digits) and sum up every sign (digit) in that string.
You won't even have to check if you are summing up digits, because regex will do it for you.

I think in order to speed up your conversion you can use the following trick:
int representation of number = character representation of number - '0'
So int 5 = char 5 - '0'
or in other words
int 5 = '5' - '0'
This is because of how the ASCII table is indexed.
Some (untested) code I wrote super fast to illustrate:
for(int i=0; i<str.length(); i++){
if (!(str.charAt(i).isDigit()) continue;
do {
//now handle digit parsing into a number
crtNumber= crtNumber*10 + str.charAt(i)-'0'
i++
} while(str.charAt(i).isDigit());
queue.push(crtNumber);//save the number somewhere
crtNumber= 0; //prepare for next round
}

Related

Efficient way to find longest streak of characters in string

This code works fine but I'm looking for a way to optimize it. If you look at the long string, you can see 'l' appears five times consecutively. No other character appears this many times consecutively. So, the output is 5. Now, the problem is this method checks each and every character and even after the max is found, it continues to check the remaining characters. Is there a more efficient way?
public class Main {
public static void main(String[] args) {
System.out.println(longestStreak("KDDiiigllllldddfnnlleeezzeddd"));
}
private static int longestStreak(String str) {
int max = 0;
for (int i = 0; i < str.length(); i++) {
int count = 0;
for (int j = i; j < str.length(); j++) {
if (str.charAt(i) == str.charAt(j)) {
count++;
} else break;
}
if (count > max) max = count;
}
return max;
}
}
We could add variable for previous char count in single iteration. Also as an additional optimisation we stop iteration if i + max - currentLenght < str.length(). It means that max can not be changed:
private static int longestStreak(String str) {
int maxLenght = 0;
int currentLenght = 1;
char prev = str.charAt(0);
for (int index = 1; index < str.length() && isMaxCanBeChanged(str, maxLenght, currentLenght, index); index++) {
char currentChar = str.charAt(index);
if (currentChar == prev) {
currentLenght++;
} else {
maxLenght = Math.max(maxLenght, currentLenght);
currentLenght = 1;
}
prev = currentChar;
}
return Math.max(maxLenght, currentLenght);
}
private static boolean isMaxCanBeChanged(String str, int max, int currentLenght, int index) {
return index + max - currentLenght < str.length();
}
Here is a regex magic solution, which although a bit brute force perhaps gets some brownie points. We can iterate starting with the number of characters in the original input, decreasing by one at a time, trying to do a regex replacement of continuous characters of that length. If the replacement works, then we know we found the longest streak.
String input = "KDDiiigllllldddfnnlleeezzeddd";
for (int i=input.length(); i > 0; --i) {
String replace = input.replaceAll(".*?(.)(\\1{" + (i-1) + "}).*", "$1");
if (replace.length() != input.length()) {
System.out.println("longest streak is: " + replace);
}
}
This prints:
longest streak is: lllll
Yes there is. C++ code:
string str = "KDDiiigllllldddfnnlleeezzeddd";
int longest_streak = 1, current_streak = 1; char longest_letter = str[0];
for (int i = 1; i < str.size(); ++i) {
if (str[i] == str[i - 1])
current_streak++;
else current_streak = 1;
if (current_streak > longest_streak) {
longest_streak = current_streak;
longest_letter = str[i];
}
}
cout << "The longest streak is: " << longest_streak << " and the character is: " << longest_letter << "\n";
LE: If needed, I can provide the Java code for it, but I think you get the idea.
public class Main {
public static void main(String[] args) {
System.out.println(longestStreak("KDDiiigllllldddfnnlleeezzeddd"));
}
private static int longestStreak(String str) {
int longest_streak = 1, current_streak = 1; char longest_letter = str.charAt(0);
for (int i = 1; i < str.length(); ++i) {
if (str.charAt(i) == str.charAt(i - 1))
current_streak++;
else current_streak = 1;
if (current_streak > longest_streak) {
longest_streak = current_streak;
longest_letter = str.charAt(i);
}
}
return longest_streak;
}
}
The loop could be rewritten a bit smaller, but mainly the condition can be optimized:
i < str.length() - max
Using Stream and collector. It should give all highest repeated elements.
Code:
String lineString = "KDDiiiiiiigllllldddfnnlleeezzeddd";
String[] lineSplit = lineString.split("");
Map<String, Integer> collect = Arrays.stream(lineSplit)
.collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(e -> 1)));
int maxValueInMap = (Collections.max(collect.values()));
for (Entry<String, Integer> entry : collect.entrySet()) {
if (entry.getValue() == maxValueInMap) {
System.out.printf("Character: %s, Repetition: %d\n", entry.getKey(), entry.getValue());
}
}
Output:
Character: i, Repetition: 7
Character: l, Repetition: 7
P.S I am not sure how efficient this code it. I just learned Streams.

Generating Binary Sequences

I want to generate every possible binary sequence of numbers, where each sequence in the list is limited to a specific number of 1's and there is padding of zeros to make every list the same length.
For example, if the sequence is supposed to be 4 numbers long, and have 2 ones, all sequences would be:
1100 1010 1001 0110 0101 0011
and the zeros at the front of the number are preserved.
This can be solved using recursive function calls:
public class BinarySequences {
public static void main(String[] args) {
final int numCount = 4;
final int oneCount = 2;
checkSubString(numCount, oneCount, "");
for (String res : results) {
System.out.println(res);
}
}
private static List<String> results = new ArrayList<>();
private static void checkSubString(int numCount, int oneCount, String prefix) {
if ((numCount >= oneCount) && (oneCount >= 0)) {
if (numCount==1) {
if (oneCount==1) {
results.add(prefix + "1");
} else {
results.add(prefix + "0");
}
} else {
checkSubString(numCount-1, oneCount , prefix + "0");
checkSubString(numCount-1, oneCount-1, prefix + "1");
}
}
}
}
If you want to preserve the 0s, then just add padding:
int end = 100; //Change this
for (int i = 0; i <= end; i++) {
String bytestring = Integer.toBinaryString(i);
String padding = "00000000000000000000000000000000";
bytestring = padding.substring(0, 32 - bytestring.length()) + bytestring;
System.out.println(bytestring);
}
Try this:
//Edit your min and max, e.g. Integer.MAX_VALUE and Integer.MIN_VALUE
int min = 0;
int max = 10;
for(int i = min; i < max; i++){
//Make 16 bit long binary Strings
String s = String.format("%16s", Integer.toBinaryString(i)).replace(' ', '0');
//Make 4 bits long chunks
List<String> chunks = new ArrayList<>();
Matcher matcher = Pattern.compile(".{0,4}").matcher(s);
while (matcher.find()) {
chunks.add(s.substring(matcher.start(), matcher.end()));
}
StringBuilder b = new StringBuilder();
for (String c : chunks) {
//Here you can count the 1 and 0 of the current chunk with c.charAt(index)
b.append(c);
b.append(" ");
}
System.out.println(b.toString());
}
Requires org.apache.commons.lang.StringUtils, but this makes it a short one:
final int digits = 4;
final int onesrequired = 2;
int maxindex = (int) Math.pow(2, digits);
for (int i = 0; i < maxindex; i++) {
String binaryStr = Integer.toBinaryString(i);
if (StringUtils.countMatches(binaryStr, "1") == onesrequired) {
System.out.print(String.format("%" + digits + "s", binaryStr).replace(' ', '0') + " ");
}
}

ArrayIndexOutOfBoundsException in ten's complement arithmetic implementation

My code tries to implement an algorithm to
take user input for two integer numbers and an operand + or - from the console,
store those numbers digit by digit in an int[50], representing negative ones in ten's complement format,
implement (decimal) digit-by-digit add/subtract operations,
print the result in decimal format without leading zeroes.
However, in my current implementation there are two problems
When adding 99 + 9999, the printed result is 01098 instead of the expected 010098.
When subtracting 99 - 9999, I get an ArrayIndexOutOfBoundsException: 50 instead of the expected result -09900.
import java.util.*;
public class Program9 {
public static String getOperand() {
Scanner scan = new Scanner(System.in);
String stringOfInteger;
System.out.print("Please enter an integer up to 50 numbers: ");
stringOfInteger = scan.nextLine();
return stringOfInteger;
}
public static int[] convert(String operand) {
int[] integer = new int[50];
char ch;
int position = operand.length() - 1;
for (int i = integer.length - 1; i >= 0; i--) {
if (position >= 0)
ch = operand.charAt(position--);
else
ch = 0;
if (ch >= '0' && ch <= '9') {
integer[i] = ch - '0';
} else {
integer[i] = 0;
}
}
return integer;
}
public static int[] add(int[] operand1, int[] operand2) {
int[] result = new int[operand1.length];
int carry = 0;
for (int i = operand1.length - 1; i >= 0; i--) {
result[i] = operand1[i] + operand2[i] + carry;
if (result[i] / 10 == 1) {
result[i] = result[i] % 10;
carry = 1;
} else
carry = 0;
}
return result;
}
public static int[] complement(int[] operand) {
int[] result = new int[operand.length];
for (int i = operand.length - 1; i >= 0; i--)
result[i] = 9 - operand[i];
return result;
}
public static int[] add1(int[] operand) {
int[] result = new int[50];
result[49] = 1;
for (int i = result.length - 2; i >= 0; i--)
result[i] = 0;
return result;
}
public static int[] negate(int[] operand) {
return add(add1(operand), complement(operand));
}
public static void print(int[] result, String operation) {
if (operation.charAt(0) == '+')
System.out.print("The subtotal of the two integer = ");
else if (operation.charAt(0) == '-')
System.out.print("The substraction of the two integers = ");
if (result[0] == 9) {
result = negate(result);
System.out.print("-");
for (int i = 0; i < result.length; i++) {
if (result[i] == 0 && result[i + 1] == 0)
continue;
else
System.out.print(result[i]);
}
} else
for (int i = 0; i < result.length; i++) {
if (result[i] == 0 && result[i + 1] == 0)
continue;
else
System.out.print(result[i]);
}
System.out.println();
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int[] result = new int[50];
String string1 = getOperand();
String string2 = getOperand();
int[] integer1 = convert(string1);
int[] integer2 = convert(string2);
String operation;
System.out.print("Please enter which operation will be used (+ or -): ");
operation = scan.nextLine();
if (operation.charAt(0) == '+')
add(integer1, integer2);
else if (operation.charAt(0) == '-')
integer2 = negate(integer2);
result = add(integer1, integer2);
System.out.println(Arrays.toString(integer1));
System.out.println(Arrays.toString(integer2));
System.out.println(Arrays.toString(add(integer1, integer2)));
print(result, operation);
}
}
Okay, after so much discussion and so many issues with your code I have totally revised your original code because you said you wanted to learn more. Among other improvements I have done the following changes:
Meaninfgul class name
Meaningful method and parameter names
Convert repeated and often used constants like 50 and the array representation of the number 1 (needed for negation) into static final members for clean code reasons (documentation, easy change in one place, meaningful names), runtime optimisation).
Extend the code to permit negative integers as operands
Added validation patterns for user input. E.g. now the maximum number length is checked in order to avoid an array overflow.
Avoid numeric overflows during calculation by making the array bigger than the maximum number of digits permitted for user input (see source code comments)
Add retry loops with error handling for operand and operator input, extract console handling into one parametrised method.
Simplify code by removing unnecessary checks because user input is already validated before converting it into an int[].
Make debug output optional
package de.scrum_master.stackoverflow;
import java.util.Arrays;
import java.util.Scanner;
import java.util.regex.Pattern;
public class TensComplementArithmetic {
// Print debug messages?
private static final boolean DEBUG = true;
// Maximum length for numbers entered by a user
// (number of digits excluding the optional +/- sign)
private static final int MAX_NUMBER_LENGTH = 50;
// Array must have one additional element for the sign and
// one more to avoid overflows when adding big negative numbers
private static final int ARRAY_LENGTH = MAX_NUMBER_LENGTH + 2;
// Scanner for console input handling
private static final Scanner INPUT_SCANNER = new Scanner(System.in);
// Regex pattern for positive/negative integer number format verification incl. length check
private static final Pattern INTEGER_PATTERN = Pattern.compile("[+-]?[0-9]{1," + MAX_NUMBER_LENGTH + "}");
// Regex pattern for operator verification (currently only "+"/"-" allowed)
private static final Pattern OPERATOR_PATTERN = Pattern.compile("[+-]");
// The number 1 is always needed for converting a 9's into a 10's complement
// during negation, so we define it as a reusable constant
private static final int[] NUMBER_ONE;
static {
// Initialise constant carrying array representation for number 1
NUMBER_ONE = new int[ARRAY_LENGTH];
NUMBER_ONE[ARRAY_LENGTH - 1] = 1;
}
public static String readConsoleInput(String prompt, Pattern validationPattern, String errorMessage) {
String input = null;
while (input == null) {
System.out.print(prompt + ": ");
if (INPUT_SCANNER.hasNext(validationPattern))
input = INPUT_SCANNER.next(validationPattern);
else {
INPUT_SCANNER.nextLine();
System.out.println(errorMessage);
}
}
return input;
}
public static String getOperand(String operandName) {
return readConsoleInput(
"Operand " + operandName,
INTEGER_PATTERN,
"Illegal number format, please enter a positive/negative integer of max. " + MAX_NUMBER_LENGTH + " digits."
);
}
private static String getOperator() {
return readConsoleInput(
"Arithmetical operator (+ or -)",
OPERATOR_PATTERN,
"Unknown operator, try again."
);
}
public static int[] parseInteger(String number) {
char sign = number.charAt(0);
boolean isNegative = sign == '-' ? true : false;
if (isNegative || sign == '+')
number = number.substring(1);
int[] result = new int[ARRAY_LENGTH];
int parsePosition = number.length() - 1;
for (int i = result.length - 1; i >= 0; i--) {
if (parsePosition < 0)
break;
result[i] = number.charAt(parsePosition--) - '0';
}
return isNegative ? negate(result) : result;
}
public static int[] add(int[] operand1, int[] operand2) {
int[] result = new int[ARRAY_LENGTH];
int carry = 0;
for (int i = ARRAY_LENGTH - 1; i >= 0; i--) {
result[i] = operand1[i] + operand2[i] + carry;
if (result[i] >= 10) {
result[i] = result[i] % 10;
carry = 1;
} else
carry = 0;
}
return result;
}
public static int[] complement(int[] operand) {
int[] result = new int[ARRAY_LENGTH];
for (int i = operand.length - 1; i >= 0; i--)
result[i] = 9 - operand[i];
return result;
}
public static int[] negate(int[] operand) {
return add(complement(operand), NUMBER_ONE);
}
public static void print(int[] result, String operation) {
System.out.print(operation.charAt(0) == '-' ? "Difference = " : "Sum = ");
if (result[0] == 9) {
result = negate(result);
System.out.print("-");
}
boolean leadingZero = true;
for (int i = 0; i < result.length; i++) {
if (leadingZero) {
if (result[i] == 0)
continue;
leadingZero = false;
}
System.out.print(result[i]);
}
System.out.println(leadingZero ? "0" : "");
}
public static void main(String[] args) {
int[] operand1 = parseInteger(getOperand("#1"));
int[] operand2 = parseInteger(getOperand("#2"));
String operator = getOperator();
if (operator.equals("-"))
operand2 = negate(operand2);
int[] result = new int[ARRAY_LENGTH];
result = add(operand1, operand2);
if (DEBUG) {
System.out.println("Operand #1 = " + Arrays.toString(operand1));
System.out.println("Operand #2 = " + Arrays.toString(operand2));
System.out.println("Result = " + Arrays.toString(result));
}
print(result, operator);
}
}
Disclaimer: Your source code has multiple problems, but in order to keep it simple I am going to ignore most of them now and will just explain the reasons for your current problems and suggest fixes for them only.
If you check the array outputs from your main method, you see that the addition/subtraction results look good, i.e. the problem is not located in the calculation routines but in the print routine. There you have
duplicate code: The for loops printing the positive/negative numbers are identical.
a cosmetic problem: One leading zero is always printed.
a logical error: You check for two consecutive zeroes in order to determine where leading zeroes end and the actual number begins. But you forget that
within a number there can also be duplicate zeroes, e.g. within 10098 or -9900. This explains why 10098 is printed as 1098: You are suppressing the first zero from being printed.
if there is a zero in the last array element (e.g. 9900) you cannot check the (non-existent) subsequent element without causing an ArrayIndexOutOfBoundsException. This explains why you get the exception for -9900.
Now what can/should you do?
Eliminate the redundant for loop. You can use the same loop to print both positive and negative numbers.
Use a boolean flag in order to remember if you are still looping through leading zeroes or not.
You can change your print method like so:
public static void print(int[] result, String operation) {
System.out.print(operation.charAt(0) == '-' ? "Difference = " : "Sum = ");
if (result[0] == 9) {
result = negate(result);
System.out.print("-");
}
boolean leadingZero = true;
for (int i = 0; i < result.length; i++) {
if (leadingZero) {
if (result[i] == 0)
continue;
leadingZero = false;
}
System.out.print(result[i]);
}
System.out.println(leadingZero ? "0" : "");
}
The code after fixing the problems. all thanks to #kriegaex !
import java.util.*;
public class Program9 {
public static String getOperand() {
Scanner scan = new Scanner(System.in);
String stringOfInteger;
System.out.print("Please enter an integer up to 50 numbers: ");
stringOfInteger = scan.nextLine();
return stringOfInteger;
}
public static int[] convert(String operand) {
int [] integer = new int[50];
char ch;
int position = operand.length() - 1;
for (int i = integer.length - 1; i >= 0; i--) {
if (position >= 0)
ch = operand.charAt(position--);
else
ch = 0;
if (ch >= '0' && ch <= '9') {
integer[i] = ch - '0';
} else {
integer[i] = 0;
}
}
return integer;
}
public static int[] add(int[] operand1, int[] operand2) {
int [] result = new int[operand1.length];
int carry = 0;
for (int i = operand1.length - 1; i >= 0; i--) {
result[i] = operand1[i] + operand2[i] + carry;
if (result[i] / 10 == 1) {
result[i] = result[i] % 10;
carry = 1;
} else
carry = 0;
}
return result;
}
public static int[] complement(int[] operand2){
int [] result = new int[operand2.length];
for (int i = operand2.length - 1; i >= 0; i--)
result[i] = 9 - operand2[i];
return result;
}
public static int[] add1(int[] operand2){
int [] result = new int[operand2.length];
result[operand2.length - 1] = 1;
for (int i = result.length - 2; i >= 0; i--)
result[i] = 0;
return result;
}
public static int[] negate(int[] operand2){
return add(add1(operand2), complement(operand2));
}
public static void print(int[] result, String operation) {
if (operation.charAt(0) == '+')
System.out.print("The subtotal of the two integers = ");
else if (operation.charAt(0) == '-')
System.out.print("The subtraction of the two integers = ");
if (result[0] == 9) {
result = negate(result);
System.out.print("-");
}
boolean leadingZero = true;
for (int i = 0; i < result.length; i++) {
if (leadingZero) {
if (result[i] == 0)
continue;
leadingZero = false;
}
System.out.print(result[i]);
}
if (leadingZero == true)
System.out.println('0' - '0');
System.out.println();
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int [] result = new int[50];
String string1 = getOperand();
String string2 = getOperand();
int [] integer1 = convert(string1);
int [] integer2 = convert(string2);
String operation;
System.out.print("Please enter which operation will be used (+ or -): ");
operation = scan.nextLine();
if (operation.charAt(0) == '+')
add(integer1, integer2);
else if (operation.charAt(0) == '-')
integer2 = negate(integer2);
result = add(integer1, integer2);
System.out.println(Arrays.toString(integer1));
System.out.println(Arrays.toString(integer2));
System.out.println(Arrays.toString(add(integer1, integer2)));
print(result, operation);
}
}

Class assignment requires me to have two versions of the same code. This one, and one using BigInteger. Need help converting to BigInteger

I am required specifically to use BigInteger in place of long. This is so if the fibonacci number is too large, it won't return a negative. We haven't done some of the more complicated functions that java has built in, so I'm going to have to do it as simple as possible.
import java.util.Scanner;
public class FibBigInt{
public static long fib_l(int n){
long result = 0;
long f0 = 1, f1 = 1;
while(n > 0){
f0 = f1;
f1 = result;
result = f0 + f1;
n--;
}
return result;
}
public static long fib_r(int n){
long result = 1;
if(n <= 2){
return result;
}
else{
result = fib_r(n - 1) + fib_r(n - 2);
}
return result;
}
public static long fval[];
public static long fib_r_Memo(int n){
long result = 1;
if(n > 2) {
if(fval[n] != 0){
result = fval[n];
}
else{
result = fib_r_Memo(n - 1) + fib_r_Memo(n - 2);
fval[n] = result;
}
}
return result;
}
public static void main(String [] args){
Scanner s = new Scanner(System.in);
System.out.print("Please enter an integer: ");
int n = s.nextInt();
long t1 = System.currentTimeMillis();
//System.out.println("Fibonacci number " + n + " is " + fib_l(n));
//System.out.println("Fibonacci number " + n + " is " + fib_r(n));
fval = new long[n + 1];
for(int i = 0; i < fval.length; ++i){
fval[i] = 0;
}
System.out.println("Fibonacci number " + n + " is " + fib_r_Memo(n));
long t2 = System.currentTimeMillis();
System.out.println("Elapsed time: " + (t2 - t1)/1000 + " seconds. ");
}
}
Here is an example recursive BigInteger version using a memoization optimization and supporting the "negafibonacci",
private static Map<Integer, BigInteger> memo = new TreeMap<>();
private static final BigInteger NEGATIVE_ONE = new BigInteger("-1");
public static BigInteger fib(final int n) {
if (n < 0) {
// This if block adds the "negafibonacci" support.
final int p = Math.abs(n);
final boolean even = p % 2 == 0;
if (even) {
return NEGATIVE_ONE.multiply(fib(p));
}
return fib(p);
} else if (n == 0) {
return BigInteger.ZERO;
} else if (n == 1 || n == 2) {
return BigInteger.ONE;
}
if (memo.containsKey(n)) {
return memo.get(n);
}
BigInteger r = fib(n - 1).add(fib(n - 2));
memo.put(n, r);
return r;
}
public static void main(String[] args) {
for (int i = -8; i <= 8; i++) {
System.out.println(fib(i).toString());
}
}
When I run the above I get a sequence that matches the one from Wikipedia -
−21 13 −8 5 −3 2 −1 1 0 1 1 2 3 5 8 13 21
Finally, I created a simple benchmark -
public static void main(String[] args) {
long current = System.currentTimeMillis();
for (int i = 1; i < 1000; i++) {
System.out.println(fib(i));
}
long end = System.currentTimeMillis();
System.out.printf("Ran in: %d milliseconds", end - current);
}
When I calculate the first 999 fibonacci numbers it completes in under 200 milliseconds. If you really wanted to optimize further you could look into the Closed-form Expression.

Manually converting a string to an integer in Java

I'm having string consisting of a sequence of digits (e.g. "1234"). How to return the String as an int without using Java's library functions like Integer.parseInt?
public class StringToInteger {
public static void main(String [] args){
int i = myStringToInteger("123");
System.out.println("String decoded to number " + i);
}
public int myStringToInteger(String str){
/* ... */
}
}
And what is wrong with this?
int i = Integer.parseInt(str);
EDIT :
If you really need to do the conversion by hand, try this:
public static int myStringToInteger(String str) {
int answer = 0, factor = 1;
for (int i = str.length()-1; i >= 0; i--) {
answer += (str.charAt(i) - '0') * factor;
factor *= 10;
}
return answer;
}
The above will work fine for positive integers, if the number is negative you'll have to do a little checking first, but I'll leave that as an exercise for the reader.
If the standard libraries are disallowed, there are many approaches to solving this problem. One way to think about this is as a recursive function:
If n is less than 10, just convert it to the one-character string holding its digit. For example, 3 becomes "3".
If n is greater than 10, then use division and modulus to get the last digit of n and the number formed by excluding the last digit. Recursively get a string for the first digits, then append the appropriate character for the last digit. For example, if n is 137, you'd recursively compute "13" and tack on "7" to get "137".
You will need logic to special-case 0 and negative numbers, but otherwise this can be done fairly simply.
Since I suspect that this may be homework (and know for a fact that at some schools it is), I'll leave the actual conversion as an exercise to the reader. :-)
Hope this helps!
Use long instead of int in this case.
You need to check for overflows.
public static int StringtoNumber(String s) throws Exception{
if (s == null || s.length() == 0)
return 0;
while(s.charAt(0) == ' '){
s = s.substring(1);
}
boolean isNegative = s.charAt(0) == '-';
if (s.charAt(0) == '-' || (s.charAt(0) == '+')){
s = s.substring(1);
}
long result = 0l;
for (int i = 0; i < s.length(); i++){
int value = s.charAt(i) - '0';
if (value >= 0 && value <= 9){
if (!isNegative && 10 * result + value > Integer.MAX_VALUE ){
throw new Exception();
}else if (isNegative && -1 * 10 * result - value < Integer.MIN_VALUE){
throw new Exception();
}
result = 10 * result + value;
}else if (s.charAt(i) != ' '){
return (int)result;
}
}
return isNegative ? -1 * (int)result : (int)result;
}
Alternate approach to the answer already posted here. You can traverse the string from the front and build the number
public static void stringtoint(String s){
boolean isNegative=false;
int number =0;
if (s.charAt(0)=='-') {
isNegative=true;
}else{
number = number* 10 + s.charAt(0)-'0';
}
for (int i = 1; i < s.length(); i++) {
number = number*10 + s.charAt(i)-'0';
}
if(isNegative){
number = 0-number;
}
System.out.println(number);
}
Given the right hint, I think most people with a high school education can solve this own their own. Every one knows 134 = 100x1 + 10x3 + 1x4
The key part most people miss, is that if you do something like this in Java
System.out.println('0'*1);//48
it will pick the decimal representation of character 0 in ascii chart and multiply it by 1.
In ascii table character 0 has a decimal representation of 48. So the above line will print 48. So if you do something like '1'-'0' That is same as 49-48. Since in ascii chart, characters 0-9 are continuous, so you can take any char from 0 to 9 and subtract 0 to get its integer value. Once you have the integer value for a character, then converting the whole string to int is straight forward.
Here is another one solution to the problem
String a = "-12512";
char[] chars = a.toCharArray();
boolean isNegative = (chars[0] == '-');
if (isNegative) {
chars[0] = '0';
}
int multiplier = 1;
int total = 0;
for (int i = chars.length - 1; i >= 0; i--) {
total = total + ((chars[i] - '0') * multiplier);
multiplier = multiplier * 10;
}
if (isNegative) {
total = total * -1;
}
Use this:
static int parseInt(String str) {
char[] ch = str.trim().toCharArray();
int len = ch.length;
int value = 0;
for (int i=0, j=(len-1); i<len; i++,j--) {
int c = ch[i];
if (c < 48 || c > 57) {
throw new NumberFormatException("Not a number: "+str);
}
int n = c - 48;
n *= Math.pow(10, j);
value += n;
}
return value;
}
And by the way, you can handle the special case of negative integers, otherwise it will throw exception NumberFormatException.
You can do like this: from the string, create an array of characters for each element, keep the index saved, and multiply its ASCII value by the power of the actual reverse index. Sum the partial factors and you get it.
There is only a small cast to use Math.pow (since it returns a double), but you can avoid it by creating your own power function.
public static int StringToInt(String str){
int res = 0;
char [] chars = str.toCharArray();
System.out.println(str.length());
for (int i = str.length()-1, j=0; i>=0; i--, j++){
int temp = chars[j]-48;
int power = (int) Math.pow(10, i);
res += temp*power;
System.out.println(res);
}
return res;
}
Using Java 8 you can do the following:
public static int convert(String strNum)
{
int result =strNum.chars().reduce(0, (a, b)->10*a +b-'0');
}
Convert srtNum to char
for each char (represented as 'b') -> 'b' -'0' will give the relative number
sum all in a (initial value is 0)
(each time we perform an opertaion on a char do -> a=a*10
Make use of the fact that Java uses char and int in the same way. Basically, do char - '0' to get the int value of the char.
public class StringToInteger {
public static void main(String[] args) {
int i = myStringToInteger("123");
System.out.println("String decoded to number " + i);
}
public static int myStringToInteger(String str) {
int sum = 0;
char[] array = str.toCharArray();
int j = 0;
for(int i = str.length() - 1 ; i >= 0 ; i--){
sum += Math.pow(10, j)*(array[i]-'0');
j++;
}
return sum;
}
}
public int myStringToInteger(String str) throws NumberFormatException
{
int decimalRadix = 10; //10 is the radix of the decimal system
if (str == null) {
throw new NumberFormatException("null");
}
int finalResult = 0;
boolean isNegative = false;
int index = 0, strLength = str.length();
if (strLength > 0) {
if (str.charAt(0) == '-') {
isNegative = true;
index++;
}
while (index < strLength) {
if((Character.digit(str.charAt(index), decimalRadix)) != -1){
finalResult *= decimalRadix;
finalResult += (str.charAt(index) - '0');
} else throw new NumberFormatException("for input string " + str);
index++;
}
} else {
throw new NumberFormatException("Empty numeric string");
}
if(isNegative){
if(index > 1)
return -finalResult;
else
throw new NumberFormatException("Only got -");
}
return finalResult;
}
Outcome:
1) For the input "34567" the final result would be: 34567
2) For the input "-4567" the final result would be: -4567
3) For the input "-" the final result would be: java.lang.NumberFormatException: Only got -
4) For the input "12ab45" the final result would be: java.lang.NumberFormatException: for input string 12ab45
public static int convertToInt(String input){
char[] ch=input.toCharArray();
int result=0;
for(char c : ch){
result=(result*10)+((int)c-(int)'0');
}
return result;
}
Maybe this way will be a little bit faster:
public static int convertStringToInt(String num) {
int result = 0;
for (char c: num.toCharArray()) {
c -= 48;
if (c <= 9) {
result = (result << 3) + (result << 1) + c;
} else return -1;
}
return result;
}
This is the Complete program with all conditions positive, negative without using library
import java.util.Scanner;
public class StringToInt {
public static void main(String args[]) {
String inputString;
Scanner s = new Scanner(System.in);
inputString = s.nextLine();
if (!inputString.matches("([+-]?([0-9]*[.])?[0-9]+)")) {
System.out.println("error!!!");
} else {
Double result2 = getNumber(inputString);
System.out.println("result = " + result2);
}
}
public static Double getNumber(String number) {
Double result = 0.0;
Double beforeDecimal = 0.0;
Double afterDecimal = 0.0;
Double afterDecimalCount = 0.0;
int signBit = 1;
boolean flag = false;
int count = number.length();
if (number.charAt(0) == '-') {
signBit = -1;
flag = true;
} else if (number.charAt(0) == '+') {
flag = true;
}
for (int i = 0; i < count; i++) {
if (flag && i == 0) {
continue;
}
if (afterDecimalCount == 0.0) {
if (number.charAt(i) - '.' == 0) {
afterDecimalCount++;
} else {
beforeDecimal = beforeDecimal * 10 + (number.charAt(i) - '0');
}
} else {
afterDecimal = afterDecimal * 10 + number.charAt(i) - ('0');
afterDecimalCount = afterDecimalCount * 10;
}
}
if (afterDecimalCount != 0.0) {
afterDecimal = afterDecimal / afterDecimalCount;
result = beforeDecimal + afterDecimal;
} else {
result = beforeDecimal;
}
return result * signBit;
}
}
Works for Positive and Negative String Using TDD
//Solution
public int convert(String string) {
int number = 0;
boolean isNegative = false;
int i = 0;
if (string.charAt(0) == '-') {
isNegative = true;
i++;
}
for (int j = i; j < string.length(); j++) {
int value = string.charAt(j) - '0';
number *= 10;
number += value;
}
if (isNegative) {
number = -number;
}
return number;
}
//Testcases
public class StringtoIntTest {
private StringtoInt stringtoInt;
#Before
public void setUp() throws Exception {
stringtoInt = new StringtoInt();
}
#Test
public void testStringtoInt() {
int excepted = stringtoInt.convert("123456");
assertEquals(123456,excepted);
}
#Test
public void testStringtoIntWithNegative() {
int excepted = stringtoInt.convert("-123456");
assertEquals(-123456,excepted);
}
}
//Take one positive or negative number
String str="-90997865";
//Conver String into Character Array
char arr[]=str.toCharArray();
int no=0,asci=0,res=0;
for(int i=0;i<arr.length;i++)
{
//If First Character == negative then skip iteration and i++
if(arr[i]=='-' && i==0)
{
i++;
}
asci=(int)arr[i]; //Find Ascii value of each Character
no=asci-48; //Now Substract the Ascii value of 0 i.e 48 from asci
res=res*10+no; //Conversion for final number
}
//If first Character is negative then result also negative
if(arr[0]=='-')
{
res=-res;
}
System.out.println(res);
public class ConvertInteger {
public static int convertToInt(String numString){
int answer = 0, factor = 1;
for (int i = numString.length()-1; i >= 0; i--) {
answer += (numString.charAt(i) - '0') *factor;
factor *=10;
}
return answer;
}
public static void main(String[] args) {
System.out.println(convertToInt("789"));
}
}

Categories

Resources