Convert 32 bit fixed point value - java

In my Java application I need to interpret a 32 Bit Fixed Point value. The number format is as follows: The first 15 bits describe the places before the comma/point, the 16th bit represents the sign of the value and the following 16 bits describe the decimal places (1/2,1/4,1/8,1/16,...).
The input is a byte array with four values. The order of the bits in the byte array is little endian.
How can I convert such a number into Java float ?

Just do exactly what it says. Assume x is the 32bit fixed point number as int.
So, put the bits after the point, after the point, and don't use the sign here:
float f = (float)(x & 0x7fff_ffff) / (float)(1 << 16);
Put back the sign:
return x < 0 ? -f : f;
You will lose some precision. A float does not have 31 bits of precision, but your input does. It's easily adapted to doubles though.
Since the sign bit is apparently really in the middle, first get it out:
int sign = x & (1 << 16);
Join the two runs of non-sign bits:
x = (x & 0xFFFF) | ((x >> 1) & 0x7fff0000);
Then do more or less the old thing:
float f = (float)x / (float)(1 << 16);
return sign == 0 ? f : -f;
In case your input is little endian format, use the following approach to generate x:
int x = ByteBuffer.wrap(weirdFixedPoint).order(ByteOrder.LITTLE_ENDIAN).getInt();
where weirdFixedPoint is the byte array containing the 32 bit binary representation.

Related

Convert 32bit data to unsigned long value

I have something like this:
int[0] = 4123;
int[1] = 2571;
I would like to combine them and make one long value in Java.
This is my attempt:
int[] r = { 4123, 2571 };
long result = ( (r[1] & 0xFFFF) << 16 | (rs[0] & 0xFFFF) );
System.out.prinln(result);
The output should be: 10111627 but I get 168497179. Probably I miss something in conversion but don't have idea what...
EDIT
This is example how the value is placed into 32-bit register.
I try the summarize and hopefully clarify what the several comments on your question already indicate:
If you want to get the number from your image which is
00001010 00001011 00010000 00011011 = 0x0A0B101B = 168497179
in one single long value and you have two ints
0001000000011011 = 0x101B = 4123 and
0000101000001011 = 0x0A0B = 2571
than your code is correct.
I would recommend you to get used to hexadecimal numbers as they show easily that there is no binary relation between 0x0A0B & 0x101B and 0x009A4A8B = 10111627.
BTW your image is contradictory: the binary numbers represent as seen above the number 0x0A0B101B but the hexadecimals read 0x0A0B101E (notice the E) while the decimals support the binary value.
Finally, I figured out your flaw:
You seem to expect to get the decimal number concatenated together as result. But unlike the hexadecimals here it does not work this way in decimal!
Let me elaborate that. You have the binary number:
00001010 00001011 00010000 00011011
Which you can easily convert to hex block by block
0x0A 0x0B 0x10 0x1B
and than just join them together
0x0A0B101B
But that magic join is just a simplification only applying to hex (and the reason why hex is so popular among programmers).
The long version is you have to multiply the higher blocks/bytes (towards the left) with the 'basis' of the preceding block (to the right). The right most block is always multiplied by 1. The base for the next block is (since there are 8 bits in the first block) 28 = 256 = 0x100. The base for the third block is (8+8 bits) 216 = 65536 = 0x10000. The last (left most) has to be multiplied by (8+8+8 bits) 224 = 16777216 = 0x1000000.
Lets make an example for the first two blocks:
Hexadecimal:
0x10 || 0x1B
(0x10 * 0x100) + (0x1B* 0x1)
0x1000 + 0x1B = 0x101B
Decimal:
16 || 27
(16 * 256) + (27 * 1)
4096 + 27 = 4123
As you can see on your image they both in it (notice the E/B issue which is in decimal a 6/3 issue) but there is no 1627. So converting binary or hexadecimal numbers to decimal is a nontrivial task (for humans), best to use a calculator.

Storing unsigned long value in two 16bit register

I want to store unsigned long value in two 16bit register.For example if I have long value (-2,147,483,648 to 2,147,483,647) then I'm using formula like:
v[0] = myValue % 65536
v[1] = myValue / 65536
To get value from register
outVal = reg0 + (reg1 * 65536)
But how to do for unsigned long which value range is from 0 to 4,294,967,295?
As commenter harold pointed out already, your formula doesn't even work correctly for negative numbers.
You should do it bitwise instead of using math to avoid surprises (and speed things up in case the compiler didn't optimize it for you already).
Splitting:
v[0] = myValue & 0xFFFF
v[1] = myValue >> 16 // this implicitly cuts off the lower 16 bits
// by shifting them away into the nirvana
Joining:
outVal = reg0 | (reg1 << 16)
This now applies to both signed and unsigned (provided that all your variables have the same "sign type").
Legend, in case your language (which you didn't specify) uses different operators:
& is bitwise AND, | is bitwise OR, << and >> are bitwise shifting left/right (SHL/SHR), 0x marks a hexadecimal literal (you could use 65536 instead of 0xFFFF, but I think the hex literal makes it clearer where this magic number comes from).

Java shifting bytes returns an unexpected result

I am trying to shift 2 bytes into a short. These 2 bytes represent an unsigned short that in turn represents a port. I've tried multiple ways to shift these bytes into a short on java. However, I constantly fail to do this correctly.
These are the ways I've tried:
byte a = 0x17;
byte b = 0xCC;
(short)((a << 8) | b);
(short)(((short)a << 8) | b);
The result is 0xFFCC, but should be 0x17CC.
Any value that undergoes arithmetic in Java, is first cast to higher type which could cover both operands. Both of operands are cast to int if they are still smaller.
As a result, b is first cast to int and becomes 0xFFFFFFCC. Or-ing it with anything shifted by 8 bits to the left always keeps the mask 0xFFFFFF00 and therefore has no impact on result. Casting it to short just shrinks off the left 16 bits.
To resolve it, explicitly mask with 0xFF before doing the operation:
(short)(((a&0xFF)<<8)|(b&0xFF))
//Try this, since you cannot convert from int to byte:
short a = 0x17;
short b = 0xCC;
System.out.println("r = " + String.format("0x%04X", (short)((a << 8) | b)));
//Output: r = 0x17CC

Java byte to int

I know there are N threads for this question but some people are using different and different methods to convert a byte to int. Is this correct what am I writing? Hex to int or hex to decimal? Which one is the correct?
Anyway, why I'm getting 4864 instead of 19 ?
byte[] buffer = ....
buffer[51] = 0x13;
System.out.println( buffer[51] << 8 );
Is this correct what am I writing?
The code you've posted does implicit conversion of int to String, but that will display it in decimal. It's important to understand that a number isn't in either hex or decimal - it's just a number. The same number can be converted to different textual representations, and that's when the base matters. Likewise you can express the same number with different literals, so these two statements are exactly equivalent:
int x = 16;
int x = 0x10;
Anyway, why I'm getting 4864 instead of 19
Because you're explicitly shifting the value left 8 bits:
buffer[51] << 8
That's basically multiplying by 256, and 19 * 256 is 4864.
you are getting 4864 as a result because 4864 is 0x1300 in hex.
if you are expecting 19(0x13) as result then I guess you are trying to do circular shifting.
you can do that using writing like that,
/*hex 0x13 (19 in decimal) is assigned to buffer[51] as int*/
buffer[51] = 0x13;
System.out.println( Integer.rotateRight(buffer[51], 8));

Bit shift in Java

May be I am too tired.
Why dont't the following display the same value?
int x = 42405;
System.out.println(x << 8);
System.out.println((x &0x00ff) << 8);
The lower bits should be clear in both cases
EDIT: Okay, I'm leaving the bottom part for posterity...
If x is int, then it's pretty simple: x << 8 will have the same value as x & 0xff if and only if none of the "middle" 16 bits are set:
The top 8 bits of x will be rendered irrelevant by the left shift
The bottom 8 bits of x are preserved by the masking
If there are any of the "middle" 16 bits set, then x & 0xff will differ from x in a bit which is still preserved by the shift, therefore the results will be different.
I don't understand why you'd expect them to always give the same results...
I'm going to assume that the type of x is byte, and that it's actually negative.
There's no shift operation defined for byte, so first there's a transformation to int... and that's what can change depending on whether or not you've got the mask.
So let's take the case where x is -1. Then (int) x is also -1 - i.e. the bit pattern is all 1s. Shift that left by 8 bits and you end up with a bit pattern of 24 1s followed by 8 0s:
11111111111111111111111100000000 = -256
Now consider the second line of code - that's taking x & 0xff, which will only take the bottom 8 bits of the promoted value of x - i.e. 255. You shift that left by 8 bits and you end up with 16 0s, 8 1s, then 8 0s:
00000000000000001111111100000000 = 65280
Below, x is > 0xff , and in one case you mask away the upper 3 bytes, meaning you
you do (0x123 & 0x00ff) << 8 , which will be 0x23 << 8 And that is quite different from 0x123 << 8
int x = 0x123;
System.out.println(x << 8); //prints 74496
System.out.println((x &0x00ff) << 8); //prints 8960
And if x is a byte, it will get "promoted" to int before the shift, and if it's negative, it'll sign extend, and you get a whole lot of 1 bits set in the integer, which is masked away with &0xff in one case, and not masked away in the other
i.e.
byte x = (byte)0xAA; //x is negative
System.out.println(x << 8); //prints -22016
System.out.println((x &0x00ff) << 8); //prints 43520

Categories