BigInteger Homework Help Needed - java

I have been told I have to write a BigInteger class, I know there is one, but I have to write my own. I am to take either ints or a string and turn them into arrays to store them. From there I am to then allow adding, subtract, and multiplying of the numbers. I have it taking the ints and the string and making the arrays that was fine. I am having issues with the rest.
For the add, I have tried to make something that checks the size of the type arrays of numbers, and then sets which is smaller and bigger. From there I have it looping till it gets to the end of the smaller one, and as it loops it takes the digit at that part of the array for the two numbers and adds them. Now this is ok till they are greater then 10, in which case I need to carryover a number. I think I had that working at a point too.
Keep in mind the two things my BigInt has is the array of the number and an int for the sign, 1 or -1.
So in this case I am having issues with it adding right and the sign being right. Same with subtracting.
As for multiplying, I am completely lost on that, and haven't even tried. Below is some of the code I have tried making: ( the add function), PLEASE HELP ME.
public BigInt add(BigInt val){
int[] bigger;
int[] smaller;
int[] dStore;
int carryOver = 0;
int tempSign = 1;
if(val.getSize() >= this.getSize()){
bigger = val.getData();
smaller = this.getData();
dStore = new int[val.getSize()+2];
if(val.getSign() == 1){
tempSign = 1;
}else{
tempSign = -1;
}
}else{
bigger = this.getData();
smaller = val.getData();
dStore = new int[this.getSize()+2];
if(this.getSign() == 1){
tempSign = 1;
}else{
tempSign = -1;
}
}
for(int i=0;i<smaller.length;i++){
if((bigger[i] < 0 && smaller[i] < 0) || (bigger[i] >= 0 && smaller[i] >= 0)){
dStore[i] = Math.abs(bigger[i]) + Math.abs(smaller[i]) + carryOver;
}else if((bigger[i] <= 0 || smaller[i] <= 0) && (bigger[i] > 0 || smaller[i] > 0)){
dStore[i] = bigger[i] + smaller[i];
dStore[i] = Math.abs(dStore[i]);
}
if(dStore[i] >= 10){
dStore[i] = dStore[i] - 10;
if(i == smaller.length - 1){
dStore[i+1] = 1;
}
carryOver = 1;
}else{
carryOver = 0;
}
}
for(int i = smaller.length;i<bigger.length;i++){
dStore[i] = bigger[i];
}
BigInt rVal = new BigInt(dStore);
rVal.setSign(tempSign);
return rVal;

if you know how to add and multiply big numbers by hand, implementing those algorithms in Java won't be difficult.

If their signs differ, you'll need to actually subtract the digits (and borrow if appropriate). Also, it looks like your carry function doesn't work to carry past the length of the smaller number (the carried "1" gets overwritten).
To go further into signs, you have a few different cases (assume that this is positive and val is negative for these cases):
If this has more digits, then you'll want to subtract val from this, and the result will be positive
If val has more digits, then you'll want to subtract this from val, and the result will be negative
If they have the same number of digits, you'll have to scan to find which is larger (start at the most significant digit).
Of course if both are positive then you just add as normal, and if both are negative you add, then set the result to be negative.

Now that we know the numbers are stored in reverse...
I think your code works if the numbers both have the same sign. I tried the following test cases:
Same length, really basic test.
Same length, carryover in the middle.
Same length, carryover at the end.
Same length, carryover in the middle and at the end
First number is longer, carryover in the middle and at the end
Second number is longer, carryover in the middle and at the end
Both negative, first number is longer, carryover in the middle and at the end
This all worked out just fine.
However, when one is positive and one is negative, it doesn't work properly.
This isn't too surprising, because -1 + 7 is actually more like subtraction than addition. You should think of it as 7-1, and it'll be much easier for you if you check for this case and instead call subtraction.
Likewise, -1 - 1 should be considered addition, even though it looks like subtraction.

I've actually written a big numbers library in assembly some years ago; i can add the multiplication code here if that helps. My advice to you is not try to write the functions on your own. There are already known ways to add, substract, multiply, divide, powmod, xgcd and more with bignumbers. I remember that i was reading Bruce Schneier's Applied Cryptography book to do that and The Art of Assembly by Randall Hyde. Both have the needed algorithms to do that (in pseudocode also). I would highly advice that you take a look, especially to the second one that it's an online free resource.

Related

How to properly handle max/min int value edge case-Java

I am working on a problem from LeetCode (not an interview question just practicing) that asks the following:
Given a sorted integer array nums, where the range of elements are in the inclusive range [lower, upper], return its missing ranges.
The code that I came up with fails for inputs where the nums array is [-2147483648,2147483647] and lower/upper are -2147483648/2147483647 respectively. The part of my code that actually answers the question is:
if (nums[0]-lower > 1) {
String range = lower + "->" + (nums[0]-1);
ans.add(range);
}
else if (nums[0]-lower == 1) {
String range = new Integer(lower).toString();
ans.add(range);
}
for (int i = 1; i < nums.length; i++) {
if (nums[i] - nums[i-1] > 2) {
String range = nums[i-1]+1 + "->" + (nums[i]-1);
ans.add(range);
}
else if (nums[i] - nums[i-1] == 2) {
String range = new Integer(nums[i]-1).toString();
ans.add(range);
}
}
I was wondering how best to handle this edge case, not just for this question but generally. Do I just add extra if-statements to my code to specifically handle these two numbers (or if addition/subtraction of numbers causes the int value to overflow) or is there a more elegant way to handle this?
The maximum value of an int is 231-1 which is 2147483647, but the difference between that number and any negative number is larger than that number itself.
So all your subtraction expressions like nums[0]-lower overflow with [-2147483648,2147483647] (or [-1,2147483647]).
You can check it with this:
System.out.println(2147483647 - -1);
This prints out -2147483648 even though you would expect it to be 2147483648.
One easy fix is to do the calculations as a 64-bit long. Change all your subtractions like below to cast the expression to long.
if (nums[0] - (long)lower > 1) {
Take the above example and change it to:
System.out.println(2147483647 - (long) -1);
This will correctly print 2147483648.

Luhn checksum validation in Java

I have to replicate the luhn algorithm in Java, the problem I face is how to implement this in an efficient and elegant way (not a requirement but that is what I want).
The luhn-algorithm works like this:
You take a number, let's say 56789
loop over the next steps till there are no digits left
You pick the left-most digit and add it to the total sum. sum = 5
You discard this digit and go the next. number = 6789
You double this digit, if it's more than one digit you take apart this number and add them separately to the sum. 2*6 = 12, so sum = 5 + 1 = 6 and then sum = 6 + 2 = 8.
Addition restrictions
For this particular problem I was required to read all digits one at a time and do computations on each of them separately before moving on. I also assume that all numbers are positive.
The problems I face and the questions I have
As said before I try to solve this in an elegant and efficient way. That's why I don't want to invoke the toString() method on the number to access all individual digits which require a lot of converting. I also can't use the modulo kind of way because of the restriction above that states once I read a number I should also do computations on it right away. I could only use modulo if I knew in advance the length of the String, but that feels like I first have to count all digits one-for-once which thus is against the restriction. Now I can only think of one way to do this, but this would also require a lot of computations and only ever cares about the first digit*:
int firstDigit(int x) {
while (x > 9) {
x /= 10;
}
return x;
}
Found here: https://stackoverflow.com/a/2968068/3972558
*However, when I think about it, this is basically a different and weird way to make use of the length property of a number by dividing it as often till there is one digit left.
So basically I am stuck now and I think I must use the length property of a number which it does not really have, so I should find it by hand. Is there a good way to do this? Now I am thinking that I should use modulo in combination with the length of a number.
So that I know if the total number of digits is uneven or even and then I can do computations from right to left. Just for fun I think I could use this for efficiency to get the length of a number: https://stackoverflow.com/a/1308407/3972558
This question appeared in the book Think like a programmer.
You can optimise it by unrolling the loop once (or as many times are you like) This will be close to twice as fast for large numbers, however make small numbers slower. If you have an idea of the typical range of numbers you will have you can determine how much to unroll this loop.
int firstDigit(int x) {
while (x > 99)
x /= 100;
if (x > 9)
x /= 10;
return x;
}
use org.apache.commons.validator.routines.checkdigit.LuhnCheckDigit . isValid()
Maven Dependency:
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.4.0</version>
</dependency>
Normally you would process the numbers from right to left using divide by 10 to shift the digits and modulo 10 to extract the last one. You can still use this technique when processing the numbers from left to right. Just use divide by 1000000000 to extract the first number and multiply by 10 to shift it left:
0000056789
0000567890
0005678900
0056789000
0567890000
5678900000
6789000000
7890000000
8900000000
9000000000
Some of those numbers exceed maximum value of int. If you have to support full range of input, you will have to store the number as long:
static int checksum(int x) {
long n = x;
int sum = 0;
while (n != 0) {
long d = 1000000000l;
int digit = (int) (n / d);
n %= d;
n *= 10l;
// add digit to sum
}
return sum;
}
As I understand, you will eventually need to read every digit, so what is wrong with convert initial number to string (and therefore char[]) and then you can easily implement the algorithm iterating that char array.
JDK implementation of Integer.toString is rather optimized so that you would need to implement your own optimalizations, e.g. it uses different lookup tables for optimized conversion, convert two chars at once etc.
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE };
// Requires positive x
static int stringSize(int x) {
for (int i=0; ; i++)
if (x <= sizeTable[i])
return i+1;
}
This was just an example but feel free to check complete implementation :)
I would first convert the number to a kind of BCD (binary coded decimal). I'm not sure to be able to find a better optimisation than the JDK Integer.toString() conversion method but as you said you did not want to use it :
List<Byte> bcd(int i) {
List<Byte> l = new ArrayList<Byte>(10); // max size for an integer to avoid reallocations
if (i == 0) {
l.add((byte) i);
}
else {
while (i != 0) {
l.add((byte) (i % 10));
i = i / 10;
}
}
return l;
}
It is more or less what you proposed to get first digit, but now you have all you digits in one single pass and can use them for your algorythm.
I proposed to use byte because it is enough, but as java always convert to int to do computations, it might be more efficient to directly use a List<Integer> even if it really wastes memory.

Java Random Class output 1 or 0

The result is pretty impressive. with almost 50% each, however the process is the one I am worried about. Sometime i get 10 ones in a roll or 8 zeros in a roll. Which I consider at that period is not a TRUE randomness. I would want to avoid that and only allowing most 3 repeated sequence. Is there a good advice on this?
int resetOne = 0;
int resetZero = 0;
Random ran = new Random();
while (y < 100) {
y++;
x = ran.nextInt(2);
if (x == 1) {
resetOne++;
resetZero = 0;
if (resetOne == 3) {
x = ran.nextInt(2);
}
oneCounter++;
} else if (x == 0) {
resetZero++;
resetOne = 0;
if (resetZero == 3) {
x = ran.nextInt(2);
}
zeroCounter++;
}
System.out.println(x);
System.out.println("0 = " + zeroCounter + " " + "1 = " + oneCounter);
}
True randomness could come up 1 10,000 times in a row. It wouldn't be likely to, but it could. So I would strongly suggest recalibrating your expectations.
If you really want biased randomness -- a progressively less "fair" coin flip -- you'll need to implement that yourself by tracking recent results and adjusting your probabilities.
As a note before my answer, if I can predict what the next number will be, it's not actually random. In your case, if I get three 0's in a row, I know with 100% certainty that the next number will be a 1.
Now, the simplest way to implement what you're asking is just to introduce two new variables: a counter that gets reset when the result changes, and a cache of the last returned value. If the counter is at the maximum allowed in a row for a result (you got three 0's in a row), then just return the other number and reset the counter (and store this returned value in the lastReturned cache).
This should keep your distributions close to the 50% mark, since it should happen approximately equally for 1s and 0s. It should be easy to test it out to verify.

Java comparing two letters

I ran in to a small problem while working on my assignment. Basically I'm making a small program that asks the user for 3 letters and compares them to 3 letters that are coded in. Then the program is supposed to compare the 3 letters and if they're the same then print true. Thus far I've been able to make it without problems using compareTo, but now the tricky part is that I need to add a "tolerance" to the program (which I have) but the tolerance is supposed to loop back from Z to A. So if tolerance is 3 and the user inputs X Y Z (when it really is A B C) it should still print out true.
NOTE: the Tolerance will not go above 3. ALSO, We shouldn't use Arrays.
Any ideas how I can accomplish this? If it's complicated to understand what I'm asking please post and I'll try to clarify it :)
Thanks
EDIT: basically this is the code that compares the tolerances
if ((a1.compareTo(d1) <= tolerance) && (a1.compareTo(d1) >= negTolerance)
&& (b1.compareTo(e1) <= tolerance) && (b1.compareTo(e1) >= negTolerance)
&& (c1.compareTo(f1) <= tolerance) && (c1.compareTo(f1) >= negTolerance))
{
open = true;
} else open = false;
where a1 - c1 are pre inputed characters and d1-f1 are user entered. tolerance is also user entered as an integer between 1 and 3
Since it's a homework assignment, I won't give you the full answer, but I'll give you a hint. You want to look at the character codes (ASCII) for the letters. This will let you solve the tolerance problem. You might also have to do some magic with % (modulus) to handle the looping back of Z to A.
EDIT
If you cannot use the ASCII values, the return value of compareTo will help you, but keep in mind that that comparing A to Z and Z to A will give you -25 and 25 respectively. This is where the % operator will help you.
I would recommend using the ASCII value of the char.
char[] expecteds = ...;
int tolerance = 3;
char input = ...;
int inputValue = char;
for (int i=0; i<expecteds.length; i++){
int delta = expected[0] - 'a' - input - 'a' % 'a';
if (i < tolerance)
result = true;
}
Use the Modulus (%) operator to cycle back around to the beginning:
int index = 0;
for (i in 1 .. 26) {
int index = (i+tolerance) % 26;
}
1) Map each character to a Number
2) Grab the tolerance
3) Add/subtract the tolerance from the number
4) Compare the letters in the tolerance range to the letter

How to test if an array contains a pair of numbers whose product is odd?

How can I write a function that takes an array of integers and returns true if their exists a pair of numbers whose product is odd?
What are the properties of odd integers? And of course, how do you write this function in Java? Also, maybe a short explanation of how you went about formulating an algorithm for the actual implementation.
Yes, this is a function out of a textbook. No, this is not homework—I'm just trying to learn, so please no "do your own homework comments."
An odd number is not evenly divisible by two. All you need to know is are there two odd numbers in the set. Just check to see if each number mod 2 is non-zero. If so it is odd. If you find two odd numbers then you can multiply those and get another odd number.
Note: an odd number multiplied by an even number is always even.
The product of two integers will be odd only if both integers are odd. So, to solve this problem, just scan the array once and see if there are two (or more) odd integers.
EDIT: As others have mentioned, you check to see if a number is odd by using the modulus (%) operator. If N % 2 == 0, then the number is even.
Properties worth thinking about:
Odd numbers are not divisible by 2
Any number multiplied by an even number is even
So you can re-state the question as:
Does the array contain at least two integers that are not divisible by 2?
Which should make things easier.
You can test for evenness (or oddness) by using the modulus.
i % 2 = 0 if i is even; test for that and you can find out if a number is even/odd
A brute force algorithm:
public static boolean hasAtLeastTwoOdds(int[] args) {
int[] target = args; // make defensive copy
int oddsFound;
int numberOddsSought = 2;
for (int i = 0; i < target.length; i++) {
if (target[i] % 2 != 0) {
if (oddsFound== numberOddsSought) {
return true;
}
oddsFound++;
}
}
return false;
}
Thank you for your answers and comments.
I now understand well how to test whether an integer is odd. For example, this method is a neat way of doing this test without using multiplication, modulus, or division operators:
protected boolean isOdd(int i) {
return ( (i&1) == 1);
}
With your help, I now realize that the problem is much simpler than I had expected. Here is the rest of my implementation in Java. Comments and criticism are welcome.
protected boolean isOddProduct(int[] arr) {
int oddCount = 0;
if (arr.length < 2)
throw new IllegalArgumentException();
for (int i = 0; i <= arr.length-1; i++) {
if (isOdd(arr[i]))
oddCount++;
}
return oddCount > 1;
}
I wonder if there exists any other ways to perform this test without using *, % or / operators? Maybe I'll ask this question in a new thread.

Categories