I read somewhere that string 0123456789ABCDEFFEDCBA987654321089ABCDEF01234567 is 192 bit (24). Its written that it is a "hex representation of bytes"
I need help on this concept.
PS: This is secret key of TripleDES algorithm.
In hexadecimal numbers, you have 16 different digits. These are written using first the ordinary 10 symbols used for decimal digits, 0 through 9. Then the first six letters of the Latin alphabet are used, i.e. A through F.
Since each digit represents a value in the range 0 through F, i.e. one of sixteen possibilities, it holds four bits of information. Thus, in a long string of hex digits, you can compute the total number of bits of information as just four times the number of digits present.
Your example string, "0123456789ABCDEFFEDCBA987654321089ABCDEF01234567", is 48 digits. This means it is a 48 * 4 = 192 bit number, in hexadecimal form.
If you're interested in viewing this large number as a sequence of bytes, just take pairs of digits, since each byte is 8 bits. The first (counting from the left) few bytes then become 0x01, 0x23, 0x45, and so on.
It's just a big number. The only difference between the numbers you are used to (such as "192") is that it's written in using the hexadecimal number system instead of the decimal number system. The hexadecimal number system uses 16 digits (0-9 and A-F) instead of the 10 you are used to (0-9).
That particular number is equivalent to 27898229935051914480226618602452055732231960245295072615 in decimal notation.
Joachim already explained the theoretical concept. If you want to play around with such numbers yourself in Java, then take a look at java.math.BigInteger.
E.g., to convert your hexadecimal number to the decimal or any other system:
// the "radix" is 16 because the string represents a hexadecimal number
BigInteger bi = new BigInteger(
"0123456789ABCDEFFEDCBA987654321089ABCDEF01234567", 16);
// print the number in decimal (digits 0-9)
System.out.println(bi.toString(10));
// print the number in octal (digits 0-7)
System.out.println(bi.toString(8));
0123456789ABCDEF FEDCBA9876543210 89ABCDEF01234567
3 (hex) keys aka 3 * 8 bytes or3 * 8 * 8 = 192 bits.
Each character in hexadecimal corresponds to 4 bits. So for your example, there are 48 characters and 48 * 4 = 192 bits.
With regard to your second question: How does the JVM distinguish between numbers in different bases?
It does not and can not do so! You as a programmer have to support the JVM. If you specify small constants, then you use a prefix to signal either decimal, octal, or hexadecimal base:
// A leading zero signals a constant in octal base;
// octal 46 is decimal 38
final int n1 = 046;
// A leading "0x" signals a constant in hexadecimal base;
// hex 3f is decimal 63
final int n2 = 0x3f;
// No prefix refers to a regular decimal number
final int n3 = 12;
There are only prefixes for octal, decimal, and hexadecimal base because these are most often used by programmers. Note, that there is no prefix for binary constants!
If you use the java.math.BigInteger class like I did in my previous reply to your first question, then you have to specify the base in the constructor:
// input numbers in octal, decimal, and hexadecimal;
// Java needs your help to recognize the base!
final BigInteger b8 = new BigInteger("12345", 8);
final BigInteger b10 = new BigInteger("12345", 10);
final BigInteger b16 = new BigInteger("12345", 16);
// output them in decimal system
System.out.println(b8.toString()); // prints "5349"
System.out.println(b10.toString()); // prints "12345"
System.out.println(b16.toString()); // prints "74565"
Related
I have the following code:
int a=-12;
char b=(char) a;
System.out.println(b);
System.out.println(b+0);
It first prints out some empty character and then a number 65524. If I change a to, say, 16 the displayed number becomes 65520. If a is -2, the number is 65534.
If the number is positive and small enough it prints out characters out of Unicode table and returns the character's number (which is the same as a) if everything is OK and that previous strange number from above if it's not allright (if a is too big).
For instance, for a = 8451 it returns ℃ (Degree Celsius) character and a itself (8451), but if a=84510 it returns some strange Chinese symbol and a different from a number (18974). If a is even bigger a=845100 it returns empty sumbol and 58668.
The question is, where do those numbers come from?
I've tried to find the answer, but wasn't lucky so far.
EDIT Since int to char is a narrowing conversion, please consider the same question with byte a. Too large numbers are obviously impossible now, but I wonder what happens with negatives - converting byte a = -x to char gives the same weird numbers as with int a.
int is a signed number which has 4 bytes and 32 bits. The Two's complement representation of -12 is
11111111 11111111 11111111 11110011 .
char is a unsigned which has 2 bytes and 16 bits.
int a=-12;
char b=(char)a;
Two's complement representation of b is
11111111 11110011
which is equivalent to 65524
I think it's because char in Java is an unsigned "Double Byte" integer. When Byte is 8-bits, double-byte is 16-bits = 2 power by 16 = 65536 And you get Two's complement (Binary subtraction operation).
Because the number is unsigned all 16 bits are used to represent the integer, so when you give a negative number it creates an overflow you get the number which is (65536 + a), for example:
When int a = -16; you get 65536 - 16 = 65520(in binary: 1111 1111 1111 0000)
When int a = -2; you get 65536 - 2 = 65534 (in binary: 1111 1111 1111 1110)
When int a = 84510; you exceed the limit of 65536 for char, so you are left with 18974 (84510 - 65536 = 18974).
You get a character from the Unicode table, I guess because it's the character set or code page you defined.
When you cast you should pay attention to the range of values of the data types you cast, in this case, the difference between int and char.
Is this Java Api's bug?
int i = 0xD3951892;
System.out.println(i); // -745203566
String binString = Integer.toBinaryString(i);
int radix = 2;
int j = Integer.valueOf(binString, radix );
Assertions.assertThat(j).isEqualTo(i);
I expect it to be true without any question. But it throws below exception:
java.lang.NumberFormatException: For input string: "11010011100101010001100010010010"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:495)
at java.lang.Integer.valueOf(Integer.java:556)
at com.zhugw.temp.IntegerTest.test_valueof_binary_string(IntegerTest.java:14)
So if I have a binary String , e.g. 11010011100101010001100010010010, How can I get its decimal number(-745203566) in Java? DIY? Write code to implement below equation?
Integer.valueOf(String, int radix) and Integer.parseInt(String, int radix) will only parse numbers of value -2 147 483 648 to 2 147 483 647, i.e. the values of 32-bit signed integers.
These functions cannot interpret two's complement numbers for binary (radix = 2), because the string being passed can be of any length, and so a leading 1 could be part of the number or the sign bit. I guess Java's developers decided that the most logical way to proceed is to never accept two's complement, rather than assume that a 32nd bit is a sign bit.
They read your input binary string as unsigned 3 549 763 730 (bigger than max int value). To read a negative value, you'd want to give a positive binary number with a - sign in front. For example for -5:
Integer.parseInt("1011", 2); // 11
// Even if you extended the 1s to try and make two's complement of 5,
// it would always read it as a positive binary value
Integer.parseInt("-101", 2); // -5, this is right
Solutions:
I suggest, first, that if you can store it as a positive number with extra sign information on your own (e.g. a - symbol), do that. For example:
String binString;
if(i < 0)
binString = "-" + Integer.toBinaryString(-i);
else // positive i
binString = Integer.toBinaryString(i);
If you need to use signed binary strings, in order to take a negative number in binary two's complement form (as a string) and parse it to an int, I suggest you take the two's complement manually, convert that into int, and then correct the sign. Recall that two's complement = one's complement + 1, and one's complement is just reverse each bit.
As an example implementation:
String binString = "11010011100101010001100010010010";
StringBuilder onesComplementBuilder = new StringBuilder();
for(char bit : binString.toCharArray()) {
// if bit is '0', append a 1. if bit is '1', append a 0.
onesComplementBuilder.append((bit == '0') ? 1 : 0);
}
String onesComplement = onesComplementBuilder.toString();
System.out.println(onesComplement); // should be the NOT of binString
int converted = Integer.valueOf(onesComplement, 2);
// two's complement = one's complement + 1. This is the positive value
// of our original binary string, so make it negative again.
int value = -(converted + 1);
You could also write your own version of Integer.parseInt for 32-bit two's complement binary numbers. This, of course, assumes you're not using Java 8 and can't just use Integer.parseUnsignedInt, which #llogiq pointed out while I was typing this.
EDIT: You could also use Long.parseLong(String, 2) first, then calculate the two's complement (and mask it by 0xFFFFFFFF), then downgrade the long down to int. Faster to write, probably faster code.
The API docs for Integer.toBinaryString(..) explicitly state:
The value of the argument can be recovered from the returned string s by calling Integer.parseUnsignedInt(s, 8).
(as of Java 8u25) I think this is a documentation error, and it should read Integer.parseUnsignedInt(s, 2). Note the Unsigned. This is because the toBinaryString output will include the sign bit.
Edit: Note that even though this looks like it would produce an unsigned value, it isn't. This is because Java does not really have a notion of unsigned values, only a few static methods to work with ints as if they were unsigned.
I am trying to write following code.but it gives me error kindly help me.
int six=06;
int seven=07;
int abc=018;
int nine=011;
System.out.println("Octal 011 ="+nine);
System.out.println("octal O18 =" + abc);
why i cant give 018 and 019 to variable.i can give value 020 and 021 to variable.
Why this happen? what's the reason behind this Kindly tell me.
I got Following error
integer number too large: 018
int eight=018;
Octal is base-8 number system, so it means digit can be from 0 to 7, you can't use digit 8 (and 9 too) in octal number system.
// Decimal declaration and possible chars are [0-9]
int decimal = 495;
// HexaDecimal declaration starts with 0X or 0x and possible chars are [0-9A-Fa-f]
int hexa = 0X1EF;
// Octal declaration starts with 0 and possible chars are [0-7]
int octal = 0757;
// Binary representation starts with 0B or 0b and possible chars are [0-1]
int binary = 0b111101111;
If the number is string format then you can convert it into int using the below
String text = "0b111101111";
int value = text.toLowerCase().startsWith("0b") ? Integer.parseInt(text.substring(2), 2)
: Integer.decode(text);
why i cant give 018 and 019 to variable.
Because an integer literal prefixed with 0 is treated as octal, and '8' and '9' aren't valid octal digits.
From section 3.10.1 of the JLS:
An octal numeral consists of an ASCII digit 0 followed by one or more of the ASCII digits 0 through 7 interspersed with underscores, and can represent a positive, zero, or negative integer.
Trying to use '8' in an octal number is like trying to use 'G' in hex... it's simple not part of the set of symbols used in that base.
Octal numbers (base 8) can only use the following figures: 01234567. The same way that decimal numbers (base 10) can only use 0123456789.
So in octal representation, 17 + 1 is 20.
The prefix 0 indicates octal(8 base)(digits 0-7).
public class MainClass{
public static void main(String[] argv){
int intValue = 034; // 28 in decimal
int six = 06; // Equal to decimal 6
int seven = 07; // Equal to decimal 7
int eight = 010; // Equal to decimal 8
int nine = 011; // Equal to decimal 9
System.out.println("Octal 010 = " + eight);
}
}
why i cant give 018 and 019 to variable.i can give value 020 and 021 to variable.
The leading zero signifies an octal literal. However, 8 and 9 are not valid octal digits. This makes 018 and 019 invalid.
When an integer literal starts with 0 in Java, it's assumed to be in octal notation. The digits 8 and 9 are illegal in octal—the digits can range only between 0 and 7.
Because it's octal, an octal number has 8 digits which spans from 0 to 7 inclusive. For the same reason 12 would be an invalid binary number.
You need at least base 9 to have 18 and a normal decimal base for 19.
For your query.....you assign an invalid value to the variable....your assigned value is started with 0(zero) ..which means that you are assigning an octal value to the variable and when you assign a value higher then 7 such as 018 in your case...the value excedes the range of octal variables and hence show an error...so try entering simply 18 so it would take it as an integer rather than an octal variable data type...
Why does this code throw a NumberFormatException :
String binStr = "1000000000000000000000000000000000000000000000000000000000000000";
System.out.println(binStr.length());// = 64
System.out.println(Long.parseLong(binStr, 2));
1000000000000000000000000000000000000000000000000000000000000000 is larger than Long.MAX_VALUE.
See https://stackoverflow.com/a/8888969/597657
Consider using BigInteger(String val, int radix) instead.
EDIT:
OK, this is new for me. It appears that Integer.parseInt(binaryIntegerString, 2) and Long.parseLong(binaryLongString, 2) parse binary as sign-magnitude not as a 2's-complement.
Because it's out of range. 1000...000 is 263, but Long only goes up to 263 - 1.
This is the same for all of Long, Integer, Short and Byte. I'll explain with a Byte example because it's readable:
System.out.println(Byte.MIN_VALUE); // -128
System.out.println(Byte.MAX_VALUE); // 127
String positive = "1000000"; // 8 binary digits, +128
String negative = "-1000000"; // 8 binary digits, -128
String plus = "+1000000"; // 8 binary digits, +128
Byte.parseByte(positive, 2); //will fail because it's bigger than Byte.MAX_VALUE
Byte.parseByte(negative, 2); //won't fail. It will return Byte.MIN_VALUE
Byte.parseByte(plus, 2); //will fail because its bigger than Byte.MAX_VALUE
The digits are interpreted unsigned, no matter what radix is provided. If you want a negative value, you have to have the minus sign at the beginning of the String. JavaDoc says:
Parses the string argument as a signed long in the radix specified by
the second argument. The characters in the string must all be digits
of the specified radix (as determined by whether Character.digit(char, int) returns a nonnegative value), except that the first character may
be an ASCII minus sign '-' ('\u002D') to indicate a negative value or
an ASCII plus sign '+' ('\u002B') to indicate a positive value. The
resulting long value is returned.
In order to get MAX_VALUE we need:
String max = "1111111"; // 7 binary digits, +127
// or
String max2 = "+1111111"; // 7 binary digits, +127
Largest long value is actually:
0111111111111111111111111111111111111111111111111111111111111111b = 9223372036854775807
This is because Long.parseLong cannot parse two's complement representation. The only way to parse two's complement binary string representation in Java SE is BigInteger:
long l = new BigInteger("1000000000000000000000000000000000000000000000000000000000000000", 2).longValue()
this gives expected -9223372036854775808result
This is the largest possible long (9223372036854775807 = 2 exp 63 - 1) in binary format. Note the L at the end of the last digit.
long largestLong = 0B0111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111L;
Actually, this is works for me:
String bitStr = "-1000000000000000000000000000000000000000000000000000000000000000";
System.out.println(Long.parseLong(bitStr, 2));
Here is a thing: inside Long.parseLong() code logic is looking for explicit sign first. And respectively to the sign, different limits are used (Long.MAX_VALUE for positive, and Long.MIN_VALUE for negative binary literals). Probably it would be better if this logic looked up first to the eldest bit (0 for positive and 1 for negative numbers) the sign
Let's say I have a byte value of 0x12 (decimal 18). I need to convert this into decimal 12. Here's how I do it:
byte hex = 0x12;
byte dec = Byte.parseByte(String.format("%2x", hex));
System.out.println(dec); // 12
Is there a better way of doing this (for example without using strings and parsing)?
Try this:
byte dec = (byte)(hex / 16 * 10 + hex % 16);
Note that it assumes that the original input is a valid BCD encoding.
If you want to iterpret a Binary coded decimal and convert to binary, you can convert to a hexadecimal string and interpret as a decimal string. Your method is a perfectly valid way to do it (be careful, though, that bytes are signed in Java.
Read up on Binary Coded Decimals here: http://en.wikipedia.org/wiki/Binary-coded_decimal
If you want to avoid string conversion, you could separate each nibble (four bytes) and multiply by the correct value:
byte hex = 0x12;
if( hex&15 > 9 || hex>>>4 > 9)
throw new NumberFormatException(); //check for valid input
byte dec = (byte)((hex & 15) + 10*(hex>>>4 & 15));
If your input is wider than a byte, this method gets out of hand easily as you need to handle each nibble separately.
Hex to Decimal - Integer.parseInt(str,16)
Decimal to Hex - Integer.toHexString(195012)