Compare two large numbers - java

Two strings representing two numbers have been provided as input. The numbers in the string can be so large that they may not be represented by the Java data type int. The objective is to compare the two numbers and output that number as a string
for example we have to compare:
"874986754789289867753896798679854698798789857387687546456"
and
"98347598375689758967756458678976893478967586857687569874"
which both are out of range of long and int data types in JAVA
and after comparing we have to output that number as a string

you could start by first looking at each string's length. if one of them is longer and you know they are both unsigned values, the longer string has the bigger number. if they both have the same length, you start comparing the strings char by char starting from left to right. when you found your first bigger digit you conclude that number is bigger.

Whether you're trying to compare or subtract isn't clear, but Java's BigInteger class has both operations. This is probably what you need:
BigInteger a = new BigInteger("874986754789289867753896798679854698798789857387687546456");
BigInteger b = new BigInteger("98347598375689758967756458678976893478967586857687569874");
System.out.println( (a.compareTo(b) > 0 ? "a" : "b") + " is larger.");
If you need to subtract the numbers I'd definitely use BigInteger, but if all you need to do is compare them you could write your own method. One of your input strings is longer than the other, so barring leading zeroes that would tell you right away which is larger. If the strings are the same length you could compare them character by character in a loop to see which is larger. The String charAt and toCharArray methods give you two different ways to implement this approach.

In order to use numbers that big, they must be declared as double. You can use parsers to transform Strings into numbers.
public static void main(String [] args) {
String numberOne = "874986754789289867753896798679854698798789857387687546456";
double parsedNumberOne = Double.parseDouble(numberOne);
String numberTwo = "98347598375689758967756458678976893478967586857687569874";
double parsedNumberTwo = Double.parseDouble(numberTwo);
double result = compareMethod (numberOne, numberTwo);
System.out.println("Result = " + result);
}
I declared the numbers explicitly and not by reading user input, but you can modify that easily to be inline with your code. In the compareMethod, you can compare those number anyway you like.
Regards

Just comparing two strings using compareTo() is more than enough. The comparison will be done by converting each character into its ASCII value.
String number1 = "874986754789289867753896798679854698798789857387687546457";
String number2 = "874986754789289867753896798679854698798789857387687546456";
int result = number1.compareTo(number2);
if (result == 0) {
System.out.println("Both are equal");
} else if (result > 0) {
System.out.println("Number1 is greater");
} else {
System.out.println("Number2 is greater");
}

If it is school assignment in which you can't use built-in solutions but you need to write your own method to compare such strings then you need to
check sign of numbers (if one is negative and one positive then answer is obvious)
remove leading zeroes - 0000123 represents 123
after removing leading zeroes compare length of numbers (longer one among positive numbers is larger)
if both numbers have same length iterate over them from left to right until you will find two different digits (if you will not find any numbers are equal).
Members of String class you may need
toCharArray()
charAt(int index)
length
In case you can use built-in solutions you can use these strings to create BigInteger instances and use its compareTo method which will tell if one number is larger (positive result) equal to (0) or smaller (negative result) than other.

You need to compare characters (converted to numbers) one by one (or group by group) from right to left. Use methods like charAt(int) or substring(int, int) respectively.

Related

Is there an approach to finding the ASCII distance between two strings of 5 characters

I am trying to find a way to calculate and print the Ascii distance between a string from user input
Scanner scan = new Scanner(System.in);
System.out.print("Please enter a string of 5 uppercase characters:");
String userString = scan.nextLine();
and a randomly generated string
int leftLimit = 65; // Upper-case 'A'
int rightLimit = 90; // Upper-case 'Z'
int stringLength = 5;
Random random = new Random();
String randString = random.ints(leftLimit, rightLimit + 1)
.filter(i -> (i <= 57 || i >= 65) && (i <= 90 || i >= 97))
.limit(stringLength)
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
.toString();
Is there a way to calculate the distance without having to separate each individual character from the two strings, comparing them and adding them back together?
Use Edit distance (Levenshtein distance)
You can
Implement your own edit distance based on the algorithm on wikipedia,
you can use an existing source code, for that look at rosetta code.
use an existing library like apache LevenshteinDistance
you can also check
Levenshtein Distance on stackoverflow
Streams are, well, as the name says, streams. They don't work very well unless you can define an operation strictly on the basis of one input: One element from a stream, without knowing its index or referring to the entire collection.
Here, that is a problem; after all, to operate on, say, the 'H' in your input, you need the matching character from your random code.
I'm not sure why you find 'separate each individual character, compare them, and add them back together' is so distasteful to you. Isn't that a pretty clean mapping from the problem description to instructions for your computer to run?
The alternative is more convoluted: You could attempt to create a mixed object that contains both the letter as well as its index, stream over this, and use the index to look up the character in the second string. Alternatively, you could attempt to create a mix object containing both characters (so, for inputs ABCDE and HELLO, an object containing both A and H), but you'd be writing far more code to get that set up, then the simple, no-streams way.
So, let's start with the simple way:
int difference = 0;
for (int i = 0; i < stringLength; i++) {
char a = inString.charAt(i);
char b = randomString.charAt(i);
difference += difference(a, b);
}
You'd have to write the difference method yourself - but it'd be a very very simple one-liner.
Trying to take two collections of some sort, and from them create a single stream where each element in the stream is matching elements from each collection (so, a stream of ["HA", "EB", "LC", "LD", "OE"]) is generally called 'zipping' (no relation to the popular file compression algorithm and product), and java doesn't really support it (yet?). There are some third party libraries that can do it, but given that the above is so simple I don't think zipping is what you're looking for here.
If you absolutely must, I guess i'd look something like:
// a stream of 0,1,2,3,4
IntStream.range(0, stringLength)
// map 0 to "HA", 1 to "EB", etcetera
.mapToObj(idx -> "" + inString.charAt(idx) + randomString.charAt(idx))
// map "HA" to the difference score
.mapToInt(x -> difference(x))
// and sum it.
.sum();
public int difference(String a) {
// exercise for the reader
}
Create an 2D array fill the array with distances - you can index directly into the 2D array to pull out the distance between the characters.
So one expression that sums up a set of array accesses.
Here is my code for this (ASCII distance) in MATLAB
function z = asciidistance(input0)
if nargin ~= 1
error('please enter a string');
end
size0 = size(input0);
if size0(1) ~= 1
error ('please enter a string');
end
length0 = size0(2);
rng('shuffle');
a = 32;
b = 127;
string0 = (b-a).*rand(length0,1) + a;
x = char(floor(string0));
z = (input0 - x);
ascii0 = sum(abs(z),'all');
ascii1 = abs(sum(z,'all'));
disp(ascii0);
disp(ascii1);
disp(ascii0/ascii1/length0);
end
This script also differentiates between the absolute ASCII distance on a per-character basis vs that on a per-string basis, thus resulting in two integers returned for the ASCII distance.
I have also included the limit of these two values, the value of which approaches the inverse of the length of strings being compared. This actually approximates the entropy, E, of every random string generation event when run.
After standard error checking, the script first finds the length of the input string. The rnd function seeds the random number generator. the a and b variables define the ASCII table minus non-printable characters, which ends at 126, inclusively. 127 is actually used as an upper bound so that the next line of code can generate a random string of variables of input length. The following line of code turns the string into the alphanumeric characters provided by the ASCII table. The following line of code subtracts the two strings element-wise and stores the result. The next two lines of code sum up the ASCII distances in the two ways mentioned in the first paragraph. Finally, the values are printed out, as well as providing the entropy, E, of the random string generation event.

Encoding a Double value to a binary string

I'm trying to encode Double values in an interval (let's say between "a" and "b") to a binary strings (in Java), given the precision (1.234 - precision is 3 in this case) of the Double values. The resulting strings should be equal in length.
I have tried using:
String binaryForm = Long.toBinaryString(Double.doubleToRawLongBits(n));
Unfortunately, the resulting strings are not equal in length.
Any ideas? The resulting strings are going to be used as chromosomes in a GA.
Use suggestion of #rgettman but normalize values between 0 and c = b - a. Thus, the new value (m) for double input n is:
m = n - a
Then zero-pad to 64. All inputs are positive.

Converting non-numeric String to Integer?

How can I convert a non-numeric String to an Integer?
I got for instance:
String unique = "FUBAR";
What's a good way to represent the String as an Integer with no collisions e.g. "FUBAR" should always be represented as the same number and shan't collide with any other String. For instance, String a = "A"; should be represented as the Integer 1 and so on, but what is a method that does this (preferrably for all unicode strings, but in my case ASCII values could be sufficient).
This is impossible. Think about it, an Integer can only be 32 bits. So, by the pigeonhole principle, there must exist at least two strings that have the same Integer value no matter what technique you use for conversion. In reality, there are infinite with the same values...
If you're just looking for an efficient mapping, then I suggest that you just use the int returned by hashCode(), which for reference is actually 31 bits.
You can map Strings to unique IDs using table. There is not way to do this generically.
final Map<String, Integer> map = new HashMap<>();
public int idFor(String s) {
Integer id = map.get(s);
if (id == null)
map.put(s, id = map.size());
return id;
}
Note: having unique id's doesn't guarantee no collisions in a hash collection.
http://vanillajava.blogspot.co.uk/2013/10/unique-hashcodes-is-not-enough-to-avoid.html
If you know the character set used in your strings, then you can think of the string as number with base other than 10. For example, hexadecimal numbers contain letters from A to F.
Therefore, if you know that your strings only contain letters from an 8-bit character set, you can treat the string as a 256-base number. In pseudo code this would be:
number n;
for each letter in string
n = 256 * n + (letter's position in character set)
If your character set contains 65535 characters, then just multiply 'n' with that number on each step. But beware, the 32 bits of an integer will be easily overflown. You probably need to use a type that can hold a larger number.
private BigDecimal createBigDecimalFromString(String data)
{
BigDecimal value = BigDecimal.ZERO;
try
{
byte[] tmp = data.getBytes("UTF-8");
int numBytes = tmp.length;
for(int i = numBytes - 1; i >= 0; i--)
{
BigDecimal exponent = new BigDecimal(256).pow(i);
value = value.add(exponent.multiply(new BigDecimal(tmp[i])));
}
}
catch (UnsupportedEncodingException e)
{
}
return value;
}
Maybe a little bit late, but I'm going to give my 10 cents to simplify it (internally is similar to BigDecimal suggested by #Romain Hippeau)
public static BigInteger getNumberId(final String value) {
return new BigInteger(value.getBytes(Charset.availableCharsets().get("UTF-8")));
}
Regardless of the accepted answer, it is possible to represent any String as an Integer by computing that String's Gödelnumber, which is a unique product of prime numbers for every possible String. With that being said it's quite impractical and slow to implement, also for most Strings you would need a BigInteger rather than a normal Integer and to decode a Gödelnumber into its corresponding String you need to have a defined Charset.

Java parsing long from string

I'm currently trying to parse some long values stored as Strings in java, the problem I have is this:
String test = "fffff8000261e000"
long number = Long.parseLong(test, 16);
This throws a NumberFormatException:
java.lang.NumberFormatException: For input string: "fffff8000261e000"
However, if I knock the first 'f' off the string, it parses it fine.
I'm guessing this is because the number is large and what I'd normally do is put an 'L' on the end of the long to fix that problem. I can't however work out the best way of doing that when parsing a long from a string.
Can anyone offer any advice?
Thanks
There's two different ways of answering your question, depending on exactly what sort of behavior you're really looking for.
Answer #1: As other people have pointed out, your string (interpreted as a positive hexadecimal integer) is too big for the Java long type. So if you really need (positive) integers that big, then you'll need to use a different type, perhaps java.math.BigInteger, which also has a constructor taking a String and a radix.
Answer #2: I wonder, though, if your string represents the "raw" bytes of the long. In your example it would represent a negative number. If that's the case, then Java's built-in long parser doesn't handle values where the high bit is set (i.e. where the first digit of a 16 digit string is greater than 7).
If you're in case #2, then here is one (pretty inefficient) way of handling it:
String test = "fffff8000261e000";
long number = new java.math.BigInteger(test, 16).longValue();
which produces the value -8796053053440. (If your string is more than 16 hex digits long, it would silently drop any higher bits.)
If efficiency is a concern, you could write your own bit-twiddling routine that takes the hex digits off the end of the string two at a time, perhaps building a byte array, then converting to long. Some similar code is here:
How to convert a Java Long to byte[] for Cassandra?
The primitive long variable can hold values in the range from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 inclusive.
The calculation shows that fffff8000261e000 hexademical is 18,446,735,277,656,498,176 decimal, which is obviously out of bounds. Instead, fffff8000261e000 hexademical is 1,152,912,708,553,793,536 decimal, which is as obviously within bounds.
As everybody here proposed, use BigInteger to account for such cases. For example, BigInteger bi = new BigInteger("fffff8000261e000", 16); will solve your problem. Also, new java.math.BigInteger("fffff8000261e000", 16).toString() will yield 18446735277656498176 exactly.
The number you are parsing is too large to fit in a java Long. Adding an L wouldn't help. If Long had been an unsigned data type, it would have fit.
One way to cope is to divide the string in two parts and then use bit shift when adding them together:
String s= "fffff8000261e000";
long number;
long n1, n2;
if (s.length() < 16) {
number = Long.parseLong(s, 16);
}
else {
String s1 = s.substring(0, 1);
String s2 = s.substring(1, s.length());
n1=Long.parseLong(s1, 16) << (4 * s2.length());
n2= Long.parseLong(s2, 16);
number = (Long.parseLong(s1, 16) << (4 * s2.length())) + Long.parseLong(s2, 16);
System.out.println( Long.toHexString(n1));
System.out.println( Long.toHexString(n2));
System.out.println( Long.toHexString(number));
}
Note:
If the number is bigger than Long.MAX_VALUE the resulting long will be a negative value, but the bit pattern will match the input.

What's the right way to represent phone numbers?

I'm having trouble representing a mobile number in one of my applications.
I was wondering if there is an Integer class that will allow you to store such a number starting with 0417254482. Perhaps using a string be a more appropriate?
At present when I'm trying to use represent a phone number with ints, doubles longs I seem to store random numbers and not the numbers I meant to store.
Use String. Aside from anything else, you won't be able to store leading zeroes if you use integers. You definitely shouldn't use int (too small) float or double (too much risk of data loss - see below); long or BigInteger could be appropriate (aside from the leading zeroes problem), but frankly I'd go with String. That way you can also store whatever dashes or spaces the user has entered to make it easier to remember the number, if you want to.
In terms of the "data loss" mentioned above for float and double - float definitely doesn't have enough precision; double could work if you're happy that you'll never need more than 16 digits (a couple fewer than you get with long) but you would need to be very, very careful that anywhere you convert the value back from double to string, you got the exact value. Many formatting conversions will give you an approximation which may be accurate to, say, 10 significant digits - but you'd want an exact integer. Basically, using floating point for phone numbers is a fundamentally bad idea. If you have to use a fixed-width numeric type, use a long, but ideally, avoid it entirely.
Think about this: Is a phone number really a number? Does it make sense adding (or make another arithmetic operation) with phone numbers? Phone numbers are codes, they're usually represented with numbers, but that's just a convention and, maybe, in another country the use letters too (I've just realized, what about international phone numbers? they have a + at the beginning.
You have to think about the nature of the things you want to represent, and then, find the most suitable representation.
If you want to do validation and normalization you probably want to rely on a library that does it properly for you. https://github.com/googlei18n/libphonenumber is one of the most common options.
Although phone numbers are named numbers, they are normally not numbers (e.g. leading zeros, country prefix +XX, ...).
So there are two possibilities to represent a phone number correctly inside a program:
Using String to keep the whole number like entered.
Using a custom data type that offers additional support for phone number features
public class PhoneNumber implements Comparable<PhoneNumber>{
private String countryCode;
private String areaCode;
private String subscriberNumber;
// Constructor(s)
// Getter
// HashCode + Equals
// compareTo
#Override
public String toString(){
return countrycode + " " + areaCode + " " + subscriberNumber;
}
}
It's really interesting to look at all the different conventions that are used internationally
Create your own PhoneNumber class with a private field of type String to represent it.
public class PhoneNumber {
private String number;
public PhoneNumber(String number) {
//check validity of number
this.number = number;
}
//getter, comparator, etc...
}
You could also represnt the number with long or BigInteger if all phone numbers have the same length, but be careful with leading zeros.
A phone number is not really an integer (or a string). It is something else which shuld have a class of its own.
EDIT:
one more thing: I wouldn't implement a setter for this class because a phone number object would better be immutable
You should use a string or a more specialized data structure.
The main reason is that the operations that you can do on phone numbers are lexicographic, and not arithmetic.
e.g. You can say that phone numbers for France start with +33, but you cannot assume they are in a numerical range.
These other arguments are not valid in my opinion
a phone number can include * or #. This symbols can be transported on phone lines, but they are not part of the phone number itself, and I consider it's out of scope.
a phone number can start with leading zeros. Local phone numbers can, but they are a limited representation in the first place. International phone numbers start with a country code, and none of them has a leading zero. Hence no international phone number has leading zeros.
a phone number starts with +. A number can perfectly represent this, by simply being positive. Also starting with + is just a representation of E164 numbers, so that they can be distinguished from local numbers. They really don't have to, if you only manipulate E164 numbers.
a phone number can contain spaces or parentheses. This is absurd, because it's just textual representation of the number. You shouldn't store this as people can have different personal preferences to separate groups of digits (., -, , etc.).
You should use string to support numbers with leading zeros. The code you provided was:
Order order1 = new PickUpOrder(orderTime, 0473519954);
//The pickup order requires an orderTime (String) and a contact number(Int). Heres
//the constructor for PickUpOrder.
public PickUpOrder(Date orderTime, String number)
{
discount = .2;
phoneNumber = number;
super.setOrderTime(orderTime);
//Test print
System.out.println(phoneNumber)
//reads int as 74049273 instead of 0473519954
}
In the constructor, the number is string but when you call the constructor you used an int for phone number. There must have been a compile error here in java I think. Is this the same code you compiled?
Every number have infinity amount of zeros on the left and right side,
To represent it you should use a string formating
class PhoneNumber implements Comparable<PhoneNumber> {
private Long number;
public PhoneNumber(Long number) {
this.number = number;
}
public Long getNumber() {
return this.number;
}
public boolean equals(Object object) {
if (getNumber() == null && object == null) {
return true; //or false its depend
}
return getNumber().equals(object);
}
public int compareTo(PhoneNumber that) {
if(that == null) {
return -1;
}
Long thisNumber = getNumber();
Long thatNumber = that.getNumber();
if (thisNumber == null && thatNumber == null) {
return 0; //or -1
}
if (thisNumber == null && thatNumber != null) {
return -1;
}
return thisNumber.compareTo(thatNumber);
}
#Override
public String toString() {
return String.format("%010d", getNumber());
}
}
Used %010d mean
%[argument_index$][flags][width][.precision]conversion
flag 0 - padding zeros
10 - amount of padding zeros
d - decimal integer
The implementation of interface Comparable give you the posibility to sort List.
List<PhoneNumber> phoneNumbers = new ArrayList();
phoneNumbers.add(new PhoneNumber (123L);
phoneNumbers.add(new PhoneNumber (123777L);
phoneNumbers.add(new PhoneNumber (125L);
phoneNumbers.add(new PhoneNumber (124L);
phoneNumbers.add(new PhoneNumber (126L);
Collections.sort(phoneNumbers);
for(PhoneNumber phoneNumber : phoneNumbers) {
System.Console.Out.WriteLine(phoneNumber);
}
The output is
0000000000
0000000123
0000000124
0000000125
0000000126
0000123777
Comparable
String Formatter
I would suggest not use primitive data type.
Reason: Primitives cannot accept special characters such as +,-,(, and, ). If you accept phone numbers in this format +1(xxx)-xxx-xxxx.

Categories

Resources