How do I compare two longs as unsigned in Java? - java

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));
}

Related

Java - Adding multiple longs overflow/underflow check [duplicate]

How does Java handle integer underflows and overflows?
Leading on from that, how would you check/test that this is occurring?
If it overflows, it goes back to the minimum value and continues from there. If it underflows, it goes back to the maximum value and continues from there.
You can check that beforehand as follows:
public static boolean willAdditionOverflow(int left, int right) {
if (right < 0 && right != Integer.MIN_VALUE) {
return willSubtractionOverflow(left, -right);
} else {
return (~(left ^ right) & (left ^ (left + right))) < 0;
}
}
public static boolean willSubtractionOverflow(int left, int right) {
if (right < 0) {
return willAdditionOverflow(left, -right);
} else {
return ((left ^ right) & (left ^ (left - right))) < 0;
}
}
(you can substitute int by long to perform the same checks for long)
If you think that this may occur more than often, then consider using a datatype or object which can store larger values, e.g. long or maybe java.math.BigInteger. The last one doesn't overflow, practically, the available JVM memory is the limit.
If you happen to be on Java8 already, then you can make use of the new Math#addExact() and Math#subtractExact() methods which will throw an ArithmeticException on overflow.
public static boolean willAdditionOverflow(int left, int right) {
try {
Math.addExact(left, right);
return false;
} catch (ArithmeticException e) {
return true;
}
}
public static boolean willSubtractionOverflow(int left, int right) {
try {
Math.subtractExact(left, right);
return false;
} catch (ArithmeticException e) {
return true;
}
}
The source code can be found here and here respectively.
Of course, you could also just use them right away instead of hiding them in a boolean utility method.
Well, as far as primitive integer types go, Java doesnt handle Over/Underflow at all (for float and double the behaviour is different, it will flush to +/- infinity just as IEEE-754 mandates).
When adding two int's, you will get no indication when an overflow occurs. A simple method to check for overflow is to use the next bigger type to actually perform the operation and check if the result is still in range for the source type:
public int addWithOverflowCheck(int a, int b) {
// the cast of a is required, to make the + work with long precision,
// if we just added (a + b) the addition would use int precision and
// the result would be cast to long afterwards!
long result = ((long) a) + b;
if (result > Integer.MAX_VALUE) {
throw new RuntimeException("Overflow occured");
} else if (result < Integer.MIN_VALUE) {
throw new RuntimeException("Underflow occured");
}
// at this point we can safely cast back to int, we checked before
// that the value will be withing int's limits
return (int) result;
}
What you would do in place of the throw clauses, depends on your applications requirements (throw, flush to min/max or just log whatever). If you want to detect overflow on long operations, you're out of luck with primitives, use BigInteger instead.
Edit (2014-05-21): Since this question seems to be referred to quite frequently and I had to solve the same problem myself, its quite easy to evaluate the overflow condition by the same method a CPU would calculate its V flag.
Its basically a boolean expression that involves the sign of both operands as well as the result:
/**
* Add two int's with overflow detection (r = s + d)
*/
public static int add(final int s, final int d) throws ArithmeticException {
int r = s + d;
if (((s & d & ~r) | (~s & ~d & r)) < 0)
throw new ArithmeticException("int overflow add(" + s + ", " + d + ")");
return r;
}
In java its simpler to apply the expression (in the if) to the entire 32 bits, and check the result using < 0 (this will effectively test the sign bit). The principle works exactly the same for all integer primitive types, changing all declarations in above method to long makes it work for long.
For smaller types, due to the implicit conversion to int (see the JLS for bitwise operations for details), instead of checking < 0, the check needs to mask the sign bit explicitly (0x8000 for short operands, 0x80 for byte operands, adjust casts and parameter declaration appropiately):
/**
* Subtract two short's with overflow detection (r = d - s)
*/
public static short sub(final short d, final short s) throws ArithmeticException {
int r = d - s;
if ((((~s & d & ~r) | (s & ~d & r)) & 0x8000) != 0)
throw new ArithmeticException("short overflow sub(" + s + ", " + d + ")");
return (short) r;
}
(Note that above example uses the expression need for subtract overflow detection)
So how/why do these boolean expressions work? First, some logical thinking reveals that an overflow can only occur if the signs of both arguments are the same. Because, if one argument is negative and one positive, the result (of add) must be closer to zero, or in the extreme case one argument is zero, the same as the other argument. Since the arguments by themselves can't create an overflow condition, their sum can't create an overflow either.
So what happens if both arguments have the same sign? Lets take a look at the case both are positive: adding two arguments that create a sum larger than the types MAX_VALUE, will always yield a negative value, so an overflow occurs if arg1 + arg2 > MAX_VALUE. Now the maximum value that could result would be MAX_VALUE + MAX_VALUE (the extreme case both arguments are MAX_VALUE). For a byte (example) that would mean 127 + 127 = 254. Looking at the bit representations of all values that can result from adding two positive values, one finds that those that overflow (128 to 254) all have bit 7 set, while all that do not overflow (0 to 127) have bit 7 (topmost, sign) cleared. Thats exactly what the first (right) part of the expression checks:
if (((s & d & ~r) | (~s & ~d & r)) < 0)
(~s & ~d & r) becomes true, only if, both operands (s, d) are positive and the result (r) is negative (the expression works on all 32 bits, but the only bit we're interested in is the topmost (sign) bit, which is checked against by the < 0).
Now if both arguments are negative, their sum can never be closer to zero than any of the arguments, the sum must be closer to minus infinity. The most extreme value we can produce is MIN_VALUE + MIN_VALUE, which (again for byte example) shows that for any in range value (-1 to -128) the sign bit is set, while any possible overflowing value (-129 to -256) has the sign bit cleared. So the sign of the result again reveals the overflow condition. Thats what the left half (s & d & ~r) checks for the case where both arguments (s, d) are negative and a result that is positive. The logic is largely equivalent to the positive case; all bit patterns that can result from adding two negative values will have the sign bit cleared if and only if an underflow occured.
By default, Java's int and long math silently wrap around on overflow and underflow. (Integer operations on other integer types are performed by first promoting the operands to int or long, per JLS 4.2.2.)
As of Java 8, java.lang.Math provides addExact, subtractExact, multiplyExact, incrementExact, decrementExact and negateExact static methods for both int and long arguments that perform the named operation, throwing ArithmeticException on overflow. (There's no divideExact method -- you'll have to check the one special case (MIN_VALUE / -1) yourself.)
As of Java 8, java.lang.Math also provides toIntExact to cast a long to an int, throwing ArithmeticException if the long's value does not fit in an int. This can be useful for e.g. computing the sum of ints using unchecked long math, then using toIntExact to cast to int at the end (but be careful not to let your sum overflow).
If you're still using an older version of Java, Google Guava provides IntMath and LongMath static methods for checked addition, subtraction, multiplication and exponentiation (throwing on overflow). These classes also provide methods to compute factorials and binomial coefficients that return MAX_VALUE on overflow (which is less convenient to check). Guava's primitive utility classes, SignedBytes, UnsignedBytes, Shorts and Ints, provide checkedCast methods for narrowing larger types (throwing IllegalArgumentException on under/overflow, not ArithmeticException), as well as saturatingCast methods that return MIN_VALUE or MAX_VALUE on overflow.
Java doesn't do anything with integer overflow for either int or long primitive types and ignores overflow with positive and negative integers.
This answer first describes the of integer overflow, gives an example of how it can happen, even with intermediate values in expression evaluation, and then gives links to resources that give detailed techniques for preventing and detecting integer overflow.
Integer arithmetic and expressions reslulting in unexpected or undetected overflow are a common programming error. Unexpected or undetected integer overflow is also a well-known exploitable security issue, especially as it affects array, stack and list objects.
Overflow can occur in either a positive or negative direction where the positive or negative value would be beyond the maximum or minimum values for the primitive type in question. Overflow can occur in an intermediate value during expression or operation evaluation and affect the outcome of an expression or operation where the final value would be expected to be within range.
Sometimes negative overflow is mistakenly called underflow. Underflow is what happens when a value would be closer to zero than the representation allows. Underflow occurs in integer arithmetic and is expected. Integer underflow happens when an integer evaluation would be between -1 and 0 or 0 and 1. What would be a fractional result truncates to 0. This is normal and expected with integer arithmetic and not considered an error. However, it can lead to code throwing an exception. One example is an "ArithmeticException: / by zero" exception if the result of integer underflow is used as a divisor in an expression.
Consider the following code:
int bigValue = Integer.MAX_VALUE;
int x = bigValue * 2 / 5;
int y = bigValue / x;
which results in x being assigned 0 and the subsequent evaluation of bigValue / x throws an exception, "ArithmeticException: / by zero" (i.e. divide by zero), instead of y being assigned the value 2.
The expected result for x would be 858,993,458 which is less than the maximum int value of 2,147,483,647. However, the intermediate result from evaluating Integer.MAX_Value * 2, would be 4,294,967,294, which exceeds the maximum int value and is -2 in accordance with 2s complement integer representations. The subsequent evaluation of -2 / 5 evaluates to 0 which gets assigned to x.
Rearranging the expression for computing x to an expression that, when evaluated, divides before multiplying, the following code:
int bigValue = Integer.MAX_VALUE;
int x = bigValue / 5 * 2;
int y = bigValue / x;
results in x being assigned 858,993,458 and y being assigned 2, which is expected.
The intermediate result from bigValue / 5 is 429,496,729 which does not exceed the maximum value for an int. Subsequent evaluation of 429,496,729 * 2 doesn't exceed the maximum value for an int and the expected result gets assigned to x. The evaluation for y then does not divide by zero. The evaluations for x and y work as expected.
Java integer values are stored as and behave in accordance with 2s complement signed integer representations. When a resulting value would be larger or smaller than the maximum or minimum integer values, a 2's complement integer value results instead. In situations not expressly designed to use 2s complement behavior, which is most ordinary integer arithmetic situations, the resulting 2s complement value will cause a programming logic or computation error as was shown in the example above. An excellent Wikipedia article describes 2s compliment binary integers here: Two's complement - Wikipedia
There are techniques for avoiding unintentional integer overflow. Techinques may be categorized as using pre-condition testing, upcasting and BigInteger.
Pre-condition testing comprises examining the values going into an arithmetic operation or expression to ensure that an overflow won't occur with those values. Programming and design will need to create testing that ensures input values won't cause overflow and then determine what to do if input values occur that will cause overflow.
Upcasting comprises using a larger primitive type to perform the arithmetic operation or expression and then determining if the resulting value is beyond the maximum or minimum values for an integer. Even with upcasting, it is still possible that the value or some intermediate value in an operation or expression will be beyond the maximum or minimum values for the upcast type and cause overflow, which will also not be detected and will cause unexpected and undesired results. Through analysis or pre-conditions, it may be possible to prevent overflow with upcasting when prevention without upcasting is not possible or practical. If the integers in question are already long primitive types, then upcasting is not possible with primitive types in Java.
The BigInteger technique comprises using BigInteger for the arithmetic operation or expression using library methods that use BigInteger. BigInteger does not overflow. It will use all available memory, if necessary. Its arithmetic methods are normally only slightly less efficient than integer operations. It is still possible that a result using BigInteger may be beyond the maximum or minimum values for an integer, however, overflow will not occur in the arithmetic leading to the result. Programming and design will still need to determine what to do if a BigInteger result is beyond the maximum or minimum values for the desired primitive result type, e.g., int or long.
The Carnegie Mellon Software Engineering Institute's CERT program and Oracle have created a set of standards for secure Java programming. Included in the standards are techniques for preventing and detecting integer overflow. The standard is published as a freely accessible online resource here: The CERT Oracle Secure Coding Standard for Java
The standard's section that describes and contains practical examples of coding techniques for preventing or detecting integer overflow is here: NUM00-J. Detect or prevent integer overflow
Book form and PDF form of The CERT Oracle Secure Coding Standard for Java are also available.
Having just kinda run into this problem myself, here's my solution (for both multiplication and addition):
static boolean wouldOverflowOccurwhenMultiplying(int a, int b) {
// If either a or b are Integer.MIN_VALUE, then multiplying by anything other than 0 or 1 will result in overflow
if (a == 0 || b == 0) {
return false;
} else if (a > 0 && b > 0) { // both positive, non zero
return a > Integer.MAX_VALUE / b;
} else if (b < 0 && a < 0) { // both negative, non zero
return a < Integer.MAX_VALUE / b;
} else { // exactly one of a,b is negative and one is positive, neither are zero
if (b > 0) { // this last if statements protects against Integer.MIN_VALUE / -1, which in itself causes overflow.
return a < Integer.MIN_VALUE / b;
} else { // a > 0
return b < Integer.MIN_VALUE / a;
}
}
}
boolean wouldOverflowOccurWhenAdding(int a, int b) {
if (a > 0 && b > 0) {
return a > Integer.MAX_VALUE - b;
} else if (a < 0 && b < 0) {
return a < Integer.MIN_VALUE - b;
}
return false;
}
feel free to correct if wrong or if can be simplified. I've done some testing with the multiplication method, mostly edge cases, but it could still be wrong.
There are libraries that provide safe arithmetic operations, which check integer overflow/underflow . For example, Guava's IntMath.checkedAdd(int a, int b) returns the sum of a and b, provided it does not overflow, and throws ArithmeticException if a + b overflows in signed int arithmetic.
It wraps around.
e.g:
public class Test {
public static void main(String[] args) {
int i = Integer.MAX_VALUE;
int j = Integer.MIN_VALUE;
System.out.println(i+1);
System.out.println(j-1);
}
}
prints
-2147483648
2147483647
Since java8 the java.lang.Math package has methods like addExact() and multiplyExact() which will throw an ArithmeticException when an overflow occurs.
I think you should use something like this and it is called Upcasting:
public int multiplyBy2(int x) throws ArithmeticException {
long result = 2 * (long) x;
if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE){
throw new ArithmeticException("Integer overflow");
}
return (int) result;
}
You can read further here:
Detect or prevent integer overflow
It is quite reliable source.
It doesn't do anything -- the under/overflow just happens.
A "-1" that is the result of a computation that overflowed is no different from the "-1" that resulted from any other information. So you can't tell via some status or by inspecting just a value whether it's overflowed.
But you can be smart about your computations in order to avoid overflow, if it matters, or at least know when it will happen. What's your situation?
static final int safeAdd(int left, int right)
throws ArithmeticException {
if (right > 0 ? left > Integer.MAX_VALUE - right
: left < Integer.MIN_VALUE - right) {
throw new ArithmeticException("Integer overflow");
}
return left + right;
}
static final int safeSubtract(int left, int right)
throws ArithmeticException {
if (right > 0 ? left < Integer.MIN_VALUE + right
: left > Integer.MAX_VALUE + right) {
throw new ArithmeticException("Integer overflow");
}
return left - right;
}
static final int safeMultiply(int left, int right)
throws ArithmeticException {
if (right > 0 ? left > Integer.MAX_VALUE/right
|| left < Integer.MIN_VALUE/right
: (right < -1 ? left > Integer.MIN_VALUE/right
|| left < Integer.MAX_VALUE/right
: right == -1
&& left == Integer.MIN_VALUE) ) {
throw new ArithmeticException("Integer overflow");
}
return left * right;
}
static final int safeDivide(int left, int right)
throws ArithmeticException {
if ((left == Integer.MIN_VALUE) && (right == -1)) {
throw new ArithmeticException("Integer overflow");
}
return left / right;
}
static final int safeNegate(int a) throws ArithmeticException {
if (a == Integer.MIN_VALUE) {
throw new ArithmeticException("Integer overflow");
}
return -a;
}
static final int safeAbs(int a) throws ArithmeticException {
if (a == Integer.MIN_VALUE) {
throw new ArithmeticException("Integer overflow");
}
return Math.abs(a);
}
There is one case, that is not mentioned above:
int res = 1;
while (res != 0) {
res *= 2;
}
System.out.println(res);
will produce:
0
This case was discussed here:
Integer overflow produces Zero.
I think this should be fine.
static boolean addWillOverFlow(int a, int b) {
return (Integer.signum(a) == Integer.signum(b)) &&
(Integer.signum(a) != Integer.signum(a+b));
}

i dont understand what is 0x7fffffff mean. is there any other way to code getHashValue method?

public int getHashValue(K key){
return (key.hashCode() & 0x7fffffff) % size;
}
i dont understand what is 0x7fffffff mean. is there any other way to code getHasValue method?
The constant 0x7FFFFFFF is a 32-bit integer in hexadecimal with all but the highest bit set.
Despite the name, this method isn't getting the hashCode, rather looking for which bucket the key should appear in for a hash set or map.
When you use % on negative value, you get a negative value. There are no negative buckets so to avoid this you can remove the sign bit (the highest bit) and one way of doing this is to use a mask e.g. x & 0x7FFFFFFF which keeps all the bits except the top one. Another way to do this is to shift the output x >>> 1 however this is slower.
A slightly better approach is to use "take the modulus and apply Math.abs". This uses all the bits of the hashCode which might be better.
e.g.
public int getBucket(K key) {
return Math.abs(key.hashCode() % size);
}
Even this is not ideal as some hashCode() have a poor distribution resulting in a higher collision rate. You might want to agitate the hashcode before the modulus etc.
public int getBucket(K key) {
return Math.abs(hash(key) % size);
}
HashMap in java 8 uses this
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
The function is simple as it handles collisions efficiently. In Java 7 it used this function.
static int hash(int h) {
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
That's the Hexadecimal representation of the Max. Integer
You can check here
0x7fffffff just remove the signal getting the complement of the number.
Using Java REPL you can see the results of the operation
> -7 & 0x7fffffff
java.lang.Integer res1 = 2147483641
> 2147483641 & 0x7fffffff
java.lang.Integer res2 = 2147483641
> 2147483641 + 6
java.lang.Integer res3 = 2147483647
> 7 + 2147483641
java.lang.Integer res4 = -2147483648
In the binary representation, the first bit is the signal. If you set it to zero you will get positive complementary if the number is negative. Or the same number if positive.

How to convert the var in js into java?

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.

How to disable Conversions and Promotions in Java?

Ok. I think this is impossible. If you think the same, you do not need to post an answer. I have read a few lines of Chapter 5. Conversions and Promotions and it seems chapter 5 has no mention of disabling Conversions and Promotions in Java.
Here is my motivation:
long uADD(long a, long b) {
try {
long c;
c = 0;
boolean carry; //carry flag; true: need to carry; false: no need to carry
carry = false;
for (int i = 0; i < 64; ++i) { //i loops from 0 to 63,
if (((((a >>> i) & 1) ^ ((b >>> i)) & 1) != 0) ^ carry) { //calculate the ith digit of the sum
c += (1 << i);
}
if (((((a >>> i) & 1) & ((b >>> i) & 1)) != 0) || (carry && ((((a >>> i) & 1) ^ ((b >>> i) & 1)) != 0))) {
carry = true; //calculate the carry flag which will be used for calculation of the (i+1)th digit
} else {
carry = false;
}
}
if (carry) { //check if there is a last carry flag
throw new ArithmeticException(); //throw arithmetic exception if true
}
return c;
} catch (ArithmeticException arithmExcep) {
throw new ArithmeticException("Unsigned Long integer Overflow during Addition");
}
}
So basically, I am writing a method that will do unsigned addition for long integer. It will throw arithmetic exception if overflow. The code above is not readable enough, so I should try to explain it.
First, there is a for loop where i loops from 0 to 63.
Then, the first if statement acts as the sum output of the full adder, it uses the ith digit of a and that of b and carry flag to calculate the i + 1th digit (true or false). (Note that i = 0 corresponds to the units digit.) If true, it adds 1 << i to c, where c is initially 0.
After that, the second if statement acts as the carry flag output of the full adder, it uses again the ith digit of a and that of b and carry flag to calculate the carry flag of the i + 1th digit. If true, set the new carry flag to true, if false, set the new carry flag false.
Finally, after exit the for loop, check if the carry flag is true. If true, throw arithmetic exception.
However, the above code does not work. After debugging, it turns out the problem occurs at
c += (1 << i);
The correct code should be:
c += (1L << i);
because Java will automatically promote integer 1 << i to Long and add it to c, showing no warning to me.
I have several questions regarding to this.
Is it possible to disable automatic promotion of one data type to another
How often does automatic promotion causing problem to you?
Is it possible to tweak the IDE so that it shows a warning to me when automatic promotion occurs? (I am using NetBeans IDE 7.3.1 at the moment.)
Sorry for lots of questions and the hard to read code. I will be studying CS in September so I try to write some code in Java to familiarize myself with Java.
Is it possible to disable automatic promotion of one data type to another
No: as you already discovered the Java Language Specification mandates numeric promotion to occur, any compiler doing this would (by definition) not be a valid Java Compiler.
How often does automatic promotion causing problem to you?
Perhaps once a year (and I code in Java for a living)?
Is it possible to tweak the IDE so that it shows a warning to me when automatic promotion occurs? (I am using NetBeans IDE 7.3.1 at the moment.)
It is worth noting that such a warning would not detect all cases where an explicit promotion is needed. For instance, consider:
boolean isNearOrigin(int x, int y, int r) {
return x * x + y + y < r * r;
}
Even though there is no automatic promotion, the multiplications may overflow, which can make the method return incorrect results, and one should probably write
return (long) x * x + (long) y + y < (long) r * r;
instead.
It's also worth noting that your proposed warning would also appear for correct code. For instance:
int x = ...;
foo(x);
would warn about automatic promotion if foo is declared with parameter type long, even though that promotion can not have any adverse effects. Since such innocent situations are quite frequent, your warning would probably be so annoying that everybody would turn it off. I'd therefore by quite surprised to find any Java compiler emit such a warning.
In general, the compiler can not detect that an operation will overflow, and even finding likely candidates for overflow is complex. Given the rarity of overflow-related problems, such an imperfect detection seems a dubious benefit, which is probably why Java compilers and IDEs do not implement it. It therefore remains the responsibility of the programmer to verify, for each arithmetic operation, that the value set afforded by the operand types is suitable. This includes specifying suitable type suffixes for any numeric literals used as operands.
PS: Though I am impressed that you got your ripple-carry adder working, I think your uAdd method could be more easily implemented as follows:
long uAdd(long a, long b) {
long sum = a + b;
if (uLess(sum, a)) {
throw new ArithmeticException("Overflow");
} else {
return sum;
}
}
/** #return whether a < b, treating both a and b as unsigned longs */
boolean uLess(long a, long b) {
long signBit = 1L << -1;
return (signBit ^ a) < (signBit ^ b);
}
To see why this is correct, let < denote the less than relation for the signed interpretation (which is equivalent to the Java operator), and ≪ denote the less than relation for the unsigned values. Let a and b be any bit pattern, from which a' and b' are obtained by flipping the sign bit. By the definition of signed integers, we then have:
If sign(a) = sign(b), we have (a ≪ b) = (a' ≪ b') = (a' < b')
If sign(a) ≠ sign(b), we have (a ≪ b) = (b' ≪ a') = (a' < b')
Therefore, (a ≪ b) = (a' < b').

Convert long string to integer without parseLong or parseInt

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

Categories

Resources