I am trying to understand how the following line of code works:
for (int i = 0; i < numSamples; i++) {
short ampValue = 0;
for (int byteNo = 0; byteNo < 2; byteNo++) {
ampValue |= (short) ((data[pointer++] & 0xFF) << (byteNo * 8));
}
amplitudes[i] = ampValue;
}
As far as I understand, this is reading 2 bytes (as 2 bytes per sample) in a inclusive manner, i.e. the ampValue is composed of two byte reads. The data is the actual data sample (file) and the pointer is increasing to read it upto the last sample. But I don't understand this part:
"data[pointer++] & 0xFF) << (byteNo * 8)); "
Also, I am wondering whether it makes any difference if I want to read this as a double instead of short?
Looks like data[] is the array of bytes.
data[pointer++] gives you a byte value in the range [-128..127].
0xFF is an int contstant, so...
data[pointer++] & 0xFF promotes the byte value to an int value in the range [-128..127]. Then the & operator zeroes out all of the bits that are not set in 0xFF (i.e., it zeroes out the 24 upper bits, leaving only the low 8 bits.
The value of that expression now will be in the range [0..255].
The << operator shifts the result to the left by (byteNo * 8) bits. That's the same as saying, it multiplies the value by 2 raised to the power of (byteNo * 8). When byteNo==0, it will multiply by 2 to the power 0 (i.e., it will multiply by 1). When byteNo==1, it will multiply by 2 to the power 8 (i.e., it will multiply by 256).
This loop is creating an int in the range [0..65535] (16 bits) from each pair of bytes in the array, taking the first member of each pair as the low-order byte and the second member as the high-order byte.
It won't work to declare ampValue as double, because the |= operator will not work on a double, but you can declare the amplitudes[] array to be an array of double, and the assignment amplitudes[i] = ampValue will implicitly promote the value to a double value in the range [0.0..65535.0].
Additional info: Don't overlook #KevinKrumwiede's comment about a bug in the example.
In Java, all bytes are signed. The expression (data[pointer++] & 0xFF) converts the signed byte value to an int with the value of the byte if it were unsigned. Then the expression << (byteNo * 8) left-shifts the resulting value by zero or eight bits depending on the value of byteNo. The value of the whole expression is assigned with bitwise or to ampValue.
There appears to be a bug in this code. The value of ampValue is not reset to zero between iterations. And amplitude is not used. Are those identifiers supposed to be the same?
Let's break down the statement:
|= is the bitwise or and assignment operator. a |= b is equivalent to a = a | b.
(short) casts the int element from the data array to a short.
pointer++ is a post-increment operation. The value of pointer will be returned and used and then immediately incremented every single time it's accessed in this fashion - this is beneficial in this case because the outer-loop is cycling through 2-byte samples (via the inner loop) from the contiguous data buffer, so this keeps incrementing.
& is the bitwise AND operator and 0xFF is the hexadecimal value for the byte 0b11111111 (255 in decimal); the expression data[pointer++] & 0xFF is basically saying, for each bit in the byte retrieved from the data array, AND it with 1. In this context, it forces Java, which by default stores signed byte objects (i.e. values from -128 to 127 in decimal), to return the value as an unsigned byte (i.e. values from 0 to 255 decimal).
Since your samples are 2 bytes long, you need to shift the second lot of 8 bits left, as the most significant bits, using the left bit-shift operator <<. The byteNo * 8 ensures that you're only shifting bits when it's the second of the two bytes.
After the two bytes have been read, ampValue will now contain the value of the sample as a short.
Related
I am trying to convert a signed byte in unsigned. The problem is the data I am receiving is unsigned and Java does not support unsigned byte, so when it reads the data it treats it as signed.
I tried it to convert it by the following solution I got from Stack Overflow.
public static int unsignedToBytes(byte a)
{
int b = a & 0xFF;
return b;
}
But when again it's converted in byte, I get the same signed data. I am trying to use this data as a parameter to a function of Java that accepts only a byte as parameter, so I can't use any other data type. How can I fix this problem?
The fact that primitives are signed in Java is irrelevant to how they're represented in memory / transit - a byte is merely 8 bits and whether you interpret that as a signed range or not is up to you. There is no magic flag to say "this is signed" or "this is unsigned".
As primitives are signed the Java compiler will prevent you from assigning a value higher than +127 to a byte (or lower than -128). However, there's nothing to stop you downcasting an int (or short) in order to achieve this:
int i = 200; // 0000 0000 0000 0000 0000 0000 1100 1000 (200)
byte b = (byte) 200; // 1100 1000 (-56 by Java specification, 200 by convention)
/*
* Will print a negative int -56 because upcasting byte to int does
* so called "sign extension" which yields those bits:
* 1111 1111 1111 1111 1111 1111 1100 1000 (-56)
*
* But you could still choose to interpret this as +200.
*/
System.out.println(b); // "-56"
/*
* Will print a positive int 200 because bitwise AND with 0xFF will
* zero all the 24 most significant bits that:
* a) were added during upcasting to int which took place silently
* just before evaluating the bitwise AND operator.
* So the `b & 0xFF` is equivalent with `((int) b) & 0xFF`.
* b) were set to 1s because of "sign extension" during the upcasting
*
* 1111 1111 1111 1111 1111 1111 1100 1000 (the int)
* &
* 0000 0000 0000 0000 0000 0000 1111 1111 (the 0xFF)
* =======================================
* 0000 0000 0000 0000 0000 0000 1100 1000 (200)
*/
System.out.println(b & 0xFF); // "200"
/*
* You would typically do this *within* the method that expected an
* unsigned byte and the advantage is you apply `0xFF` only once
* and than you use the `unsignedByte` variable in all your bitwise
* operations.
*
* You could use any integer type longer than `byte` for the `unsignedByte` variable,
* i.e. `short`, `int`, `long` and even `char`, but during bitwise operations
* it would get casted to `int` anyway.
*/
void printUnsignedByte(byte b) {
int unsignedByte = b & 0xFF;
System.out.println(unsignedByte); // "200"
}
I'm not sure I understand your question.
I just tried this and for byte -12 (signed value) it returned integer 244 (equivalent to unsigned byte value but typed as an int):
public static int unsignedToBytes(byte b) {
return b & 0xFF;
}
public static void main(String[] args) {
System.out.println(unsignedToBytes((byte) -12));
}
Is it what you want to do?
Java does not allow to express 244 as a byte value, as would C. To express positive integers above Byte.MAX_VALUE (127) you have to use a different integral type, like short, int or long.
Complete guide for working with unsigned bytes in Java:
Unsigned byte in Java
(Source for this answer.)
The Java Language does not provide anything like the unsigned keyword. A byte according to the language spec represents a value between −128 - 127. For instance, if a byte is cast to an int Java will interpret the first bit as the sign and use sign extension.
That being said, nothing prevents you from viewing a byte simply as 8 bits and interpret those bits as a value between 0 and 255. Just keep in mind that there's nothing you can do to force your interpretation upon someone else's method. If a method accepts a byte, then that method accepts a value between −128 and 127 unless explicitly stated otherwise.
Here are a couple of useful conversions / manipulations for your convenience:
Conversions to / from int
// From int to unsigned byte
int i = 200; // some value between 0 and 255
byte b = (byte) i; // 8 bits representing that value
// From unsigned byte to int
byte b = 123; // 8 bits representing a value between 0 and 255
int i = b & 0xFF; // an int representing the same value
(Or, if you're on Java 8+, use Byte.toUnsignedInt.)
Parsing / formatting
Best way is to use the above conversions:
// Parse an unsigned byte
byte b = (byte) Integer.parseInt("200");
// Print an unsigned byte
System.out.println("Value of my unsigned byte: " + (b & 0xFF));
Arithmetics
The 2-complement representation "just works" for addition, subtraction and multiplication:
// two unsigned bytes
byte b1 = (byte) 200;
byte b2 = (byte) 15;
byte sum = (byte) (b1 + b2); // 215
byte diff = (byte) (b1 - b2); // 185
byte prod = (byte) (b2 * b2); // 225
Division requires manual conversion of operands:
byte ratio = (byte) ((b1 & 0xFF) / (b2 & 0xFF));
There are no primitive unsigned bytes in Java. The usual thing is to cast it to bigger type:
int anUnsignedByte = (int) aSignedByte & 0xff;
I think the other answers have covered memory representation and how you handle these depends on the context of how you plan on using it. I'll add that Java 8 added some support for dealing with unsigned types. In this case, you could use Byte.toUnsignedInt
int unsignedInt = Byte.toUnsignedInt(myByte);
A side note, if you want to print it out, you can just say
byte b = 255;
System.out.println((b < 0 ? 256 + b : b));
You can also:
public static int unsignedToBytes(byte a)
{
return (int) ( ( a << 24) >>> 24);
}
Explanation:
let's say a = (byte) 133;
In memory it's stored as: "1000 0101" (0x85 in hex)
So its representation translates unsigned=133, signed=-123 (as 2's complement)
a << 24
When left shift is performed 24 bits to the left, the result is now a 4 byte integer which is represented as:
"10000101 00000000 00000000 00000000" (or "0x85000000" in hex)
then we have
( a << 24) >>> 24
and it shifts again on the right 24 bits but fills with leading zeros. So it results to:
"00000000 00000000 00000000 10000101" (or "0x00000085" in hex)
and that is the unsigned representation which equals to 133.
If you tried to cast a = (int) a;
then what would happen is it keeps the 2's complement representation of byte and stores it as int also as 2's complement:
(int) "10000101" ---> "11111111 11111111 11111111 10000101"
And that translates as: -123
Although it may seem annoying (coming from C) that Java did not include unsigned byte in the language it really is no big deal since a simple "b & 0xFF" operation yields the unsigned value for (signed) byte b in the (rare) situations that it is actually needed. The bits don't actually change -- just the interpretation (which is important only when doing for example some math operations on the values).
If think you are looking for something like this.
public static char toUnsigned(byte b) {
return (char) (b >= 0 ? b : 256 + b);
}
Adamski provided the best answer, but it is not quite complete, so read his reply, as it explains the details I'm not.
If you have a system function that requires an unsigned byte to be passed to it, you can pass a signed byte as it will automatically treat it as an unsigned byte.
So if a system function requires four bytes, for example, 192 168 0 1 as unsigned bytes you can pass -64 -88 0 1, and the function will still work, because the act of passing them to the function will un-sign them.
However you are unlikely to have this problem as system functions are hidden behind classes for cross-platform compatibility, though some of the java.io read methods return unsighed bytes as an int.
If you want to see this working, try writing signed bytes to a file and read them back as unsigned bytes.
I am trying to use this data as a parameter to a function of Java that accepts only a byte as parameter
This is not substantially different from a function accepting an integer to which you want to pass a value larger than 2^32-1.
That sounds like it depends on how the function is defined and documented; I can see three possibilities:
It may explicitly document that the function treats the byte as an unsigned value, in which case the function probably should do what you expect but would seem to be implemented wrong. For the integer case, the function would probably declare the parameter as an unsigned integer, but that is not possible for the byte case.
It may document that the value for this argument must be greater than (or perhaps equal to) zero, in which case you are misusing the function (passing an out-of-range parameter), expecting it to do more than it was designed to do. With some level of debugging support you might expect the function to throw an exception or fail an assertion.
The documentation may say nothing, in which case a negative parameter is, well, a negative parameter and whether that has any meaning depends on what the function does. If this is meaningless then perhaps the function should really be defined/documented as (2). If this is meaningful in an nonobvious manner (e.g. non-negative values are used to index into an array, and negative values are used to index back from the end of the array so -1 means the last element) the documentation should say what it means and I would expect that it isn't what you want it to do anyway.
I happened to accidentally land on this page after wondering about the apparent asymmetry of the netty ByteBuf writeInt and readUnsignedInt methods.
After reading the interesting and educational answers I am still wondering what function you were calling when you said:
I am trying to use this data as a parameter to a function of Java that
accepts only a byte as parameter.
For what it's worth after so many years, here is my fifty cents:
Let's assume the method you are calling is updating some balance with micro amounts and that it behaves according to some well-defined set of requirements. Ie, it is considered to have a correct implementation for its intended behavior:
long processMicroPayment(byte amount) {
this.balance += amount;
return balance;
}
Basically, if you supply a positive amount it will be added to the balance, and a negative amount will effectively be subtracted from the balance. Now because it accepts a byte as its parameter the implicit assumption is that it functionally only accepts amounts between -128 and +127. So if you want to use this method to add, say, 130 to the balance, it simply will not produce the result YOU desire, because there is no way within the implementation of this method to represent an amount higher than 127. So passing it 130 will not result in your desired
behavior. Note that the method has no way of implementing a (say) AmountOutOfBoundsException because 130 will be 'interpreted' as a negative value that is still obeying the method's contract.
So I have the following questions:
are you using the method according to its (implicit or explicit) contract?
is the method implemented correctly?
am I still misunderstanding your question?
There is no unsigned byte in Java, but if you want to display a byte, you can do,
int myInt = 144;
byte myByte = (byte) myInt;
char myChar = (char) (myByte & 0xFF);
System.out.println("myChar :" + Integer.toHexString(myChar));
Output:
myChar : 90
For more information, please check, How to display a hex/byte value in Java.
Yes and no. Ive been digging around with this problem.
Like i understand this:
The fact is that java has signed interger -128 to 127..
It is possible to present a unsigned in java with:
public static int toUnsignedInt(byte x) {
return ((int) x) & 0xff;
}
If you for example add -12 signed number to be unsigned you get 244. But you can use that number again in signed, it has to be shifted back to signed and it´ll be again -12.
If you try to add 244 to java byte you'll get outOfIndexException.
Cheers..
If you have a function which must be passed a signed byte, what do you expect it to do if you pass an unsigned byte?
Why can't you use any other data type?
Unsually you can use a byte as an unsigned byte with simple or no translations. It all depends on how it is used. You would need to clarify what you indend to do with it.
As per limitations in Java, unsigned byte is almost impossible in the current data-type format. You can go for some other libraries of another language for what you are implementing and then you can call them using JNI.
If you want unsigned bytes in Java, just subtract 256 from the number you're interested in. It will produce two's complement with a negative value, which is the desired number in unsigned bytes.
Example:
int speed = 255; //Integer with the desired byte value
byte speed_unsigned = (byte)(speed-256);
//This will be represented in two's complement so its binary value will be 1111 1111
//which is the unsigned byte we desire.
You need to use such dirty hacks when using leJOS to program the NXT brick.
I am trying to convert a signed byte in unsigned. The problem is the data I am receiving is unsigned and Java does not support unsigned byte, so when it reads the data it treats it as signed.
I tried it to convert it by the following solution I got from Stack Overflow.
public static int unsignedToBytes(byte a)
{
int b = a & 0xFF;
return b;
}
But when again it's converted in byte, I get the same signed data. I am trying to use this data as a parameter to a function of Java that accepts only a byte as parameter, so I can't use any other data type. How can I fix this problem?
The fact that primitives are signed in Java is irrelevant to how they're represented in memory / transit - a byte is merely 8 bits and whether you interpret that as a signed range or not is up to you. There is no magic flag to say "this is signed" or "this is unsigned".
As primitives are signed the Java compiler will prevent you from assigning a value higher than +127 to a byte (or lower than -128). However, there's nothing to stop you downcasting an int (or short) in order to achieve this:
int i = 200; // 0000 0000 0000 0000 0000 0000 1100 1000 (200)
byte b = (byte) 200; // 1100 1000 (-56 by Java specification, 200 by convention)
/*
* Will print a negative int -56 because upcasting byte to int does
* so called "sign extension" which yields those bits:
* 1111 1111 1111 1111 1111 1111 1100 1000 (-56)
*
* But you could still choose to interpret this as +200.
*/
System.out.println(b); // "-56"
/*
* Will print a positive int 200 because bitwise AND with 0xFF will
* zero all the 24 most significant bits that:
* a) were added during upcasting to int which took place silently
* just before evaluating the bitwise AND operator.
* So the `b & 0xFF` is equivalent with `((int) b) & 0xFF`.
* b) were set to 1s because of "sign extension" during the upcasting
*
* 1111 1111 1111 1111 1111 1111 1100 1000 (the int)
* &
* 0000 0000 0000 0000 0000 0000 1111 1111 (the 0xFF)
* =======================================
* 0000 0000 0000 0000 0000 0000 1100 1000 (200)
*/
System.out.println(b & 0xFF); // "200"
/*
* You would typically do this *within* the method that expected an
* unsigned byte and the advantage is you apply `0xFF` only once
* and than you use the `unsignedByte` variable in all your bitwise
* operations.
*
* You could use any integer type longer than `byte` for the `unsignedByte` variable,
* i.e. `short`, `int`, `long` and even `char`, but during bitwise operations
* it would get casted to `int` anyway.
*/
void printUnsignedByte(byte b) {
int unsignedByte = b & 0xFF;
System.out.println(unsignedByte); // "200"
}
I'm not sure I understand your question.
I just tried this and for byte -12 (signed value) it returned integer 244 (equivalent to unsigned byte value but typed as an int):
public static int unsignedToBytes(byte b) {
return b & 0xFF;
}
public static void main(String[] args) {
System.out.println(unsignedToBytes((byte) -12));
}
Is it what you want to do?
Java does not allow to express 244 as a byte value, as would C. To express positive integers above Byte.MAX_VALUE (127) you have to use a different integral type, like short, int or long.
Complete guide for working with unsigned bytes in Java:
Unsigned byte in Java
(Source for this answer.)
The Java Language does not provide anything like the unsigned keyword. A byte according to the language spec represents a value between −128 - 127. For instance, if a byte is cast to an int Java will interpret the first bit as the sign and use sign extension.
That being said, nothing prevents you from viewing a byte simply as 8 bits and interpret those bits as a value between 0 and 255. Just keep in mind that there's nothing you can do to force your interpretation upon someone else's method. If a method accepts a byte, then that method accepts a value between −128 and 127 unless explicitly stated otherwise.
Here are a couple of useful conversions / manipulations for your convenience:
Conversions to / from int
// From int to unsigned byte
int i = 200; // some value between 0 and 255
byte b = (byte) i; // 8 bits representing that value
// From unsigned byte to int
byte b = 123; // 8 bits representing a value between 0 and 255
int i = b & 0xFF; // an int representing the same value
(Or, if you're on Java 8+, use Byte.toUnsignedInt.)
Parsing / formatting
Best way is to use the above conversions:
// Parse an unsigned byte
byte b = (byte) Integer.parseInt("200");
// Print an unsigned byte
System.out.println("Value of my unsigned byte: " + (b & 0xFF));
Arithmetics
The 2-complement representation "just works" for addition, subtraction and multiplication:
// two unsigned bytes
byte b1 = (byte) 200;
byte b2 = (byte) 15;
byte sum = (byte) (b1 + b2); // 215
byte diff = (byte) (b1 - b2); // 185
byte prod = (byte) (b2 * b2); // 225
Division requires manual conversion of operands:
byte ratio = (byte) ((b1 & 0xFF) / (b2 & 0xFF));
There are no primitive unsigned bytes in Java. The usual thing is to cast it to bigger type:
int anUnsignedByte = (int) aSignedByte & 0xff;
I think the other answers have covered memory representation and how you handle these depends on the context of how you plan on using it. I'll add that Java 8 added some support for dealing with unsigned types. In this case, you could use Byte.toUnsignedInt
int unsignedInt = Byte.toUnsignedInt(myByte);
A side note, if you want to print it out, you can just say
byte b = 255;
System.out.println((b < 0 ? 256 + b : b));
You can also:
public static int unsignedToBytes(byte a)
{
return (int) ( ( a << 24) >>> 24);
}
Explanation:
let's say a = (byte) 133;
In memory it's stored as: "1000 0101" (0x85 in hex)
So its representation translates unsigned=133, signed=-123 (as 2's complement)
a << 24
When left shift is performed 24 bits to the left, the result is now a 4 byte integer which is represented as:
"10000101 00000000 00000000 00000000" (or "0x85000000" in hex)
then we have
( a << 24) >>> 24
and it shifts again on the right 24 bits but fills with leading zeros. So it results to:
"00000000 00000000 00000000 10000101" (or "0x00000085" in hex)
and that is the unsigned representation which equals to 133.
If you tried to cast a = (int) a;
then what would happen is it keeps the 2's complement representation of byte and stores it as int also as 2's complement:
(int) "10000101" ---> "11111111 11111111 11111111 10000101"
And that translates as: -123
Although it may seem annoying (coming from C) that Java did not include unsigned byte in the language it really is no big deal since a simple "b & 0xFF" operation yields the unsigned value for (signed) byte b in the (rare) situations that it is actually needed. The bits don't actually change -- just the interpretation (which is important only when doing for example some math operations on the values).
If think you are looking for something like this.
public static char toUnsigned(byte b) {
return (char) (b >= 0 ? b : 256 + b);
}
Adamski provided the best answer, but it is not quite complete, so read his reply, as it explains the details I'm not.
If you have a system function that requires an unsigned byte to be passed to it, you can pass a signed byte as it will automatically treat it as an unsigned byte.
So if a system function requires four bytes, for example, 192 168 0 1 as unsigned bytes you can pass -64 -88 0 1, and the function will still work, because the act of passing them to the function will un-sign them.
However you are unlikely to have this problem as system functions are hidden behind classes for cross-platform compatibility, though some of the java.io read methods return unsighed bytes as an int.
If you want to see this working, try writing signed bytes to a file and read them back as unsigned bytes.
I am trying to use this data as a parameter to a function of Java that accepts only a byte as parameter
This is not substantially different from a function accepting an integer to which you want to pass a value larger than 2^32-1.
That sounds like it depends on how the function is defined and documented; I can see three possibilities:
It may explicitly document that the function treats the byte as an unsigned value, in which case the function probably should do what you expect but would seem to be implemented wrong. For the integer case, the function would probably declare the parameter as an unsigned integer, but that is not possible for the byte case.
It may document that the value for this argument must be greater than (or perhaps equal to) zero, in which case you are misusing the function (passing an out-of-range parameter), expecting it to do more than it was designed to do. With some level of debugging support you might expect the function to throw an exception or fail an assertion.
The documentation may say nothing, in which case a negative parameter is, well, a negative parameter and whether that has any meaning depends on what the function does. If this is meaningless then perhaps the function should really be defined/documented as (2). If this is meaningful in an nonobvious manner (e.g. non-negative values are used to index into an array, and negative values are used to index back from the end of the array so -1 means the last element) the documentation should say what it means and I would expect that it isn't what you want it to do anyway.
I happened to accidentally land on this page after wondering about the apparent asymmetry of the netty ByteBuf writeInt and readUnsignedInt methods.
After reading the interesting and educational answers I am still wondering what function you were calling when you said:
I am trying to use this data as a parameter to a function of Java that
accepts only a byte as parameter.
For what it's worth after so many years, here is my fifty cents:
Let's assume the method you are calling is updating some balance with micro amounts and that it behaves according to some well-defined set of requirements. Ie, it is considered to have a correct implementation for its intended behavior:
long processMicroPayment(byte amount) {
this.balance += amount;
return balance;
}
Basically, if you supply a positive amount it will be added to the balance, and a negative amount will effectively be subtracted from the balance. Now because it accepts a byte as its parameter the implicit assumption is that it functionally only accepts amounts between -128 and +127. So if you want to use this method to add, say, 130 to the balance, it simply will not produce the result YOU desire, because there is no way within the implementation of this method to represent an amount higher than 127. So passing it 130 will not result in your desired
behavior. Note that the method has no way of implementing a (say) AmountOutOfBoundsException because 130 will be 'interpreted' as a negative value that is still obeying the method's contract.
So I have the following questions:
are you using the method according to its (implicit or explicit) contract?
is the method implemented correctly?
am I still misunderstanding your question?
There is no unsigned byte in Java, but if you want to display a byte, you can do,
int myInt = 144;
byte myByte = (byte) myInt;
char myChar = (char) (myByte & 0xFF);
System.out.println("myChar :" + Integer.toHexString(myChar));
Output:
myChar : 90
For more information, please check, How to display a hex/byte value in Java.
Yes and no. Ive been digging around with this problem.
Like i understand this:
The fact is that java has signed interger -128 to 127..
It is possible to present a unsigned in java with:
public static int toUnsignedInt(byte x) {
return ((int) x) & 0xff;
}
If you for example add -12 signed number to be unsigned you get 244. But you can use that number again in signed, it has to be shifted back to signed and it´ll be again -12.
If you try to add 244 to java byte you'll get outOfIndexException.
Cheers..
If you have a function which must be passed a signed byte, what do you expect it to do if you pass an unsigned byte?
Why can't you use any other data type?
Unsually you can use a byte as an unsigned byte with simple or no translations. It all depends on how it is used. You would need to clarify what you indend to do with it.
As per limitations in Java, unsigned byte is almost impossible in the current data-type format. You can go for some other libraries of another language for what you are implementing and then you can call them using JNI.
If you want unsigned bytes in Java, just subtract 256 from the number you're interested in. It will produce two's complement with a negative value, which is the desired number in unsigned bytes.
Example:
int speed = 255; //Integer with the desired byte value
byte speed_unsigned = (byte)(speed-256);
//This will be represented in two's complement so its binary value will be 1111 1111
//which is the unsigned byte we desire.
You need to use such dirty hacks when using leJOS to program the NXT brick.
This question already has answers here:
java byte data type
(3 answers)
Closed 8 years ago.
since english isn't my main language and i've didn't find any pointers as to how to manually calculate the new number.
Example:
byte b = (byte) 720;
System.out.println(b); // -48
I know that most primary data types use the two complement.
Byte value ranges from -128 to 127, so it's expected to round the number down to something that fits in byte.
The Question is how do i manually calculate the -48 of the typecasted 720? I've read that i have to convert it to two complement, so taking the binary number, searching from right to left for the first one and then inverting all others and since byte only has 8 bits, take the first 8 bits. But that didn't quite work for me, it would be helpful if you would tell me how to calculate a typecasted number that doesn't fit into byte. Thanks for reading! :)
The binary representation of 702 is
10 1101 0000
Get rid of everything except the last 8 bits (because that's what fits into a byte).
1101 0000
Because of the leading 1, get the complement
0010 1111
and add 1
0011 0000
and negate the value. Gives -48.
In Java, integral types are always 2's complement. Section 4.2 of the JLS states:
The integral types are byte, short, int, and long, whose values are 8-bit, 16-bit, 32-bit and 64-bit signed two's-complement integers
You can mask out the least significant 8 bits.
int value = 720;
value &= 0xFF;
But that leaves a number in the range 0-255. Numbers higher than 127 represent negative numbers for bytes.
if (value > Byte.MAX_VALUE)
value -= 1 << 8;
This manually yields the -48 that the (byte) cast yields.
First what happens is the value (in binary) is truncated.
720 binary is 0b1011010000
We can only fit 8 bits 0b11010000
first digit 1, so the value is negative.
2's compliment gives you -48.
This is close to redundant with the answer posted by rgettman, but since you inquired about the two's complement, here is "manually" taking the 2's complement, rather than simply subtracting 256 as in that answer.
To mask the integer down to the bits that will be considered for a byte, combine it bitwise with 11111111.
int i = 720;
int x = i & 0xFF;
Then to take the two's complement:
if (x >> 7 == 1) {
x = -1 * ((x ^ 0xFF) + 1);
}
System.out.println(x);
I'm writing file save and load functions for a specific file format that I have no control over and the format specifies that at a specific byte position I must write 4 bytes of data to signify a 32bit unsigned value... in my test file this value is 16052, or 0x00003EB4... so I write to the data to the byte array that will be saved in this manner:
data[index] = 0xB4;
data[index+1] = 0x3E;
data[index+2] = 0x00;
data[index+3] = 0x00;
You can see the data is in little-endian format, which is correct... the problem is when I try to load this data with my file load function java sees the data in as such:
-76, 62, 0, 0
the 0xB4 value is being interpreted as -76 because bytes are signed in java... when I try to recompose these 4 bytes into a single 32bit value using the following code the value ends up as -76...
value = data[index+3];
value <<= 8;
value |= data[index+2];
value <<= 8;
value |= data[index+1];
value <<= 8;
value |= data[index];
What this should do is the following:
set value to 0x00 (high order byte), shift left 8 bits, or 0x00 onto the lower 8 bits, shift left 8 bits, or 0x3E onto the lower 8 bits, shift left 8 bits, or 0xB4 (low order byte) onto the lower 8 bits.
This should produce the value 0x00003EB4... which is what I started with... however for some reason I cannot figure out it is giving me the value -76 after that operation.
I am convinced this is due to java's interpretation of the 0xB4 byte as the value -76 which is screwing up the bitwise OR operation...
My question is what must I do to get around this?
Thank you.
When you are loading the bytes, they are signed. When they are coerced to integers, they are sign extended. To solve this problem, you can do a bitwise AND with 0xFF to take only the 8 LSbs of the signed integer.
In your case value |= (data[index+i]) should become value |= (data[index+i] & 0xFF) (where i is replaced with the index offsets that you have).
I've a few lines of code within a project, that I can't see the value of...
buffer[i] = (currentByte & 0x7F) | (currentByte & 0x80);
It reads the filebuffer from a file, stored as bytes, and then transfers then to buffer[i] as shown, but I can't understand what the overall purpose is, any ideas?
Thanks
As the other answers already stated, (currentByte & 0x7F) | (currentByte & 0x80) is equivalent to (currentByte & 0xFF). The JLS3 15.22.1 says this is promoted to an int:
When both operands of an operator &,
^, or | are of a type that is
convertible (§5.1.8) to a primitive
integral type, binary numeric
promotion is first performed on the
operands (§5.6.2). The type of the
bitwise operator expression is the
promoted type of the operands.
because JLS3 5.6.2 says that when currentByte has type byte and 0x7F is an int (and this is the case), then both operands are promoted to int.
Therefore, buffer will be an array of element type int or wider.
Now, by performing & 0xFF on an int, we effectively map the original byte range -128..127 into the unsigned range 0..255, an operation often used by java.io streams for example.
You can see this in action in the following code snippet. Note that to understand what is happening here, you have to know that Java stores integral types, except char, as 2's complement values.
byte b = -123;
int r = b;
System.out.println(r + "= " + Integer.toBinaryString(r));
int r2 = b & 0xFF;
System.out.println(r2 + "= " + Integer.toBinaryString(r2));
Finally, for a real-world example, check out the Javadoc and implementation of the read method of java.io.ByteArrayInputStream:
/**
* Reads the next byte of data from this input stream. The value
* byte is returned as an <code>int</code> in the range
* <code>0</code> to <code>255</code>. If no byte is available
* because the end of the stream has been reached, the value
* <code>-1</code> is returned.
*/
public synchronized int read() {
return (pos < count) ? (buf[pos++] & 0xff) : -1;
}
(currentByte & 0x7F) | (currentByte & 0x80)
is equivalent to
currentByte & (0x7F | 0x80)
which equals
currentByte & 0xFF
which is exactly the same as
currentByte
Edit: I only looked at the right side of the assignment, and I still think the equivalance is true.
However, it seems like the code wants to cast the signed byte to a larger type while interpreting the byte as unsigned.
Is there an easier way to cast signed-byte to unsigned in java?
I think someone did too much thinking here. That's just not right.
I have but one remark
The original author was worried about the run-time replacing the byte with a native signed integer (presumably 32-bit) and is explicitly trying to tell us something about the sign bit being "special"?
It's code left behind. Unless you know you're on a fishy run-time? What's the type of the 'buffer' anyway?
The complicated bitwise logic is completely superfluous.
for (int i = 0; i < buffer.length; i++) {
buffer[i] = filebuffer[currentPosition + i] & 0xff;
}
does the same thing. If buffer is declared as an array of bytes you may even leave out the & 0xff, but unfortunately the declaration is not shown.
The reason may be that the original developer was confused by bytes being signed in Java.
The result of a bitwise AND operation has a 1 on that bits where both bits are 1 while the result of a bitwise OR operation hase a on that bits where either one of bot bits is 1.
So an example evaluation for the value 0x65:
01100101 0x65
& 01111111 0x7F
===============
01100101 0x65
01100101 0x65
& 10000000 0x80
===============
00000000 0x00
01100101 0x65
| 00000000 0x00
===============
01100101 0x65
The good thing about these kinds of logical operations: you can try every possible combination (all 256 of them) and verify that you get the answer you expected.
Turns out, the file which the byte was being read from was in a signed bit notation, and of a different length, therefore it was requried to perform this task to allow it to be extended to the java int type, while retaining its correct sign :)