How can I mask a hexadecimal int using Java? - java

I have an integer that contains a hexa value. I want to extract the first characters from this hexa value like it was a String value but I don't want to convert it to a String.
int a = 0x63C5;
int afterMask= a & 0xFFF;
System.out.println(afterMask); // this gives me "3C5" but I want to get the value "63C"
In my case I can't use String utilities like substring.

It's important to understand that an integer is just a number. There's no difference between:
int x = 0x10;
int x = 16;
Both end up with integers with the same value. The first is written in the source code as hex but it's still representing the same value.
Now, when it comes to masking, it's simplest to think of it in terms of binary, given that the operation will be performed bit-wise. So it sounds like you want bits 4-15 of the original value, but then shifted to be bits 0-11 of the result.
That's most simply expressed as a mask and then a shift:
int afterMask = (a & 0xFFF0) >> 4;
Or a shift then a mask:
int afterMask = (a >> 4) & 0xFFF;
Both will give you a value of (decimal) 1596 = (hex) 63C.
In this particular case, as your input didn't have anything in bits 12+, the mask is unnecessary - but it would be if you wanted an input of (say) 0x1263c5 to still give you an output corresponding to 0x63c.

If you want "63C" all you need is to shift right 4 bits (to drop the right most nibble). Like,
int a = 0x63C5;
int afterMask = a >> 4;
System.out.println(Integer.toHexString(afterMask));
Outputs (as requested)
63c

int a = 0x63C5;
int aftermask = a >> 4 ;
System.out.println( String.format("%X", aftermask) );

The mask you need to use is 0XFFF0

Related

How to change the most significant bit to a 1 after shifting an int to the right using '>>'?

For example, when I have a number such as 0x54 in binary that would be 01010100. After using the bit-wise operator '>>' this number will turn into 00101010. Instead of the most significant bit being a 0, I need it to be a one. How can i accomplish this?
Is your number always 8 bits wide? If thats the case you can simply have the decimal representation of 10000000 which is 128 and do a bitwise or
so let's take your example
int val = 84; /// 01010100
int newVal = val >> 1; // 00101010
int mostSig = newVal | 128; // 10101010

Can I simplify reading a short from binary data

I'm trying to simplify some code for decoding data in a file and I've written a test case to show the issue.
Given two bytes as 0xFe and 0xFF I want that to be read as 0xFFFE (65534),
the existing code does
headerBuffer.get() & 0xff + (headerBuffer.get() & 0xff) * 256
I thought, if I made buffer byte order little endian, I could get same result by reading as a short. But I do not get same result, why not ?
headerBuffer.getShort();
public void testReadingOfShort() {
ByteBuffer headerBuffer = ByteBuffer.allocate(2);
headerBuffer.order(ByteOrder.LITTLE_ENDIAN);
headerBuffer.put((byte) 0xFE);
headerBuffer.put((byte)0xFF);
headerBuffer.position(0);
int format = headerBuffer.get() & 0xff + (headerBuffer.get() & 0xff) * 256;
headerBuffer.position(0);
int formatNew = headerBuffer.getShort();
System.out.println("Format:"+format+"("+ Hex.asHex(format)+")"+":FormatNew:"
+formatNew+"("+Hex.asHex(formatNew)+")");
}
Outputs
Format:65534(0xfffe):FormatNew:-2(0xfffffffffffffffe)
You do get the same value. The problem happens when you assign the short to an int on this line:
int formatNew = headerBuffer.getShort();
When you do this, Java performs sign extension to ensure that the numeric value in the short gets converted to the same numeric value in the int. In your case, that is -2.
The representation of -2 as a short is 0xFFFE, while the int representation is 0xFFFFFFFE. In other words, the sign bit of the short is copied into the additional upper bits of int.
You can address this by not assigning the short to int. You also need to make sure that your Hex.asHex has a proper overload for short, otherwise the same conversion would happen when formatNew gets passed as an argument.
Alternatively, if you would like to treat the value of the short as unsigned, and assign it to an int, you can mask the result with 0xFFFF, like this:
int formatNew = headerBuffer.getShort() & 0xFFFF;
My hypothesis here is that in your Hex class you have a .asHex() method taking a short as an argument which does something like:
int value = (int) argument;
Tough luck. If you "upcast" from one integer type to another, the sign bit, if present, is carried. Which means that if you try and cast short 0xfffe to an int, you will NOT end up with 0x0000fffe but... 0xfffffffe. Hence your result.
If you wanted to cast it as an unsigned value you'd have to mask it, like so:
int value = (int) argument & 0xffff;
You can simply obtain the desired value as
int formatNew = headerBuffer.getShort() & 0xFFFF;
or, alternatively, if you use Java 8:
int formatNew = Short.toUnsignedInt(headerBuffer.getShort());
This will basically drop all bits from the int that are not part of a short. But it won't relieve your from the responsibility of carefully checking where you expect unsigned values, and how to handle the (naturally) signed values in the respective context.

Convert number in one base to another base in Java without using libraries

This is not a homework problem, I am too old to get home works :)
So, ideally I am trying to convert a number in a given base to another given base.
Can someone please share the logic, then probably I can write the code myself. Not able to find anything online surprisingly.
The answer depends on whether or not you can use a primitive, such as an int or long for your representation.
If you can, the algorithm is reasonably simple: convert the number in base X to a primitive representation, then convert that representation to base Y.
To convert a number to primitive, use this algorithm:
Make a running total res, and set it to zero
Go through the string representing the number number in base X left-to-right
Convert each "digit" (which may be represented by a letter) to its numeric value
Multiply running total by X, then add the numeric value of the digit to it
To convert back, use this algorithm:
Make a string builder
Remove the value of the last digit by obtaining digit = num % Y
Convert the digit value to digit character (it may be a letter)
Append the digit character to the string builder
Drop the last digit from representation by using num /= Y
Continue while num is not zero
Reverse the string in the string builder
If your number is too big for a primitive, such as int or long, you need to build a class for holding numbers greater than primitives. I would recommend using BigInteger initially, and then replacing it with your own implementation.
You could try this:
String input = /* your input */;
int inputBase = /* your input base */;
int outputBase = /* wished output base */;
int inputInt = Integer.valueOf(input, inputBase);
String output = Integer.toString(inputInt, outputBase);
Is the number a scalar or a fraction?
Extra work is required to convert the fraction part.
And it is not easy to cheat, unlike BigInteger.toString(),
BigDecimal.toString() does not take a radix.
General algorithm is :
Say you get a number in base x. It means Σ ai xi
first compute the number as a long or a BigInteger if too huge simply by iteratively computing above formula : n = a 0 + x * a1 + ...
then decompose n to base y : n0 = n, b0 = n0 % y
then iteratively : ni = ni-1 - bi-1 / y , bi = ni % y
And you get base y representation : Σ bi yi

Bitwise op unexpectedly goes negative

Can someone please explain to me why I'm getting these results?
public static int ipv4ToInt(String address) {
int result = 0;
// iterate over each octet
for(String part : address.split(Pattern.quote("."))) {
// shift the previously parsed bits over by 1 byte
result = result << 8;
System.out.printf("shift = %d\n", result);
// set the low order bits to the current octet
result |= Integer.parseInt(part);
System.out.printf("result = %d\n", result);
}
return result;
}
For ipv4ToInt("10.35.41.134"), I get:
shift = 0
result = 10
shift = 2560
result = 2595
shift = 664320
result = 664361
shift = 170076416
result = 170076550
10.35.41.134 = 170076550
This is the same result that I get when I do the math myself.
For ipv4ToInt("192.168.0.1"), I get:
shift = 0
result = 192
shift = 49152
result = 49320
shift = 12625920
result = 12625920
shift = -1062731776
result = -1062731775
192.168.0.1 = -1062731775
For this one, when I do the math manually, I get 3232235521.
Interestingly:
3232235521 = 11000000101010000000000000000001
And when I enter 1062731775 into my Windows calc and hit the +/- button, I get:
-1062731775 = 11111111111111111111111111111111 11000000101010000000000000000001
The function still works for my purposes, but I'm just really curious to know why on earth result is going negative when I do that last bit shift?
Because of bit overflow in your case!
In Java, the integer is also 32 bits and range is from -2,147,483,648 to 2,147,483,647.
12625920 << 8 crosses the limit of 2^31-1 and hence,the result turns negative...
The result just overturns from -ve side and hence,whatever range is left from the positive side is accompanied by that much from negative side!!!
As suggested by everyone,you should use long variable to avoid overflow!
All primitives in java are signed - They can be positive or negative. The highest bit is used to control this, so when it gets set, the number becomes negative.
Try using a long instead - that will give you the wanted result, as longs can be much larger without overflow being hit.
11000000101010000000000000000001 is 32 bits. The value it represents depends on how you interpret those bits:
as a 32bit signed integer, it is negative (because the left-most bit is 1)
as a 32bit unsigned integer, it is positive (like every other unsigned integer)
as the lowers bits of a long (signed or unsigned), it would give a positive value (if the left-most bits stay 0)
Java uses signed integers, so if you print the value, you'll see a negative number. That does not mean your bits are wrong.
It matters only for printing, you can use these ways for printing a positive integer:
1) change result to long (java will do the work for you).
2) handle signed int as unsigned int by yourself (possibly make a method int2string(int n) or toString(int n).
3) Integer.toUnsignedString(int) is you are using java 8.
As far as I understand, your are parsing an IP address, remember, java use signed data types, you can't have a 32 bits integer.
change result to long to fix that.

how to assign negative numbers as binary to int variable in java?

I was seeing how to represent binary numbers in java.
one option is to use as String and use Integer.parseInt() to get the decimal value;
The other option (assignment of 2 to b):
int b = 0b0010; //2
System.out.println(b);
System.out.println(Integer.toBinaryString(-2));
output:
2
11111111111111111111111111111110
using this format, how to represent -2:
int c=??//-b
int values are stored in 32 bits where the most significant bit is the sign.
0b0010; //2
is actually
0b00000000_00000000_00000000_00000010; //2
To convert that to a negative number, you flip the 0s to 1s and the 1s to 0s` and add 1. So
0b00000000_00000000_00000000_00000010; //2
0b11111111_11111111_11111111_11111101
0b11111111_11111111_11111111_11111110; // +1
And so
int b = 0b11111111_11111111_11111111_11111110;
would have the value -2.
Use the Bitwise NOT operator:
00000000000000000000000000000010 // 2 = 0b0010
00000000000000000000000000000001 // 1 = 0b0010-0b0001
11111111111111111111111111111110 // ~1 = ~(0b0010-0b0001)
11111111111111111111111111111110 // -2 = ~(0b0010-0b0001)
So you just subtract 0b001 and flip all the bits with the ~ Bitwise operator:
int b = ~(0b0010-0b0001); // ~(2-1) = ~1 = -2
System.out.println(b);
System.out.println(Integer.toBinaryString(b));
Demo
You are confusing storage with presentation. int b has no base, regardless of whether you assign 2, 0b010 or 0x02 to it. Base 10 is just something println assumes.
You can use Integer.toString(number, radix) to print properly signed binary numbers.

Categories