Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Saturday, December 27, 2025

Reading unsigned data in Java

In binary files, a single byte is often used to represent numbers from 0 to 255 (unsigned). However, in Java, a byte is signed, ranging from -128 to 127, because Java doesn't have a unsigned types (with the exception of the 2 byte char type). A raw byte with value 0xF0 in a file meant to represent 240 will become -16 when using Javas's ByteBuffer.get(). To fix this:

int unsignedByte = buffer.get() & 0xFF;

Explanation: When performing bitwise operations, Java automatically "promotes" the 8-bit byte to a 32-bit signed integer. If the byte is 0xF0 = 240 (11110000), Java sees the leading 1 and assumes it is a negative number. Through Sign Extension, it fills the new 24 bits with 1s to preserve that negative value (-16) in the larger container.

Original Byte: 11110000 (-16, see two's complement)
Promoted Int : 11111111 11111111 11111111 11110000 (Still -16)
Now, you apply the mask 0xFF (255). In binary, 0xFF as a 32-bit integer is 00000000 00000000 00000000 11111111:
  11111111 11111111 11111111 11110000 (The promoted -16)
& 00000000 00000000 00000000 11111111 (The 0xFF mask)
 -------------------------------------
  00000000 00000000 00000000 11110000 (The result: 240)

By "ANDing" the promoted integer with 0xFF, you effectively clear out all the 1s created by sign extension, leaving only the original 8 bits and giving you the correct unsigned value of 240.

Similary, reading an unsigned short (16-bit) from file:

int unsignedShort = buffer.getShort() & 0xFFFF;

Reading an unsigned int (32-bit):

long unsignedInt = buffer.getInt() & 0xFFFFFFFFL;

Note that an unsigned 32-bit integer can exceed the capacity of a Java int. You must jump up to a long and use a long literal mask (noted by the L at the end of the mask value).

When writing a value that is first multplied by a scale factor of 2^31 (1 << 31),  Java assumes the 1 << 31 is an int and shifting 1 by 31 places puts it into the sign bit position of a 32bit int, which results in the negative value of -2147483648. Correct usage:

double val = 123;
long scaleFactor = (1L << 31); // Will be positive 2147483648 because long is 64bit
                               // and shifting by 31 won't put the 1 into sign bit
                               // position
long val_scaled = (long) (val * scaleFactor);

Friday, July 11, 2025

Double-to-Int Conversion with Bit Shifting

We often need to pack a large numeric range into 32 bits. For instance, timestamps in microseconds over a 36 minute period exceed Integer.MAX_VALUE. By discarding the least significant bits (via right shift), we can fit the value and later we can recover it by the same amount of left shift. However, increasing the number of shifts decreases accuracy. What we need to optimize is to find the right amount of bit shift that covers the range and minimizes error. The following Java code investigates this:


Wednesday, February 12, 2025

Longitude convention and octal values

Recently, I encountered a bug in code that handled longitude values, where 33 degrees longitude is typically written as 033. Upon investigation, I discovered that Java was calculating 033 + 1 as 28 instead of 34. This happened because, when we write longitude values like "033" in geographic notation, we mean decimal 33 degrees. However, if we write it directly in Java, C++, or similar languages, it is interpreted as octal 33 (which equals decimal 27) due to the leading zero!

This is a classic example of why it's important to be careful when working with domain-specific number formats - what makes sense in geographic notation can have unexpected behavior when directly translated to programming language syntax!

Thursday, October 31, 2024

Handling long operations in observer chains

If you have lengthy observer notification chains where observers notify other observers, making the trigger order unpredictable, and these chains include time-consuming operations like updating a map drawing, you can use the following approach to only update the drawing when the last observer in the chain is reached:

Friday, July 12, 2024

Passing JSON to ProcessBuilder

I am using one JVM to prepare inputs for a simulation in another JVM. The simulation uses a C++ DLL, and when that DLL crashes, it takes the JVM with it. Running it in a separate JVM protects the first JVM from crashing as well. I prepare the simulation inputs as a JSON string in the first JVM and pass it to the second using ProcessBuilder. However, when passing a standard JSON, ProcessBuilder strips away the double quotes, e.g., "count": 5 becomes count: 5, which results in an invalid JSON that cannot be parsed in the main(String[] args) method. The workaround is to use jsonStr.replace("\"", "\\\"") before passing jsonStr to ProcessBuilder.

Thursday, February 8, 2024

NetBeans "the type of ... is erroneous"

If your Java project builds successfully but NetBeans 8.2 shows red marks in code with the message "the type of ... is erronous", close NetBeans, clear all files inside 8.2 cache folder. On Windows the folder is located in %LOCALAPPDATA%/NetBeans/Cache/8.2
If this does not get rid of red marks, close NetBeans, open project.properties file, Delete any extra "}" at the end of javac.classpath section, e.g. it the final line in that section should not be ${reference.mylib}} but ${reference.mylib}. This usually happens when you manually edit the file.

Tuesday, October 25, 2022

Initial values in Java and C++

In Java a variable of type int or double has the initial value of zero. But in C++, they can get random values, as you can see in the example below. Note that in C++, the easiest way to set all fields to zero is to use memset.
#include <iostream>
typedef struct {
    int n;
    double values[12];
} DATA;

int main() {
    DATA data;
    std::cout << data.n << ", " << data.values[3] << std::endl;
    memset(&data, 0, sizeof(data)); //set all fields to zero
    std::cout << data.n << ", " << data.values[3] << std::endl;
    std::cout << "Press enter..." << std::endl;
    std::cin.get();
}

Thursday, September 1, 2022

Different results when rounding floating points

Java's Math.round(0.5) and C++'s std::round(0.5) result in the value of 1 while Python 3 round(0.5) results in zero because while Java and C++ use round up, Python 3 uses round half to even.

Wednesday, June 22, 2022

Java: Table with numeric input and length checks

Sample code showing how to do numeric input and character length checks with a JTable:


Tuesday, March 8, 2022

Java: Get raw text in JFormattedTextField

You could define a custom class that derives from JFormattedTextField and use KeyListener to get the raw text that the user is typing: