UPDATED QUESTION 01/28/2016:
Since my question wasn't terribly clear before (I'm learning still), here is a re-write of my post:
Here is the scenario I find myself in:
I have some code written that reads data from a log file containing GPS coordinates formatted in the following way in hex:
"X1 X2 X3 X4 Y1 Y2 Y3 Y4"
Where the X's are the latitude component and the Y's are the longitude component. My code converts these messages into values for latitude/longitude in degrees by essentially performing the following sequence:
String strHexLat = X1 + X2 + X3 + X4; //(X1X2X3X4 viewed as one hex value)
String strHexLon = Y1 + Y2 + Y3 + Y4; //(Y1Y2Y3Y4 viewed as one hex value)
int intLat = Integer.decode(strHexLat);
int intLon = Integer.decode(strHexLon);
if ((intLat & 0x40000000) != 0) {
intLat |= 0x80000000;
}
if ((intLon & 0x40000000) != 0) {
intLon |= 0x80000000;
}
double lat = (double) intLat / 3600000; // convert from MAS to DEG
double lon = (double) intLon / 3600000; // convert from MAS to DEG
Despite not being particularly elegant, the above code does what I want it to. Where my real trouble begins is reversing the process. I am trying to write some code that will now create log files in the same format as the existing files, starting with coordinates and generating the 8 character hex array representing the coordinates.
The following snippets are what I currently have to perform this conversion, along with sample inputs, the resulting outputs, and the desired outputs:
(1) Convert coordinates in degrees to milliarcseconds:
/* TEST COORDINATES */
mLat = 42.281422;
mLon = -83.748552;
/* Convert values from degrees to milliarcseconds*/
long convLat = (long)(mLat * 3600000.0);
long convLon = (long)(mLon * 3600000.0);
Inputs:
mLat = 42.281422
mLon = -83.748552
Outputs:
convLat = 152213119
convLon = -301494787
Desired Outputs:
Above output is as desired.
(2) Account for negative values:
/* Account for negative values */
if(convLat < 0) convLat = convLat & 0x00000000ffffffffL;
if(convLon < 0) convLon = convLon & 0x00000000ffffffffL;
Inputs:
convLat = 152213119
convLon = -301494787
Outputs:
convLat = 152213119
convLon = 3993472509
Desired Outputs:
Above output is as desired.
(3) Split value into 4 values (just trying latitude component for now):
/* Split into four values */
byte[] dataLat = new byte[4];
dataLat[0] = (byte) ( ( convLat >>> 24 ) & 0xff );
dataLat[1] = (byte) ( ( convLat >>> 16 ) & 0xff );
dataLat[2] = (byte) ( ( convLat >>> 8 ) & 0xff );
dataLat[3] = (byte) ( ( convLat >>> 0 ) & 0xff );
Inputs:
convLat = 152213119
Outputs:
dataLat[0] = 9
dataLat[1] = 18
dataLat[2] = -106
dataLat[3] = 127
Desired Outputs:
***** I am not entirely certain about the negative values.
(4) Convert values into single hex string:
/* Convert to 1 hex string per component */
String hexLat = Long.toHexString(convLat);
String hexLon = Long.toHexString(convLon);
Inputs:
convLat = 152213119
convLon = 3993472509
Outputs:
hexLat = "912967f"
hexLon = "ee078dfd"
Desired Outputs:
These values are valid, and can be converted back to the desired value in degrees.
If:
convLat = 152213119 was converted to "912967f"
I want:
convLat = 152213119 to become "09 12 96 7f"
Where:
any of the four hex values can be either 1 or 2 digits and will be padded on the left with 0's, in this case it was just the first digit but it could be any of the four.
(5) Convert values into 4 hex strings:
/* Convert to 4 hex strings per component */
String[] hexStringLat = new String[4];
hexStringLat[0] = Integer.toHexString(dataLat[0]);
hexStringLat[1] = Integer.toHexString(dataLat[1]);
hexStringLat[2] = Integer.toHexString(dataLat[2]);
hexStringLat[3] = Integer.toHexString(dataLat[3]);
Inputs:
dataLat[0] = 9
dataLat[1] = 18
dataLat[2] = -106
dataLat[3] = 127
Outputs:
hexStringLat[0] = "9"
hexStringLat[1] = "12"
hexStringLat[2] = "ffffff96"
hexStringLat[3] = "7f"
Desired Outputs:
When converting to just a single hex string we get the value "912967f"
Which I want to be in the form of four strings as mentioned above, "09 12 96 7f".
When converting directly to four hex values, however, I get "9 12 ffffff96 7f".
In this case the padding operation is simple, however I do not want the 3 value to be negative.
Questions:
Why is the third value negative when converting directly to four hex characters and not when converting to just one hex string?
Is there an 'easy' way to convert the single string to the format I desire?
I could write some sloppy code to run the single code through that would try different ways of splitting the values and then testing that the string converts back, but that just seems like the wrong way to go about it.
Note:
I have found the following somewhat helpful, but not complete for the scenario I am in:
How to perform unsigned to signed conversion in Java?
Thanks in advance for the help, and I apologize if I have again left out any necessary details, please ask and I will update again as soon as possible if you need more info.
I haven't tested this, but can't you use String.format?
String.format ("%02X %02X %02X %02X", (byte) ( ( convLat >>> 24 ) & 0xff ), etc.
That is, break out each byte, as you have already done by shifting and masking, and passing them as parameters to String.format.
The 02 ensures two digits, adding a leading zero if necessary. The upper case X means use hex and use upper case A-F.
Since you already have hex string for lat and long, why not simply split it,
Matcher m = Pattern.compile(".{1,2}").matcher(hexLat.toUpperCase());
String s1 = m.find() ? hexLat.substring(m.start(), m.end()) : "";
String s2 = m.find() ? hexLat.substring(m.start(), m.end()) : "";
String s3 = m.find() ? hexLat.substring(m.start(), m.end()) : "";
String s4 = m.find() ? hexLat.substring(m.start(), m.end()) : "";
Related
The following code:
String a = "100.00";
String b = "10.00";
String c= "5.00";
String value = a+ "\n"+ b +"\n" +c;
System.out.println(value);
Prints:
100.00
10.00
5.00
I need output in a format where decimal point position will be fixed without using any string format library (with logic):
100.00
10.00
5.00
Variable values are coming from the database and requirement is to show values with the decimal point in the same position with values vertically.
Here's an example using streams; probably could be more efficient but I was having fun.
It assumes all have 2 decimals as you showed, just FYI; that could be modified though.
String a = "100.00";
String b = "10.00";
String c= "5.00";
List<String> strings = Arrays.asList(a, b, c);
final int maxLen = strings.stream().map(String::length).reduce(Math::max).get();
strings.forEach(s -> {
System.out.println(Stream.generate(() -> " ").limit(maxLen - s.length()).collect(Collectors.joining()) + s);
});
Results:
100.00
10.00
5.00
I also put pthe 3 examples into a list so it would work on an arbitrary number of elements.
Without Java 8
String a = "100.00";
String b = "10.00";
String c = "5.00";
List<String> strings = Arrays.asList(a, b, c);
int maxLen = -1;
for (String s : strings) maxLen = Math.max(maxLen, s.length());
for (String s : strings) {
String spaces = "";
for (int i = 0; i < maxLen - s.length(); ++i) {
spaces += " ";
}
System.out.println(spaces += s);
}
I don't know what 'don't use any String format library' means specifically, but... now we get into a semantic argument as to what 'library' means. You're formatting a string. If I take your question on face value you're asking for literally the impossible: How does one format a string without formatting a string?
I'm going to assume you meant: Without adding a third party dependency.
In which case, if you have doubles (or BigDecimal or float) as input:
String.format("%6.2f", 100.00);
String.format("%6.2f", 10.00);
String.format("%6.2f", 5.00);
(6? Yes; 6! The 6 is the total # of characters to print at minimum. You want 3 digits before the separator, a separator, and 2 digits after, that's a grand total of 6, hence the 6.)
If you have strings as input, evidently you are asking to right-justify them? Well, you can do that:
String.format("%6s", "100.00");
String.format("%6s", "10.00");
String.format("%6s", "5.00");
NB: For convenience, System.out.printf("%6s\n", "100.0"); is short for System.out.println(String.format("%6s", "100.0"));
I have a problem with bit operations
int progress = slider.getProgress(); value of user input
then I have to do shift left and change it to HEX
int shl = 1<<progress-1;
String hexStr = Integer.toHexString(shl);
Nex Im sending bytes by BT
byte bit = Byte.decode(hexStr)
command[2]=bit;
Now the problem
If user set for example 2 it is ok 0b100 = 0x04
But if user set 5 0b10000 = hexStr = 10 in command[2] it gets value 0x0A
Why is it changing value?
"But if user set 5 0b10000 = hexStr = 10 in command[2] it gets value = 0x0A.
Why is it changing value?"
It is correct. What different result are you expecting?
For example : If progress is 5 then...
Doing bit shift like 1 << progress-1 == 1 << 4 = (resulting bits= 0001 0000) which gives :
int shl = 10 in hex format or even int shl = 16 in decimal format
Doing String hexStr = Integer.toHexString(shl); puts shl's "10" hex string value to the other string hexStr (ie: is also now a "10")...
Doing byte bit = Byte.decode(hexStr) makes a byte with a decimal value of hexStr's "10".
This is how your result is command[2] saying hex value of 0x0A which == decimal value of 10.
....
"I'm not translating decimal to binary or hex, but the user input which tells on which position "1" should go. Hope it's clear..."
Why not just write "1" and then add as many zeroes as required (padding)?
Note: I'm not sure what value command[2]= is supposed to get. Maybe it checks the 8 bits of that byte, or maybe it expects a number (integer). It's confusng becuase your numbers rely on "1 followed by zeroes", also binary can be "1 followed by zeroes"
Binary : There are 8 bits in a byte, so the max binary you can send is 10000000 only.
Integer : A single byte is signed so the max value s 128. By this logic your options are 1, 10, 100 only.
See if this helps (check which command[2]= you want. I've commented // them out for now) :
int progress = 5;
int shl = 1 << progress-1; //why??
String hexStr = Integer.toHexString(shl);
String shlStr = Integer.toString(shl);
String zeroStr = "";
byte bit = Byte.decode(hexStr);
//command[2]=bit;
System.out.println("shl result string : " + shlStr);
System.out.println("Bytes string hex : " + hexStr);
//# Padding
for(int i = 0; i < (progress-1); i++)
{ zeroStr += "0"; }
shlStr = "1" + zeroStr;
//command[2]= Byte.decode(shlStr);
System.out.println("Result string hex : " + zeroStr);
System.out.println("shi padding string : " + shiStr);
I have been working on a project and i saw some references on web and they initialized :
int val= 0x000; output 0
int val1= 0x001; output 1
How exactly java is converting this?
Thanks
It's an hexadecimal (base 16 instead of base 10). Hexadecimals starts with 0x.... And it can contain these digits: 0123456789ABCDEF
Octals (base 8) starts with 0... and can containt digits less than 8 (01234567)
int dec = 123; // decimal: 1*(10^2) + 2*(10^1) + 3*(10^0) = 123
int oct = 0123; // octal: 1*(8^2) + 2*(8^1) + 3*(8^0) = 83
int hex = 0x123; // hexadecimal: 1*(16^2) + 2*(16^1) + 3*(16^0) = 291
You can do int val = 0; and int val = 1; with decimal notation..
The 0x before the number indicate an hexadecimal notation...
All notations are:
0b to binary: int i = 0b10101010110;
nothing to decimal: int i = 123;
0 to octal: int i = 0123345670;
0x to hexadecimal: int i = 0xAEF123;
As a matter of fact, Java does not "convert" but "interpret" the values (as hexadecimal).
Numbers starting with 0x are hexadecimal. Java converts them (like decimal ones, too) to binary and saves them.
This hexadecimal number system (base 16)
Start with 0x...
(Octals start with 0...)
Link
I have a question about converting String type binary number to bit and write in the txt file.
For example we have String like "0101011" and want to convert to bit type "0101011"
then write in to the file on the disk.
I would like to know is there anyway to covert to string to bit..
i was searching on the web they suggest to use bitarray but i am not sure
thanks
Try this:
int value = Integer.parseInt("0101011", 2); // parse base 2
Then the bit pattern in value will correspond to the binary interpretation of the string "0101011". You can then write value out to a file as a byte (assuming the string is no more than 8 binary digits).
EDIT You could also use Byte.parseByte("0101011", 2);. However, byte values in Java are always signed. If you tried to parse an 8-bit value with the 8th bit set (like "10010110", which is 150 decimal), you would get a NumberFormatException because values above +127 do not fit in a byte. If you don't need to handle bit patterns greater than "01111111", then Byte.parseByte works just as well as Integer.parseInt.
Recall, though, that to write a byte to a file, you use OutputStream.write(int), which takes an int (not byte) value—even though it only writes one byte. Might as well go with an int value to start with.
You can try the below code to avoid overflows of the numbers.
long avoidOverflows = Long.parseLong("11000000000000000000000000000000", 2);
int thisShouldBeANegativeNumber = (int) avoidOverflows;
System.out.println("Currect value : " + avoidOverflows + " -> " + "Int value : " + thisShouldBeANegativeNumber);
you can see the output
Currect value : 3221225472 -> Int value : -1073741824
//Converting String to Bytes
bytes[] cipherText= new String("0101011").getBytes()
//Converting bytes to Bits and Convert to String
StringBuilder sb = new StringBuilder(cipherText.length * Byte.SIZE);
for( int i = 0; i < Byte.SIZE * cipherText .length; i++ )
sb.append((cipherText [i / Byte.SIZE] << i % Byte.SIZE & 0x80) == 0 ? '0' : '1');
//Byte code of input in Stirn form
System.out.println("Bytecode="+sb.toString()); // some binary data
//Convert Byte To characters
String bin = sb.toString();
StringBuilder b = new StringBuilder();
int len = bin.length();
int i = 0;
while (i + 8 <= len) {
char c = convert(bin.substring(i, i+8));
i+=8;
b.append(c);
}
//String format of Binary data
System.out.println(b.toString());
I have the following code...
int Val=-32768;
String Hex=Integer.toHexString(Val);
This equates to ffff8000
int FirstAttempt=Integer.parseInt(Hex,16); // Error "Invalid Int"
int SecondAttempt=Integer.decode("0x"+Hex); // Error "Invalid Int"
So, initially, it converts the value -32768 into a hex string ffff8000, but then it can't convert the hex string back into an Integer.
In .Net it works as I'd expect, and returns -32768.
I know that I could write my own little method to convert this myself, but I'm just wondering if I'm missing something, or if this is genuinely a bug?
int val = -32768;
String hex = Integer.toHexString(val);
int parsedResult = (int) Long.parseLong(hex, 16);
System.out.println(parsedResult);
That's how you can do it.
The reason why it doesn't work your way: Integer.parseInt takes a signed int, while toHexString produces an unsigned result. So if you insert something higher than 0x7FFFFFF, an error will be thrown automatically. If you parse it as long instead, it will still be signed. But when you cast it back to int, it will overflow to the correct value.
It overflows, because the number is negative.
Try this and it will work:
int n = (int) Long.parseLong("ffff8000", 16);
int to Hex :
Integer.toHexString(intValue);
Hex to int :
Integer.valueOf(hexString, 16).intValue();
You may also want to use long instead of int (if the value does not fit the int bounds):
Hex to long:
Long.valueOf(hexString, 16).longValue()
long to Hex
Long.toHexString(longValue)
It's worth mentioning that Java 8 has the methods Integer.parseUnsignedInt and Long.parseUnsignedLong that does what you wanted, specifically:
Integer.parseUnsignedInt("ffff8000",16) == -32768
The name is a bit confusing, as it parses a signed integer from a hex string, but it does the work.
Try using BigInteger class, it works.
int Val=-32768;
String Hex=Integer.toHexString(Val);
//int FirstAttempt=Integer.parseInt(Hex,16); // Error "Invalid Int"
//int SecondAttempt=Integer.decode("0x"+Hex); // Error "Invalid Int"
BigInteger i = new BigInteger(Hex,16);
System.out.println(i.intValue());
As Integer.toHexString(byte/integer) is not working when you are trying to convert signed bytes like UTF-16 decoded characters you have to use:
Integer.toString(byte/integer, 16);
or
String.format("%02X", byte/integer);
reverse you can use
Integer.parseInt(hexString, 16);
Java's parseInt method is actally a bunch of code eating "false" hex : if you want to translate -32768, you should convert the absolute value into hex, then prepend the string with '-'.
There is a sample of Integer.java file :
public static int parseInt(String s, int radix)
The description is quite explicit :
* Parses the string argument as a signed integer in the radix
* specified by the second argument. The characters in the string
...
...
* parseInt("0", 10) returns 0
* parseInt("473", 10) returns 473
* parseInt("-0", 10) returns 0
* parseInt("-FF", 16) returns -255
Using Integer.toHexString(...) is a good answer. But personally prefer to use String.format(...).
Try this sample as a test.
byte[] values = new byte[64];
Arrays.fill(values, (byte)8); //Fills array with 8 just for test
String valuesStr = "";
for(int i = 0; i < values.length; i++)
valuesStr += String.format("0x%02x", values[i] & 0xff) + " ";
valuesStr.trim();
Below code would work:
int a=-32768;
String a1=Integer.toHexString(a);
int parsedResult=(int)Long.parseLong(a1,16);
System.out.println("Parsed Value is " +parsedResult);
Hehe, curious. I think this is an "intentianal bug", so to speak.
The underlying reason is how the Integer class is written. Basically, parseInt is "optimized" for positive numbers. When it parses the string, it builds the result cumulatively, but negated. Then it flips the sign of the end-result.
Example:
66 = 0x42
parsed like:
4*(-1) = -4
-4 * 16 = -64 (hex 4 parsed)
-64 - 2 = -66 (hex 2 parsed)
return -66 * (-1) = 66
Now, let's look at your example
FFFF8000
16*(-1) = -16 (first F parsed)
-16*16 = -256
-256 - 16 = -272 (second F parsed)
-272 * 16 = -4352
-4352 - 16 = -4368 (third F parsed)
-4352 * 16 = -69888
-69888 - 16 = -69904 (forth F parsed)
-69904 * 16 = -1118464
-1118464 - 8 = -1118472 (8 parsed)
-1118464 * 16 = -17895552
-17895552 - 0 = -17895552 (first 0 parsed)
Here it blows up since -17895552 < -Integer.MAX_VALUE / 16 (-134217728).
Attempting to execute the next logical step in the chain (-17895552 * 16)
would cause an integer overflow error.
Edit (addition): in order for the parseInt() to work "consistently" for -Integer.MAX_VALUE <= n <= Integer.MAX_VALUE, they would have had to implement logic to "rotate" when reaching -Integer.MAX_VALUE in the cumulative result, starting over at the max-end of the integer range and continuing downwards from there. Why they did not do this, one would have to ask Josh Bloch or whoever implemented it in the first place. It might just be an optimization.
However,
Hex=Integer.toHexString(Integer.MAX_VALUE);
System.out.println(Hex);
System.out.println(Integer.parseInt(Hex.toUpperCase(), 16));
works just fine, for just this reason. In the sourcee for Integer you can find this comment.
// Accumulating negatively avoids surprises near MAX_VALUE