I have an assignment to create my own implementation of a class to handle integers of unlimited size, and then to compare my implementation's runtime to that of Java's BigInteger. When I measured and graphed the runtime of my add function it was a parabola, implying a big theta running time of Ө(n^2). I have no nested loops so I expected it to be Ө(n) and cannot figure out why it isn't. I suspect it might be that I use
string += integer
in my add method inside a loop. I am not quite sure how that operation is implemented, is it a runtime of Ө(n)? If not, can anyone spot why my code isn't Ө(n)?
Here is my add method and the constructor it calls.
public HugeInteger(String val) throws IllegalArgumentException{
String temp = "";
boolean leading = true;
//check valid input
for(int i=0; i<val.length(); i++){
if(val.charAt(i) < '0' || val.charAt(i) > '9') //checks if each digit is a number from 0 to 9
if(i!=0 || val.charAt(i) != '-') //doesn't throw if the digit is a '-' at the first character of string
throw new IllegalArgumentException("Input string must be a number");
}
//remove leading zeros
for(int i=0; i<val.length(); i++){
if(!leading || val.charAt(i) != '0')
temp += val.charAt(i);
if(val.charAt(i) > '0' && val.charAt(i) <= '9') //reached first non-zero digit
leading = false;
}
if(temp == "") //this happens when the input was just a string of zeros
temp = "0";
val = temp;
if(val.charAt(0) != '-'){ //no negative sign
digits = new int[val.length()];
for(int i=0; i<val.length(); i++){
digits[i] = (int)(val.charAt(val.length()-1-i) - 48); //in ASCII the char '0' == 48
}
negative = false;
}
else{
digits = new int[val.length() - 1];
for(int i=1; i<val.length(); i++){ //for loop starts after the '-' sign
digits[i-1] = (int)(val.charAt(val.length()-i) - 48); //in ASCII the char '0' == 48
}
negative = true;
}
}
public HugeInteger add(HugeInteger h){
int carry = 0;
int size = digits.length>h.digits.length?digits.length:h.digits.length; //choose larger # of digits
String sum = "";
String sumFlipped = "";
int bigger = 0;
boolean swapped = false;
int temp;
int sign = 1;
int hsign = 1;
//assign sign based on negative or not
if(negative && !h.negative)
sign = -1;
if(!negative && h.negative)
hsign = -1;
//compare magnitudes. 1 means this is biger and -1 means h is bigger
if(digits.length>h.digits.length)
bigger = 1;
else if(digits.length<h.digits.length)
bigger = -1;
else{ //same length
for(int i=0; i<digits.length; i++){ //both digits arrays are same length
if(digits[digits.length-1-i] > h.digits[h.digits.length-1-i]){
bigger = 1;
break;
}
if(digits[digits.length-1-i] < h.digits[h.digits.length-1-i]){
bigger = -1;
break;
}
}
}
//positive number must be bigger than negative number for long subtraction
//if not, swap signs
if(bigger == 1 && negative && !h.negative){ //this is bigger and negative
swapped = true;
sign *= -1;
hsign *= -1;
}
if(bigger == -1 && !negative && h.negative){ //h is bigger and negative
swapped = true;
sign *= -1;
hsign *= -1;
}
for(int i=0; i<size; i++){
if(i>=digits.length)
temp = h.digits[i]*hsign + carry;
else if(i>=h.digits.length)
temp = digits[i]*sign + carry;
else
temp = digits[i]*sign + h.digits[i]*hsign + carry;
if(temp>9){ //adds the digit to the string, then increments carry which is used in next iteration
temp -= 10;
sum += temp;
carry = 1;
}
else if(temp<0){
temp += 10;
carry = -1;
sum += temp;
}
else{
sum += temp;
carry = 0;
}
}
if(carry == 1)
sum += 1;
if(negative && h.negative || swapped)
sum += '-';
//flip string around
for(int i=0; i < sum.length(); i++){
sumFlipped += sum.charAt(sum.length() - 1 - i);
}
HugeInteger sumHugeInteger = new HugeInteger(sumFlipped);
return sumHugeInteger;
}
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.
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
So in my last question's code was an error. I tried to modify the code which should add two big numbers made as two arrays (I can't use BigIntiger for this, I have to made the method by myself). But it still gives me wrong results of addition.
For example (I already have the constructors for this):
BigNumber dl1 = new BigNumber(1500);
BigNumber dl2 = new BigNumber("987349837937497938943242");
dl3 = dl1.add(dl2);
System.out.println("Result: " + dl3);
It gives me 6575 which is wrong result.
public BigNumber add(BigNumber num2){
char[] m = null;
long y = 0;
long x = 0;
boolean tmpBool = false;
boolean leftIsBigger = false;
String tmpString = "";
int ending = 0;
if (this.n.length >= num2.n.length){
m = new char[this.n.length + 1];
y = num2.n.length;
x = this.n.length;
leftIsBigger = true;
}
else{
m = new char[this.n.length + 1];
y = this.n.length;
x = num2.n.length;
}
for(int i = 0; i < y; i++){
int left = 0;
if(leftIsBigger) left = Character.getNumericValue(this.n[i]);
else left = Character.getNumericValue(num2.n[i]);
for(int j = 0; j < y; j++){
int right = 0;
if(!leftIsBigger) right = Character.getNumericValue(num2.n[j]);
else righta = Character.getNumericValue(this.n[j]);
int z = left + right;
if(tmpBool){
z++;
tmpBool = false;
}
if(z > 9){
tmpBool = true;
z = z%10;
}
m[i] = Character.forDigit(z, 10);
}
ending++;
}
for(int k = ending; k < m.length - 1; k++){
if (leftIsBigger){
if (tmpBool){
int c = Character.getNumericValue(this.n[k]);
if (c > 9){
tmpBool = true;
c = c%10;
m[k] = Character.forDigit(c, 10);
}
else{
tmpBool = false;
m[k] = Character.forDigit((c+1), 10);
}
}
else
m[k] = this.n[k];
}else{
if (tmpBool){
int c = Character.getNumericValue(liczba2.n[k]);
if (c > 9){
tmpBool = true;
c = c%10;
m[k] = Character.forDigit(c, 10);
}
else{
tmpBool = false;
m[k] = Character.forDigit((c+1), 10);
}
}
else
m[k] = this.n[k];
}
}
for (int it = m.length - 1; it >= 0; it--){
tmpString += m[it];
}
BigNumber dl = new BigNumber(tmpString);
return dl;
}
Isn't the problem that in your initial if statement (The one that checks the lengths of the inner arrays) in the else you initialize your m char array to the length of this.n instead of num2.n?
EDIT: Also, the way you've setup your iterations, I assume your inner arrays go from left to right? as in Index 0 is 10^0, index 1 is 10^1, index 2 is 10^2 etc? Otherwise that would be a problem as well. Be mindful that this means you have to revert the inner String char array in the String type constructor.
Your code is too complicated for me to search for the error. The whole "left is longer" logic is flawed, IMHO.
I'd do it thus, assuming we are working on char-Arrays with decimal digits in them:
char [] x, y; // the operands we want to add
char [] result = new char[max (x.length, y.length) + 1];
int xi = x.length-1; // index in 1st operand
int yi = y.length-1; // index in 2nd operand
int ri = result.length-1; // index in result
boolean carry = false;
while (xi >= 0 || yi >= 0) {
char xc = xi >= 0 ? x[xi--] : '0';
char yc = yi >= 0 ? y[yi--] : '0';
char res = xc + yc - '0';
if (carry) res++;
carry = res > '9';
if (carry) res -= 10;
result[ri--] = res;
}
assert (ri == 0);
result[0] = carry ? '1' : '0';
Note that the result array is always 1 char longer than the longest argument. This is not good, as repeated additions will result in longer and longer arrays that carry a lot of 0 in front.
Hence, either copy the result to another array if the last addition did not have a carry bit, or - even better - change the algorithm so that it ignores leading zeroes.
This is left as an exercise.
import java.lang.Integer;
import java.util.Arrays;
public class Decimal {
//initialize intance variables
private int decimal;
private String hex;
public static void toHex(String s) {
int decimal = Integer.parseInt(s); //converts the s string into an int for binary conversion.
String hex = null;
int[] binNum = new int[16];
int[] binNumNibble = new int[4]; //A nibble is four bits.
int nibbleTot = 0;
char hexDig = '\0';
char[] cvtdHex = new char[4];
StringBuffer result = new StringBuffer();
for(int a = 32768; a == 1; a /= 2) { //32768 is the value of the largest bit.
int b = 0;//Will top at 15 at the end of the for loop. 15 references the last spot in the binNum array.
if(decimal > a) {
decimal -= a;
binNum[b++] = 1;//Arrays have a default value of zero to all elements. This provides a parsed binary number.
}
}
for(int a = 0; a == 15; a += 3) {
//Copies pieces of the binary number to the binNumNibble array. .arraycopy is used in java 1.5 and lower.
//Arrays.copyOfRange is used in java 1.5 and higher.
System.arraycopy(binNum, a, binNumNibble, 0, 4);
for(int b = 8; b == 1; a += 3) {
int c = 0;
nibbleTot += binNumNibble[c++];
//Converts the single hex value into a hex digit.
if(nibbleTot >= 1 && nibbleTot <= 9) {
hexDig += nibbleTot;
} else if(nibbleTot == 10) {
hexDig = 'A';
} else if(nibbleTot == 11) {
hexDig = 'B';
} else if(nibbleTot == 12) {
hexDig = 'C';
} else if(nibbleTot == 13) {
hexDig = 'D';
} else if(nibbleTot == 14) {
hexDig = 'E';
} else if(nibbleTot == 15) {
hexDig = 'F';
}
cvtdHex[c++] = hexDig;
}
}
//return hex = new String(cvtdHex);
hex = new String(cvtdHex);
System.out.print("Hex: " + hex);
}
}
I can't seem to figure out why variable hex is returned as a blank variable. I've been using System.out.print(); in each for loop and none of them are used, giving me the impression that the for loops are being skipped entirely, but I don't understand why and I'm on a time limit.
Any help is much appreciated, but please don't just paste code. I need to understand this for my computer science class!
yes, your for loops ARE being skipped, since the second part of the for statement is not the break condition but the condition that has to be fullfilled for the loop to run.
So it is NOT
for(a = 0; a == 15; a += 3)
but
for(a = 0; a <= 15; a += 3)
and so on...
The for loops wont execute because of the double ==
How about
String.format("%h", 256)
I need to add 8 numbers together from a string.E.g. If someone enters say 1234 it will add the numbers together 1 + 2 + 3 + 4 = 10 then 1 + 1 = 2. I have done this so far. I cannot figure out how to add these numbers up using a for loop.
String num2;
String num3;
num2 = (jTextField1.getText());
num3 = num2.replaceAll("[/:.,-0]", "");
String[] result = num3.split("");
int inte = Integer.parseInt(num3);
for (int i = 0; i < 8; i++){
// Stuck
}
How about that (I skipped exceptions...):
String[] sNums = jTextField1.getText().replaceAll("[^1-9]", "").split("(?<!^)");
int sum = 0;
for (String s : sNums) {
sum += Integer.parseInt(s); // add all digits
}
while (sum > 9) { // add all digits of the number, until left with one-digit number
int temp = 0;
while (sum > 0) {
temp += sum % 10;
sum = sum / 10;
}
sum = temp;
}
For every element in result, you need to convert it to an int, then add it to some variable, maybe called sum.
int sum = 0;
// for every String in the result array
for (int i = 0; i < BOUND; i++) {
// convert s[i] to int value
// add the int value to sum
}
This pseudo code should do it without splitting, arrays etc.
String s = "1234.56";
int sum = 0;
int i = 0;
while (i < s.length()) {
char c = s.charAt(i)
if (c >= '0' && c <= '9') sum += c - '0';
i++;
}
Should result in sum = 21
public static int addAll(String str) {
str = str.replaceAll("[^1-9]", "");
if (str.length() == 0)
return 0;
char[] c = str.toCharArray();
Integer result = c[0] - 48;
while (c.length > 1) {
result = 0;
for (int i = 0; i < c.length; i++) {
result += c[i] - 48;
}
c = result.toString().toCharArray();
}
return result;
}