If I have a Java long value - say x - which should be interpreted as an unsigned value (i.e. 0x8000_0000_0000_0000 and higher should be interpreted as positive value) then how can I convert it to BigInteger?
Obviously, BigInteger.valueOf(x) would result in a negative value, and conversion to hexadecimals or bytes seems wasteful.
Actually, the conversion is pretty simple. You can use masking similar to converting unsigned integers to long:
Let's first create the mask as constant (this simply results in the least significant 32 bits set to 1):
private static final long UNSIGNED_INT_MASK = (1L << Integer.SIZE) - 1L;
then we can perform:
int unsignedInt = 0x8000_0000; // sample input value
long l = (long) unsignedInt & UNSIGNED_INT_MASK;
So for BigInteger we can create the mask like this (64 least significant bits set to 1):
// use "import static java.math.BigInteger.ONE;" to shorten this line
private static final BigInteger UNSIGNED_LONG_MASK = BigInteger.ONE.shiftLeft(Long.SIZE).subtract(BigInteger.ONE);
great, then the rest will be easy:
long unsignedLong = 0x8000_0000_0000_0000L; // sample input value
BigInteger bi = BigInteger.valueOf(unsignedLong).and(UNSIGNED_LONG_MASK);
It's not rocket science, but sometimes you just want to find a quick and easy answer.
This conversion is actually implemented in java.lang.Long in OpenJDK: Long.java:241. It's private though, so pasting it here:
/**
* Return a BigInteger equal to the unsigned value of the
* argument.
*/
private static BigInteger toUnsignedBigInteger(long i) {
if (i >= 0L)
return BigInteger.valueOf(i);
else {
int upper = (int) (i >>> 32);
int lower = (int) i;
// return (upper << 32) + lower
return (BigInteger.valueOf(Integer.toUnsignedLong(upper))).shiftLeft(32).
add(BigInteger.valueOf(Integer.toUnsignedLong(lower)));
}
}
An extensive article on unsigned long and alternatives is available on my blog: Unsigned long in Java
Related
I have a String representing a HEX value of a 64bit integer "0000000000EA6484". I need to transform it to the double value "0.9155962467" using Java. The instructions I 've been given is to format a 12.52 FP value of type int64_t (8 Bytes).
I found with some googling that the int64_t datatype in C++ is a signed integer. I have also found this post which seem to be relevant but confused me a bit.
Finally I have tried the following java code to see if I get the expected result but I get in both cases "7.5894195E-317". I am sure that either I have not understood how to solve the problem so I would appreciate some help, or that the expected output is wrong.
import java.nio.ByteBuffer;
public class Main {
public static void main(String[] args) {
String hexString = "0000000000EA6484";//0.9155962467
long longValue = Long.parseLong(hexString, 16);
longValue = Long.parseUnsignedLong(hexString, 16);
System.out.println(longValue);
double doubleValue = Double.longBitsToDouble(longValue);
System.out.println(doubleValue);
byte[] bytes = hexStringToByteArray(hexString);
doubleValue = ByteBuffer.wrap(bytes).getDouble();
System.out.println(doubleValue);
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
}
return data;
}
}
As shown, 0000000000EA6484 represents 0.9155962467193603515625 in a Q40.24 format, not a floating-point format. This is a fixed-point format with 40 integer bits (including a sign bit) and 24 fraction bits. To convert it from the integer represented by those bits in a 64-bit integer format to the value represented by the same bits in the Q12.52 format, divide it by 224: EA648416 = 1536115610, 15361156 / 224 = 0.9155962467193603515625. In Java, dividing the integer value by 16777216 (224) should suffice.
It appears whomever told you this was a 12.52 FP format was wrong. Even if there is some endian issue, or any other byte reordering, that would not explain the shifted position of the bits with respect to a 12.52 format, since it differs by a sub-byte fraction (52 bits − 24 bits = 28 bits, which is 3½ bytes).
Wondering if there is an API to calculate log_2 directly? Here is my current code, which I transfer log_2(N) to be log_e(N)/log_e(2).
BTW, it seems for normal Java Double type, there is no method to calculate log_2(double_value) directly?
My code in Java,
BigInteger x = BigInteger.valueOf(16);
BigInteger y = BigInteger.valueOf((long)(Math.log(x.longValue()) / Math.log(2)));
System.out.println(y.doubleValue()); // return 4.0 as expected
This is built in to the BigInteger API. From the Javadoc:
public int bitLength()
Returns the number of bits in the minimal two's-complement representation of this BigInteger, excluding a sign bit. For positive BigIntegers, this is equivalent to the number of bits in the ordinary binary representation. (Computes (ceil(log2(this < 0 ? -this : this+1))).)
If you want partial bits:
const twoToThe50th = Math.pow(2, 50);
const log2BigInt = (x: bigint) => {
let log = 0;
while (x > twoToThe50th) {
// Shift by 6 bytes to right to stay on byte boundaries
x = x >> BigInt(48);
log += 48;
}
// x is now small enough to be a Number, which we
// can pass to JavaScript's built in log2 function
return log + Math.log2(Number(x));
}
Now I'm try to convert some js code into java , there is a problem:
In js
46022*65535 = 3016051770
and
(46022*65535)|7867 = -1278910789
In java
46022*65535 = -1278915526 this is overflow
46022L*65535L = 3016051770L this is the same result to js
(46022*65535)|7867 = -1278910789 this one and the one below is the problem
(46022L*65535L)|7867L = 3016056507L
So , why the | operator will make two positive number to be nagtive number?
What's the different between java and js when dealing with the int and long to do this operation?
And then , how to write java code compatible with js in this situation ?
Attention:I know the range of int and long , my problem is |.
More problems :
According to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators
& is also 32bit operation, then:
In js
2996101485 & 65535 = 57709
In java
2996101485 is overflow to int so I use double to store it and cast it into int when I need to do AND.
double a = 2996101485l;
double b = 65535;
int c = (int) a & (int) b; Now c = 65535
But if I use long to cast :
long c = (long) a & (long) b; Now c = 57709
So , just simply cast double into int will cause problems. And I want to know why?
I got the problem , 2996101485 can be present in 32bit in js and in java it should be long. So I write functions to convert those operations , for example, & should use this java function to run give same result in js:
private double doOR(double x, double y) {
if (x > Integer.MAX_VALUE && x <= 1l << 32) {
if (y > Integer.MAX_VALUE && y <= 1l << 32) {
return (long) x | (long) y;
} else {
return (long) x | (int) y;
}
} else {
return (int) x | (int) y;
}
}
The problem is that while numbers in JavaScript have roughly 53-bit precision (they appear to be based on floating point doubles), the bitwise OR operates on only 32 bits.
Bitwise operators treat their operands as a sequence of 32 bits (zeroes and ones), rather than as decimal, hexadecimal, or octal numbers.
This means that when working with arithmetic, long will get you the JavaScript-like arithmetic (with numbers such as yours), since Java ints will overflow; but when working with bitwise operations, int will get you the JavaScript-like results, since then both platforms are operating on 32-bit numbers.
You should use long instead.
System.out.println(46022L*65535L); // = 3016051770
Java has ints and longs.
System.out.println(Integer.MAX_VALUE); // = 2147483647
System.out.println(Long.MAX_VALUE); // = 9,223,372,036,854,775,807
As for the language difference, I can only attribute it to different precisions between the languages. If you see this question, you'll see the largest number in JS is 9,007,199,254,740,992. That's a guess, it might be for another reason.
Here's is the situation ... i have a binary file which contains 32-bit binary strings of characters (e.g 1011011100100110101010101011010 ) and i want to convert this to integer ... I have already tried to do it with parse-Int but if the most significant value is 1, i get back a negative number and i do not want that ... Then i tried it with parse-Long and it was okay but after that when i get this integer i have to send it to another class which can receive only integers , as a result i do casting from long to int and i get back a negative integer again ... The only way to do that is with a piece of code that i found which does the opposite thing ( from int to string ) but i do not understand how to change-convert it. It is about masks which i do not know a lot of things.
Here is the code :
private static String intToBitString(int n) {
StringBuffer sb = new StringBuffer();
for (int mask = 1 << 31; mask != 0; mask = mask >>> 1)
sb.append((n & mask) == 0 ? "0" : "1");
return sb.toString();
}
Thank you in advance...
An integer with the highest bit set to 1 is a negative integer, regardless of the number of bits. Just add the heading zero to the string or alternatively clear the highest bit with bitwise AND (x & 0x7FFFFFFF). You can only store a 31 bit positive integer in java int.
Even if you assign such value to long (long x = 0xFFFFFFFF, will be -1), the sign bit expands and now you have the negative long (you can write 0x0FFFFFFFFL however to assign the expected 00000000FFFFFFFF to long). You still need to clear the high bits if this is unwanted behavior.
int a = 0x80000007; // High bit 1 - negative!
long b = a; // Sign expands!
// Clearing high bits (mind leading 0 and
// the long type suffix (L) in the hex constant:
long c = b & 0x0FFFFFFFFL;
System.out.println(a + ":" + Long.toHexString(b) + ":"
+ Long.toHexString(c));
The output: -2147483641:ffffffff80000007:80000007
I'm storing bit patterns of unsigned 64-bit numbers in a long variable and want to calculate the distance between two of them on the unsigned range. Because Java interprets long as a two's complement signed integer, I can't just do a - b, as the following example shows:
// on the unsigned range, these numbers would be adjacent
long a = 0x7fffffffffffffffL;
long b = 0x8000000000000000L;
// but as two's complement (or any representation that
// stores the sign in the first bit), they aren't
assert b - a == 1;
What's the correct way to do this?
Starting with Java 8, the comparison of long as unsigned integers can be done via Long.compareUnsigned(x, y).
Here is a simple backport for Java 7 and earlier:
public static int compareUnsigned(long x, long y) {
return Long.compare(x + Long.MIN_VALUE, y + Long.MIN_VALUE);
}
As the arithmetic wraps round, it works out the same for the case you give. If you interpret the result as an unsigned value, it will be true for all cases - you're just changing the interpretation of the bit pattern, it's still a set homomorphic to Ζ264.
If you're dealing with addition and subtraction, it doesn't matter whether you're using signed or unsigned types, as long as the arguments are both signed or both unsigned. If you need to compare a and b, compare a-b to 0.
Works for me:
long a = 0x7fffffffffffffffL;
long b = 0x8000000000000000L;
b - a = (long) 1
a - b = (long) -1
I used this solution:
if (longA == longB) return 0;
return (longA < longB) ^ (longA < 0) ^ (longB< 0) ? 1 : -1;
All credits go to this website
As previously mentioned, you won't have a problem with subtraction, so if that is all you are trying to do, then don't worry.
But, by your example, addition will overflow, and none of the relational operators will work properly. If this is a concern then you can write your own relational ops, or use a better box type than Long.
Solutions:
1. Use BigInteger instead of Long. BigInteger was created for doing calculations with large numbers and can easily support 128bit calculations.
Write your own relational operations and exclude the used of addition or multiplication as a possibility. Writing your own relational operator is really not that hard. First you compare the most significant bit. If the most significant bit is the same for both numbers, you can mask it by doing a bitwise and (&) with 0X7FFFFFFFFFFFFFFF and then compare the masked values.
I use the following code:
static boolean unsignedLessThan(long left, long right) {
return (left < right) ^ (left < 0) ^ (right < 0);
}
(based on example by Tamutnefret)
http://www.darksleep.com/player/JavaAndUnsignedTypes.html
Obviously you need deal with bits.
static boolean compare(long a, long b)
{
if(( a & (Long.MAX_VALUE + 1)) != 0)
return ( b & (Long.MAX_VALUE + 1) ) != 0
? (a < b) //same sign
: true; //a is greater b
else
return ( b & (Long.MAX_VALUE + 1) ) != 0
? false //b is greater a
: a < b; //same sign
}
Or you can do half and half like this,
public static long unsignedDiff(long a, long b) {
long mask = 0xFFFFFFFFL;
return (( ((a >> 32) & mask) - ((b >> 32) & mask) ) << 32) +
+ ((a & mask) - (b & mask));
}