Creating a BigInteger from String and pad "0"s to it - java

[InputParam1:Decimal Number in String format(for Eg:30),
InputParam2:Integer to denote number of repeating 0's to append(for Eg:6)]
For converting a number from Decimal to Binary and pad digits to its front I need to perform the following steps:
Step1: BigInteger binary=new BigInteger(InputParam1,2);
-->This works when I define a BigInt with a base 16 (which I just tried when base2 failed) but not with a base 2 like above.
It throws a numberformat exception.
Step 2: String pad=StringUtils.repeat("0",InputParam2);
(to repeat 0 'InputParam2' number of times)
-->This works fine
Step 3: Need to append pad in front of binary(from Step1)
For a BigInteger, I'm not able to get something similar to .append.
So I'm trying to a)convert this BigInteger number to String and b)append pad c)convert back to BigInteger (this step I'm not able to get without creating a new BigInteger)
Any pointers on Step1 and Step3-c would be helpful please.

#1 - You haven't said what value you're passing in InputParam1, but my guess is that you're passing in something other than a string containing only '0' in '1' characters. The 'radix' parameter to the constructor tells the code how to interpret the string you're giving it. This works fine for me:
BigInteger binary=new BigInteger("1000",2);
System.out.println(binary);
How you construct the number has nothing to do with how you're eventually going to want to represent or display that number. The key idea here is that the representation of a number (hex, decimal, binary) has nothing to do with the number itself, just like leading zeros don't affect the value of number. 1111 binary, f hex, and 15 decimal are all the same number. If you pass the three of these into BigDecimal's constructor with a radix of 2, 16 and 10 respectively, you'll end up with EXACTLY the same thing in each case. The object will lose any notion of what kind of representation you used to set it to its initial value.
#3 - There is no concept of a number (int, BigInteger, etc.) with zero padding at the front, just as there's no notion of which base/radix you might use to represent a number visually. You can think about it conceptually, but that's just a way of displaying the number. It has nothing to do with the number itself.
I hadn't tried it before, but it seems there's no super simple way to format a binary value in Java with leading 0s, like there is for decimal and hex, since String.format() doesn't give a format specifier for binary. Per this StackOverflow post How to get 0-padded binary representation of an integer in java?, this seems to be about the best way to go, having converted the most accepted answer to work with BigInteger:
String str = String.format("%16s", binary.toString(2)).replace(' ', '0');
So here's all of my sample code, with output:
BigInteger binary=new BigInteger("1000",2);
System.out.println(binary);
String str = String.format("%16s", binary.toString(2)).replace(' ', '0');
System.out.println(str);
Output:
8
0000000000001000

Related

What is the significance of radix in Character.fordigit() in Java?

Could someone please help me understand the significance of radix in the Character.forDigit(int digit, int radix) method?
Choosing a suitable radix lets you produce "digits" that are not decimal digits - for example, if you pass 16 for the radix, you can produce characters for digits ten through fifteen, because counting in hex uses sixteen digits - 0 through 9, followed by A through F:
char ten = Character.forDigit(10, 16); // returns 'a'
Demo.
This is tricky because the significance isn't as obvious as it first appears. When converting a string to an integer, of course the radix matters a lot. If you are converting "101" to an integer, you will get different answers depending on whether the radix (base) is binary (2), decimal (10), octal (8), hex (16), or any other base. Similarly, when converting an integer to a string, the results (when the source is >= MAX_RADIX) are all different for the different radices.
For forDigit, the answer isn't as clear. When you're converting a number to a single character representing a digit, the answer is always the same as long as the digit is valid for the radix. Thus, Character.forDigit(11,radix) always returns 'b' for all radices 12 and up. So the only significance is in how it handles the case when the digit is not valid for the radix? That is, for binary (radix=2), forDigit only works if the digit is 0 or 1; so what should it do if you say Character.forDigit(2,2), since 2 is not a valid binary digit?
There are a few things the language designers could have done: (1) get rid of the radix parameter and put the onus on the programmer to make sure the digit is in range (which in many cases will be a given anyway); (2) throw an exception; (3) return some special value. They chose (3): if you give it a digit that isn't valid for the radix, it returns '\0', the null character. This doesn't seem to be the best choice--you're unlikely to really want to use the null character for anything, which means you have to make your own check, which means they probably should have had the method throw an exception. But there it is.
But anyway, that's the significance of radix for this method: it performs a check to make sure the argument is in range, based on the radix.
It is the base of the number. One normally uses base 10 (ie 0-9). However, you might also be interested in using hexadecimal (ie 0-9, A-F), for example. The radix would then be 16.
Example:
Character.forDigit(8, 16)=8
Character.forDigit(9, 16)=9
Character.forDigit(10, 16)=a
Character.forDigit(11, 16)=b

Converting negative integer to hex value using pre-defined methods

I am a beginner in Java, and have just started learning this language.
I am learning and experimenting with examples from Herbert Schildt's book to test my understanding.
My objective is to convert negative integer to hex using in-built java methods, and then back to integer (or long). However, there are two issues that I am facing:
Issue #1: as I understand from the thread hex string to decimal conversion, Java Integer parseInt error and Converting Hexadecimal String to Decimal Integer that the converted value fffffff1 is too big to fit into Integer, so I have used Long. However, when fffffff1 is converted back to Long, I don't get -15. I get garbage value = 4294967281.
Moreover, when I type-cast the result from Long to Integer, it works well. I am not sure why Long result would show garbage value and then magically I would get the right value by just typecasting the number to integer-type. I am sure I am missing something crucial here.
Issue#2: If I don't use radix (or even change it from 16 to 4) in the method Long.parseLong(), I get an exception.
Here's my code:
public class HexByte {
public static void main(String[] args) {
byte b = (byte) 0xf1;
System.out.println("Integer value is:"+Integer.valueOf(b)); //you would get -15
int i = -15;
System.out.println("Hexadecimal value is:"+Integer.toHexString(i));
//Let's try to convert to hex and then back to integer:
System.out.println("Integer of Hexadecimal of -15 is:"+(int)Long.parseLong(Integer.toHexString(i),16 ));
//type-cast to integer works well, but not sure why
System.out.println("Integer of Hexadecimal of -15 is:"+Long.parseLong(Integer.toHexString(i),16));
//This surprisingly throws garbage value
System.out.println("Integer of Hexadecimal of -15 is:"+Long.parseLong(Integer.toHexString(i)));
//doesn't work - throws an exception
}
}
Can someone please help me? I didn't want to open duplicate threads for above issues so I have included them herewith.
Issue 1:
Negative numbers are represented using Two's Complement, which you can read more about here: wikipedia link
Basically, the left-most bit is used to determine the sign of the integer (whether it's positive or negative). A 0 means the number is positive, and a 1 means it's negative.
fffffff1 doesn't go all the way to the left, so the left-most bit when you convert that to long is a 0, which means the number is positive. When you cast it to an integer, the left bits are just dropped, and you end up somewhere in the middle of the 1s such that your leftmost digit is now a 1, so that the result is negative.
An example, with much shorter lengths for demonstration's sake:
4-bit number: 0111 -> this is positive since it starts with a 0
2-bit number using the last 2 bits of the 4-bit number: 11 -> this is negative since it starts with a 1.
Longs are like the 4-bit number in this example, and ints are like the 2-bit number. Longs have 64 bits and ints have 32 bits.
Issue 2:
If you don't specify a radix, Long.parseLong assumes base 10. You're giving it "fffffff1", and it doesn't recognize "f" as a digit in base 10 and thus throws an exception. When you specify the radix 16 then it knows "f" = 15 so there aren't any problems.

How to convert binary fraction into hexadecimal in Java?

How can i convert a binary fraction or a decimal fraction into hex in Java?
What is the algorithm to do that?
for example i want (11.110)2 be converted into (3.C)16
and which data type do I need to hold the hex fraction ?
plz help.
Thanks.
This answer is not meant to be a complete guide on how to make a fully working program that converts from one radix to another, but it mentions most of the steps you'd have to do if you want to use the built-in methods that are available.
There are no built-in methods for converting floating-point numbers, but there are built-in methods for converting integers from/to any radix between 2-36. If you only need to convert between binary and hexadecimal and nothing else, you could also do it manually (see below the line further down), but I recommend using these methods otherwise.
If you remove the radix point . from the number (in its String-representation), you get a whole number, but keep track of how many digits were to the right of the radix point.
Here are three ways to convert a whole number from a String with any radix:
Integer.parseInt(String val, int radix) will convert to int.
Long.parseLong(String val, int radix) will convert to long.
new BigInteger(String val, int radix) will convert to BigInteger.
You should then convert the number to a double or BigDecimal, and make sure you get the radix point back in place, by dividing by the correct number. For instance, you can turn (1234)6 into (12.34)6 by dividing it by 6².
Now you are halfway done, and basically go backwards to convert the number back to a String (but with some other radix).
At the step where you want to convert from int/long/BigInteger to a String, use toString:
Integer.toString(int val, int radix) will convert from int.
Long.toString(long val, int radix) will convert from long.
val.toString(int radix) will convert from BigInteger.
Remember to insert the radix point again, and you're done.
To convert from binary to hex manually, you do the same as you would do if they were whole numbers, with few differences.
Divide the binary number into sets of 4 consecutive digits, starting at the radix point, going both left and right. Add leading/trailing zeros as needed. The rest is as explained in the link.
For instance: 101011.011 is divided into 0010 1011 . 0110 which becomes 2B.6 after converting each set to hexadecimal.

Reduce Java BigInteger to fixed length smaller number

I'm attempting to implement a random number generator system; essentially I'm reading in an SHA1 hash, which then gets converted into a BigInteger value:
String start = "abc";
String hash = utils.SHA1(start); //Generates an SHA1 hash of the string
byte[] bytes = hash.getBytes();
BigInteger big = new BigInteger(bytes);
This code generates a BigInteger with a value of:
811203900027758629330492243480887228261034167773619203962320290854945165232584286910163772258660
What I need to somehow do (and this is where I get confused), is reduce that number into a much shorter number with a fixed number of decimal places.
Using a combination of modular arithmetic and Java Math API functions, is there a sensible way of reducing this number down into a 3 digit number. Or any other length of number I choose.
At the moment I'm just simply converting that huge number into a String, and then taking a substring of the length of number I want. However I'm not entirely happy with this as the numbers I get aren't that random, as the range is somewhat limited with 3 digits.
The whole purpose of this is for the newly generated random x digit number to be then converted into a string using a radix of 36, to also include ASCII alphabet characters.
Any information or advice would be greatly appreciated.
Thanks!!
Yes you can use modulus like .mod(1000) or for base 36 .mod(36*36*36) or even plain .longValue() % 1000 or .longValue() % (36*36*36)
You can use Long.toString(x, 10) or Long.toString(x, 36)
Not sure I can tell much more without giving you the answer.

Converting US-ASCII encoded byte to integer and back

I have a byte array that can be of size 2,3 or 4. I need to convert this to the correct integer value. I also need to do this in reverse, i.e an 2,3 or 4 character integer to a byte array.
e.g., raw hex bytes are : 54 and 49. The decoded string US-ASCII value is 61. So the integer answer needs to be 61.
I have read all the conversion questions on stackoverflow etc that I could find, but they all give the completely wrong answer, I dont know whether it could be the encoding?
If I do new String(lne,"US-ASCII"), where lne is my byte array, I get the correct 61. But when doing this ((int)lne[0] << 8) | ((int)lne[1] & 0xFF), I get the complete wrong answer.
This may be a silly mistake or I completely don't understand the number representation schemes in Java and the encoding/decoding idea.
Any help would be appreciated.
NOTE: I know I can just parse the String to integer, but I would like to know if there is a way to use fast operations like shifting and binary arithmetic instead?
Here's a thought on how to use fast operations like byte shifting and decimal arithmetic to speed this up. Assuming you have the current code:
byte[] token; // bytes representing a bunch of ascii numbers
int n = Integer.parseInt(new String(token)); // current approach
Then you could instead replace that last line and do the following (assuming no negative numbers, no foreign langauge characters, etc.):
int n = 0;
for (byte b : token)
n = 10*n + (b-'0');
Out of interest, this resulted in roughly a 28% speedup for me on a massive data set. I think this is due to not having to allocate new String objects and then trash them after each parseInt call.
You need two conversion steps. First, convert your ascii bytes to a string. That's what new String(lne,"us-ascii") does for you. Then, convert the string representation of the number to an actual number. For that you use something like Integer.parseInt(theString) -- remember to handle NumberFormatException.
As you say, new String(lne,"US-ASCII") will give you the correct string. To convert your String to an integer, use int myInt = Integer.parseInt(new String(lne,"US-ASCII"));

Categories

Resources