One liner to check two decimal strings differ only by 1 ulp - java

I have two decimal numbers in String form that are rounded slightly differently. I want a function that would treat them as "equal" if they only differ by 1 ulp (i.e. only the last digit differs by 1).
Currently the most readable form I can come up with is like:
private static boolean diffByUlp(String oldVal, String newVal) {
BigDecimal nb = new BigDecimal(newVal);
return nb.subtract(new BigDecimal(oldVal)).abs().equals(nb.ulp());
}
However, I'd really like a way to do this in one expression (so it fits in an if statement) and avoid using the expensive BigDecimals.
(BTW: they differ by more than 1 double (binary) ulp.)
Any suggestions?

I assume you are looking for a performance effective solution since you've already mentioned that using BigDecimal is too expensive in your case. Although giving advice on performance without knowing the whole context is quite tricky. You may consider a solution based on comparing characters from both decimal numbers stored as a String. It may give you a quick boost if numbers you compare are usually different starting from very first digits (e.g. comparing 120.0001 with 512.0 can be easily tracked just by comparing first character in both strings). But if for most cases your numbers are pretty close then you might stick to BigDecimal - it's all about measuring the performance with real data.
Below you can find an exemplary solution based on comparing characters from strings. It handles a case where two decimal numbers uses different precision. Also when comparing "1.00" with "1.00001" the first number is "treated" as "1.00000". You can use this class as a utility class that provides you a single static method that you can use in any if statement.
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
final class StringDecimal {
private static final Map<Integer, Integer> charToInt = new ConcurrentHashMap<>();
static {
charToInt.put(48, 0);
charToInt.put(49, 1);
charToInt.put(50, 2);
charToInt.put(51, 3);
charToInt.put(52, 4);
charToInt.put(53, 5);
charToInt.put(54, 6);
charToInt.put(55, 7);
charToInt.put(56, 8);
charToInt.put(57, 9);
}
private static boolean areEqual(String num1, String num2) {
int size = Math.min(num1.length(), num2.length()) - 1;
// 1. Compare first n-1 characters where n is max common length for both strings
for (int i = 0; i < size; i++) {
if (num1.charAt(i) != num2.charAt(i)) {
return false;
}
}
int lastDigitDiff = Math.max(num1.charAt(size), num2.charAt(size)) - Math.min(num1.charAt(size), num2.charAt(size));
// 2. Check last common digit
if (lastDigitDiff > 1) {
return false;
}
// 3. If both decimal numbers have same size, they are equal at this moment
if (num1.length() == num2.length()) {
return true;
}
if (num1.length() > num2.length()) {
return testRemainingDigits(num1, size);
}
return testRemainingDigits(num2, size);
}
private static boolean testRemainingDigits(String num, int size) {
int lastDigitsSum = 0;
int lastDigit = charToInt.getOrDefault((int) num.charAt(num.length() - 1), 0);
// 1. Check if last digit is equal to 1
if (lastDigit > 1) {
return false;
}
// 2. Sum all remaining digits from longer string and accept sum == 1
for (int i = num.length() - 1; i > size; i--) {
lastDigitsSum += charToInt.getOrDefault((int) num.charAt(i), 0);
}
return lastDigit == 0 && lastDigitsSum == 0 ||
lastDigit == 1 && lastDigitsSum == 1;
}
public static void main(String[] args) {
List<List<Object>> numbers = Arrays.asList(
Arrays.asList("1.00", "1.000000", true),
Arrays.asList("120.0", "121.0", false),
Arrays.asList("120.0", "120.1", true),
Arrays.asList("1024.00001", "1024.00000", true),
Arrays.asList("1024.00002", "1024.00000", false),
Arrays.asList("1024.00001", "1024.0000", true),
Arrays.asList("1024.00001", "1024", true),
Arrays.asList("1024.00010", "1024", false),
Arrays.asList("1024.00002", "1024", false),
Arrays.asList("1024.00001", "1025.00001", false)
);
for (List<Object> data : numbers) {
String num1 = (String) data.get(0);
String num2 = (String) data.get(1);
boolean expected = (boolean) data.get(2);
boolean result = areEqual(num1, num2);
String status = expected == result ? "OK" : "FAILED";
System.out.println("["+status+"] " + num1 + " == " + num2 + " ? " + result);
}
}
}
It's very imperative, but it's still quite easy to understand what happens under the hood. Complexity of this algorithm is O(n).
Running this exemplary program produces following output:
[OK] 1.00 == 1.000000 ? true
[OK] 120.0 == 121.0 ? false
[OK] 120.0 == 120.1 ? true
[OK] 1024.00001 == 1024.00000 ? true
[OK] 1024.00002 == 1024.00000 ? false
[OK] 1024.00001 == 1024.0000 ? true
[OK] 1024.00001 == 1024 ? true
[OK] 1024.00010 == 1024 ? false
[OK] 1024.00002 == 1024 ? false
[OK] 1024.00001 == 1025.00001 ? false
I hope it will help you coming up with the best solution to your problem.

You have high expectations in a very "floating" area.
Still one, not so serious, answer:
static boolean probablySame(String x, String y) {
return Math.abs(x.hashCode() - y.hashCode()) <= 1;
}

So you want to compactly check if two decimal values only differ by at most 1. For example 3.2 and 2.4 (difference is 0.8).
First you should note that the only purpose of BigDecimal is to provide infinite space and precision in contrast to the limited datatype double (same holds for BigInteger and int). However you only use it to parse a decimal value from a String. Using that class only for that purpose is quite a big overhead, as you already mentioned. Parsing values can also be done with the Double#parseDouble method (documentation), it returns a compact small double value.
All in all your code could look like this:
private static boolean differAtMostByOne(final String oldVal, final String newVal) {
final double oldValAsDouble = Double.parseDouble(oldVal);
final double newValAsDouble = Double.parseDouble(newVal),
final double difference = Math.abs(oldValAsDouble - newValAsDouble);
final double compareTo = 1.0;
final double precision = 0.000001;
final boolean differByAtMostOne = difference <= compareTo + precision;
return differByAtMostOne;
}
Or the same compact:
private static boolean differAtMostByOne(final String oldVal, final String newVal) {
return Math.abs(Double.parseDouble(oldVal) - Double.parseDouble(newVal)) < 1.000001;
}
Note that a direct comparison with the value 1.0 should be avoided when comparing with decimal values. Instead you should allow a small region around the value to account for precision loss.
Else it could be that you input values whose difference is exactly 1 but the computer may represent it by a value like 1.000000000000000001 and the program should also accept it thus the precision region.

Assuming you need this only for Strings with the same lenght. Following might be a possible solution.
check that the strings are equal, except the last digit
check that the last digit is not more of then by one
The snippet should only demonstrate the principal. Further optimization possible.
static boolean diffByUlp(String s1, String s2) {
for (int i = 0; i < s1.length() - 1; i++) {
if (s1.charAt(i) != s2.charAt(i)) {
return false;
}
}
char c1 = s1.charAt(s1.length() - 1);
char c2 = s2.charAt(s2.length() - 1);
if (c1 >= c2) {
return c1-c2 <= 1;
}
return c2-c1 <= 1;
}

Related

How to calculate the number of zeros in binary?

Hi I am making a method that can take an integer as a parameter and compute how many zeros its binary form has. So for example, if I have binaryZeros(44), its binary form is 101100. Therefore, binaryZeros(44) should return 3. However, I am making some errors and I cannot tell where it is coming from. I would appreciate it if someone can point out where I am making that error, or if my approach (logic) to this problem is good enough. Thank you!
My code is Below:
public static int binaryZeros(int n) {
int zeroCount = 0;
double m = n;
while (m >= 0.0) {
m = m / 2.0;
if (m == Math.floor(m)) {
zeroCount++;
} else {
m = Math.floor(m);
}
}
return zeroCount;
}
Below is a more concise way to solve this problem
public static int binaryZeros(int n) {
int zeroCount = 0;
// Run a while loop until n is greater than or equals to 1
while(n >= 1)
{
/* Use modulo operator to get the reminder of division by 2 (reminder will be 1 or 0 as you are dividing by 2).
Keep in mind that binary representation is an array of these reminders until the number is equal to 1.
And once the number is equal to 1 the reminder is 1, so you can exit the loop there.*/
if(n % 2 == 0)
{
zeroCount++;
}
n = n / 2;
}
return zeroCount;
}
Your approach is good, but I think there's a better way to do it. The Integer class has a static method that returns the binary of a number: Integer.toBinaryString(num) . This will return a String.
Then, you can just check if there are any 0 in that string with method that has a for loop and evaluating with an if:
public int getZeros(String binaryString){
int zeros = 0;
for(int i=0; i < binaryString.length; i++)
if(binaryString.charAt[i].equals('0')
zeros++;
return zeros;
}
I believe this would be a simpler option and it doesn't have any errors.
Once m == 0.0, it will never change, so your while loop will never stop.
If you start with a number m >= 0, it can never become negative no matter how many times you divide it by 2 or use Math.floor. The loop should stop when m reaches 0, so change the condition to while (m > 0.0).
Note that you could do the same thing with built-in standard library methods. For example, there is a method that returns the number of leading zeros in a number, and a method that returns the number of bits set to 1. Using both you can compute the number of zeros that are not leading zeros:
static int binaryZeros(int n) {
return Integer.SIZE - Integer.numberOfLeadingZeros(n) - Integer.bitCount(n);
}
Here is one way. It simply complements the integer reversing 1's and 0's and then counts the 1 bits. You should not be using floating point math when doing this.
~ complements the bits
&1 masks the low order bit. Is either 1 or 0
>>> shifts right 1 bit including sign bit.
System.out.println(binaryZeros(44) + " (" +Integer.toBinaryString(44) +")");
System.out.println(binaryZeros(-44) + " ("Integer.toBinaryString(-44)+")");
public static int binaryZeros(int v) {
int count = 0;
while (v != 0) {
// count 1 bits
// of ~v
count += (~v)&1;
v >>>=1;
}
return count;
}
Prints
3 (101100)
4 (11111111111111111111111111010100)
Just be simple, whe there's Integer.bitCount(n) method:
public static int binaryZeros(int n) {
long val = n & 0xFFFFFFFFL;
int totalBits = (int)(Math.log(val) / Math.log(2) + 1);
int setBits = Long.bitCount(val);
return totalBits - setBits;
}
public static int getZeros(int num) {
String str= Integer.toBinaryString(num);
int count=0;
for(int i=0; i<str.length(); i++) {
if(str.charAt(i)=='0') count++;
}
return count;
}
The method toBinaryString() returns a string representation of the integer argument as an unsigned integer in base 2. It accepts an argument in Int data-type and returns the corresponding binary string.
Then the for loop counts the number of zeros in the String and returns it.

How to use comparison operators like >, =, < on BigDecimal

I have a domain class with unitPrice set as BigDecimal data type. Now I am trying to create a method to compare price but it seems like I can't have comparison operators in BigDecimal data type. Do I have to change data type or is there other way around?
To be short:
firstBigDecimal.compareTo(secondBigDecimal) < 0 // "<"
firstBigDecimal.compareTo(secondBigDecimal) > 0 // ">"
firstBigDecimal.compareTo(secondBigDecimal) == 0 // "=="
firstBigDecimal.compareTo(secondBigDecimal) >= 0 // ">="
Every object of the Class BigDecimal has a method compareTo you can use to compare it to another BigDecimal. The result of compareTo is then compared > 0, == 0 or < 0 depending on what you need. Read the documentation and you will find out.
The operators ==, <, > and so on can only be used on primitive data types like int, long, double or their wrapper classes like Integerand Double.
From the documentation of compareTo:
Compares this BigDecimal with the specified BigDecimal.
Two BigDecimal
objects that are equal in value but have a different scale (like 2.0
and 2.00) are considered equal by this method. This method is provided
in preference to individual methods for each of the six boolean
comparison operators (<, ==, >, >=, !=, <=). The suggested idiom for
performing these comparisons is: (x.compareTo(y) <op> 0), where <op>
is one of the six comparison operators.
Returns:
-1, 0, or 1 as this BigDecimal is numerically less than, equal to, or greater than val.
Use the compareTo method of BigDecimal :
public int compareTo(BigDecimal val) Compares this BigDecimal with the
specified BigDecimal.
Returns:
-1, 0, or 1 as this BigDecimal is numerically less than, equal to, or greater than val.
Here is an example for all six boolean comparison operators (<, ==, >, >=, !=, <=):
BigDecimal big10 = new BigDecimal(10);
BigDecimal big20 = new BigDecimal(20);
System.out.println(big10.compareTo(big20) < -1); // false
System.out.println(big10.compareTo(big20) <= -1); // true
System.out.println(big10.compareTo(big20) == -1); // true
System.out.println(big10.compareTo(big20) >= -1); // true
System.out.println(big10.compareTo(big20) > -1); // false
System.out.println(big10.compareTo(big20) != -1); // false
System.out.println(big10.compareTo(big20) < 0); // true
System.out.println(big10.compareTo(big20) <= 0); // true
System.out.println(big10.compareTo(big20) == 0); // false
System.out.println(big10.compareTo(big20) >= 0); // false
System.out.println(big10.compareTo(big20) > 0); // false
System.out.println(big10.compareTo(big20) != 0); // true
System.out.println(big10.compareTo(big20) < 1); // true
System.out.println(big10.compareTo(big20) <= 1); // true
System.out.println(big10.compareTo(big20) == 1); // false
System.out.println(big10.compareTo(big20) >= 1); // false
System.out.println(big10.compareTo(big20) > 1); // false
System.out.println(big10.compareTo(big20) != 1); // true
You can use method named compareTo, x.compareTo(y). It will return 0 if x and y are equal, 1 if x is greater than y and -1 if x is smaller than y
Discussion
This thread has plenty of answers stating that the BigDecimal.compareTo(BigDecimal) method is the one to use to compare BigDecimal instances. I just wanted to add for anyone not experienced with using the BigDecimal.compareTo(BigDecimal) method: Be careful with how you create your BigDecimal instances. For example:
new BigDecimal(0.8) will create a BigDecimal instance with a value which is not exactly 0.8 and which has a scale of 50+,
new BigDecimal("0.8") will create a BigDecimal instance with a value which is exactly 0.8 and which has a scale of 1.
These two BigDecimal instances are unequal according to the BigDecimal.compareTo(BigDecimal) method because their values are unequal when the scale is not limited to a few decimal places.
Summary
Firstly, be careful to create your BigDecimal instances with the BigDecimal(String val) constructor or the BigDecimal.valueOf(double val) method rather than the BigDecimal(double val) constructor. Secondly, note that you can limit the scale of BigDecimal instances prior to comparing them by means of the BigDecimal.setScale(int newScale, RoundingMode roundingMode) method.
BigDecimal isn't a primitive, so you cannot use the <, > operators. However, since it's a Comparable, you can use the compareTo(BigDecimal) to the same effect. E.g.:
public class Domain {
private BigDecimal unitPrice;
public boolean isCheaperThan(BigDecimal other) {
return unitPirce.compareTo(other.unitPrice) < 0;
}
// etc...
}
Alternatively, if you're already using commons-lang3 (version 3.10 and up), you can leverage their ComparableUtils API like so:
import static org.apache.commons.lang3.compare.ComparableUtils.is;
var areEqual = is(first).equalTo(second);
var isGreater = is(first).greaterThan(second);
var isLess = is(first).lessThan(second);
var isBetween = is(first).between(second, third);
// etc.
Nowadays, most large projects include commons-lang3 as a dependency, anyway.
You can follow this utility static method and Operator enum for comparing the two numbers:
public static boolean check(BigDecimal firstNum, Operator operator, BigDecimal secondNum) {
switch (operator) {
case EQUALS:
return firstNum.compareTo(secondNum) == 0;
case LESS_THAN:
return firstNum.compareTo(secondNum) < 0;
case LESS_THAN_OR_EQUALS:
return firstNum.compareTo(secondNum) <= 0;
case GREATER_THAN:
return firstNum.compareTo(secondNum) > 0;
case GREATER_THAN_OR_EQUALS:
return firstNum.compareTo(secondNum) >= 0;
}
throw new IllegalArgumentException("Will never reach here");
}
public enum Operator {
LESS_THAN, LESS_THAN_OR_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUALS, EQUALS
}
Using com.ibm.etools.marshall.util.BigDecimalRange util class of IBM one can compare if BigDecimal in range.
boolean isCalculatedSumInRange = BigDecimalRange.isInRange(low, high, calculatedSum);
Below is an example to compare two BigDecimal values.
public class BigDecimalDemo {
public static void main(String[] args) {
// create 2 BigDecimal objects
BigDecimal bg1, bg2;
bg1 = new BigDecimal("10");
bg2 = new BigDecimal("20");
//create int object
int res;
res = bg1.compareTo(bg2); // compare bg1 with bg2
String str1 = "Both values are equal ";
String str2 = "First Value is greater ";
String str3 = "Second value is greater";
if( res == 0 )
System.out.println( str1 );
else if( res == 1 )
System.out.println( str2 );
else if( res == -1 )
System.out.println( str3 );
}
}

How can I tell that an integer is only 2 digits long?

I need to write a Java program that prompts the user to enter an integer consisting of exactly 2 digits; then displays on the screen the sum of its individual digits.
I am stuck here. What am I doing wrong?
import java.util.Scanner ;
public class ss {
public static void main(String[] args)
{
Scanner input = new Scanner(System.in);
int x;
System.out.println("Please Enter a number consists of 2 digits only : ");
x = input.nextInt();
x.length() == 2;
}
}
and the last line contains an error!
Assuming that x is positive, a simple way to check if it has exactly two digits would be:
if (x >= 10 && x <= 99) {
// x contains exactly two digits
}
The variable x is of type int, so you can't call a method on it. You need to either read the input as a String or convert the int to a String then call length(), or just test that the int is between 10 and 99, inclusive.
In a programming langauge, there are things called L-values and R-values. In an assignment operation, a L-value can accept a R-value as input. This comes from the typical layout which has L-values on the left of the assignment operator and R-values on the right side of the assignment operator.
x = 5;
x is the L-value and 5 is the R-value. It is possible to assign five to x.
However, a function returns a R-value. Therefore, it is possible to do this
x = a.length();
but is is not possible to do
a.length() = x;
because you can not assign a value to the return of a function.
Fundamentally, L-values are names which represent a value, but R-values are values or items which when analyzed result in the return of values.
Now, if you used the equals comparison operator, both values must be R-values, because no assignment is being performed
a.length == x
is just fine, because it is not the assignment operator = but rather one of the comparison operators ==.
Your error comes because x is a primitive, not an object. Only objects have methods like length(). A quick an easy way to determine the length of an integer is by using Math.log().
public int length(int n){
if (n == 0) return 1; // because Math.log(0) is undefined
if (n < 0) n = -n; // because Math.log() doesn't work for negative numbers
return (int)(Math.log10(n)) + 1; //+1 because Math.log10 returns one less
//than wanted. Math.log10(10) == 1.
}
This method uses the fact that the base b logarithm of an integer a is related to the length of the integer a.
Or, if you don't know how to use methods, you could do this (assuming n is the integer to check):
int length = (n == 0)? 1: ((n > 0)? (int) (Math.log(n)) + 1: (int) (Math.log(-n)) + 1);
Or, if you don't use the ternary operator, you could expand it:
int length = -1; //placeholder; might not need it.
if (n == 0) length = 1;
else if (n > 0) length = (int) (Math.log(n)) + 1;
else length = (int) (Math.log(-n)) + 1;
You can't find the length of an int by calling a method on it, but you can find the length of a String.
Try converting the int to a String and finding the length of that:
boolean isTwoDigits = x.toString().length() == 2;
You cannot call length on integer just write
if(x>=10 && x<=99)
{
//write your code here
}

How to test if a double is an integer

Is it possible to do this?
double variable;
variable = 5;
/* the below should return true, since 5 is an int.
if variable were to equal 5.7, then it would return false. */
if(variable == int) {
//do stuff
}
I know the code probably doesn't go anything like that, but how does it go?
Or you could use the modulo operator:
(d % 1) == 0
if ((variable == Math.floor(variable)) && !Double.isInfinite(variable)) {
// integer type
}
This checks if the rounded-down value of the double is the same as the double.
Your variable could have an int or double value and Math.floor(variable) always has an int value, so if your variable is equal to Math.floor(variable) then it must have an int value.
This also doesn't work if the value of the variable is infinite or negative infinite hence adding 'as long as the variable isn't inifinite' to the condition.
Guava: DoubleMath.isMathematicalInteger. (Disclosure: I wrote it.) Or, if you aren't already importing Guava, x == Math.rint(x) is the fastest way to do it; rint is measurably faster than floor or ceil.
public static boolean isInt(double d)
{
return d == (int) d;
}
Try this way,
public static boolean isInteger(double number){
return Math.ceil(number) == Math.floor(number);
}
for example:
Math.ceil(12.9) = 13; Math.floor(12.9) = 12;
hence 12.9 is not integer, nevertheless
Math.ceil(12.0) = 12; Math.floor(12.0) =12;
hence 12.0 is integer
Here is a good solution:
if (variable == (int)variable) {
//logic
}
Consider:
Double.isFinite (value) && Double.compare (value, StrictMath.rint (value)) == 0
This sticks to core Java and avoids an equality comparison between floating point values (==) which is consdered bad. The isFinite() is necessary as rint() will pass-through infinity values.
Here's a version for Integer and Double:
private static boolean isInteger(Double variable) {
if ( variable.equals(Math.floor(variable)) &&
!Double.isInfinite(variable) &&
!Double.isNaN(variable) &&
variable <= Integer.MAX_VALUE &&
variable >= Integer.MIN_VALUE) {
return true;
} else {
return false;
}
}
To convert Double to Integer:
Integer intVariable = variable.intValue();
Similar to SkonJeet's answer above, but the performance is better (at least in java):
Double zero = 0d;
zero.longValue() == zero.doubleValue()
My simple solution:
private boolean checkIfInt(double value){
return value - Math.floor(value) == 0;
}
public static boolean isInteger(double d) {
// Note that Double.NaN is not equal to anything, even itself.
return (d == Math.floor(d)) && !Double.isInfinite(d);
}
A simple way for doing this could be
double d = 7.88; //sample example
int x=floor(d); //floor of number
int y=ceil(d); //ceil of number
if(x==y) //both floor and ceil will be same for integer number
cout<<"integer number";
else
cout<<"double number";
My solution would be
double variable=the number;
if(variable-(int)variable=0.0){
// do stuff
}
you could try in this way: get the integer value of the double, subtract this from the original double value, define a rounding range and tests if the absolute number of the new double value(without the integer part) is larger or smaller than your defined range. if it is smaller you can intend it it is an integer value. Example:
public final double testRange = 0.2;
public static boolean doubleIsInteger(double d){
int i = (int)d;
double abs = Math.abs(d-i);
return abs <= testRange;
}
If you assign to d the value 33.15 the method return true. To have better results you can assign lower values to testRange (as 0.0002) at your discretion.
Personally, I prefer the simple modulo operation solution in the accepted answer.
Unfortunately, SonarQube doesn't like equality tests with floating points without setting a round precision. So we have tried to find a more compliant solution. Here it is:
if (new BigDecimal(decimalValue).remainder(new BigDecimal(1)).equals(BigDecimal.ZERO)) {
// no decimal places
} else {
// decimal places
}
Remainder(BigDecimal) returns a BigDecimal whose value is (this % divisor). If this one's equal to zero, we know there is no floating point.
Because of % operator cannot apply to BigDecimal and int (i.e. 1) directly, so I am using the following snippet to check if the BigDecimal is an integer:
value.stripTrailingZeros().scale() <= 0
Similar (and probably inferior) to Eric Tan's answer (which checks scale):
double d = 4096.00000;
BigDecimal bd = BigDecimal.valueOf(d);
String s = bd.stripTrailingZeros().toPlainString();
boolean isInteger = s.indexOf(".")==-1;
Here's a solution:
float var = Your_Value;
if ((var - Math.floor(var)) == 0.0f)
{
// var is an integer, so do stuff
}

How to determine if a number is positive or negative?

I was asked in an interview, how to determine whether a number is positive or negative. The rules are that we should not use relational operators such as <, and >, built in java functions (like substring, indexOf, charAt, and startsWith), no regex, or API's.
I did some homework on this and the code is given below, but it only works for integer type. But they asked me to write a generic code that works for float, double, and long.
// This might not be better way!!
S.O.P ((( number >> 31 ) & 1) == 1 ? "- ve number " : "+ve number );
any ideas from your side?
The integer cases are easy. The double case is trickier, until you remember about infinities.
Note: If you consider the double constants "part of the api", you can replace them with overflowing expressions like 1E308 * 2.
int sign(int i) {
if (i == 0) return 0;
if (i >> 31 != 0) return -1;
return +1;
}
int sign(long i) {
if (i == 0) return 0;
if (i >> 63 != 0) return -1;
return +1;
}
int sign(double f) {
if (f != f) throw new IllegalArgumentException("NaN");
if (f == 0) return 0;
f *= Double.POSITIVE_INFINITY;
if (f == Double.POSITIVE_INFINITY) return +1;
if (f == Double.NEGATIVE_INFINITY) return -1;
//this should never be reached, but I've been wrong before...
throw new IllegalArgumentException("Unfathomed double");
}
The following is a terrible approach that would get you fired at any job...
It depends on you getting a Stack Overflow Exception [or whatever Java calls it]... And it would only work for positive numbers that don't deviate from 0 like crazy.
Negative numbers are fine, since you would overflow to positive, and then get a stack overflow exception eventually [which would return false, or "yes, it is negative"]
Boolean isPositive<T>(T a)
{
if(a == 0) return true;
else
{
try
{
return isPositive(a-1);
}catch(StackOverflowException e)
{
return false; //It went way down there and eventually went kaboom
}
}
}
This will only works for everything except [0..2]
boolean isPositive = (n % (n - 1)) * n == n;
You can make a better solution like this (works except for [0..1])
boolean isPositive = ((n % (n - 0.5)) * n) / 0.5 == n;
You can get better precision by changing the 0.5 part with something like 2^m (m integer):
boolean isPositive = ((n % (n - 0.03125)) * n) / 0.03125 == n;
You can do something like this:
((long) (num * 1E308 * 1E308) >> 63) == 0 ? "+ve" : "-ve"
The main idea here is that we cast to a long and check the value of the most significant bit. As a double/float between -1 and 0 will round to zero when cast to a long, we multiply by large doubles so that a negative float/double will be less than -1. Two multiplications are required because of the existence of subnormals (it doesn't really need to be that big though).
What about this?
return ((num + "").charAt(0) == '-');
// Returns 0 if positive, nonzero if negative
public long sign(long value) {
return value & 0x8000000000000000L;
}
Call like:
long val1 = ...;
double val2 = ...;
float val3 = ...;
int val4 = ...;
sign((long) valN);
Casting from double / float / integer to long should preserve the sign, if not the actual value...
You say
we should not use conditional operators
But this is a trick requirement, because == is also a conditional operator. There is also one built into ? :, while, and for loops. So nearly everyone has failed to provide an answer meeting all the requirements.
The only way to build a solution without a conditional operator is to use lookup table vs one of a few other people's solutions that can be boiled down to 0/1 or a character, before a conditional is met.
Here are the answers that I think might work vs a lookup table:
Nabb
Steven Schlansker
Dennis Cheung
Gary Rowe
This solution uses modulus. And yes, it also works for 0.5 (tests are below, in the main method).
public class Num {
public static int sign(long x) {
if (x == 0L || x == 1L) return (int) x;
return x == Long.MIN_VALUE || x % (x - 1L) == x ? -1 : 1;
}
public static int sign(double x) {
if (x != x) throw new IllegalArgumentException("NaN");
if (x == 0.d || x == 1.d) return (int) x;
if (x == Double.POSITIVE_INFINITY) return 1;
if (x == Double.NEGATIVE_INFINITY) return -1;
return x % (x - 1.d) == x ? -1 : 1;
}
public static int sign(int x) {
return Num.sign((long)x);
}
public static int sign(float x) {
return Num.sign((double)x);
}
public static void main(String args[]) {
System.out.println(Num.sign(Integer.MAX_VALUE)); // 1
System.out.println(Num.sign(1)); // 1
System.out.println(Num.sign(0)); // 0
System.out.println(Num.sign(-1)); // -1
System.out.println(Num.sign(Integer.MIN_VALUE)); // -1
System.out.println(Num.sign(Long.MAX_VALUE)); // 1
System.out.println(Num.sign(1L)); // 1
System.out.println(Num.sign(0L)); // 0
System.out.println(Num.sign(-1L)); // -1
System.out.println(Num.sign(Long.MIN_VALUE)); // -1
System.out.println(Num.sign(Double.POSITIVE_INFINITY)); // 1
System.out.println(Num.sign(Double.MAX_VALUE)); // 1
System.out.println(Num.sign(0.5d)); // 1
System.out.println(Num.sign(0.d)); // 0
System.out.println(Num.sign(-0.5d)); // -1
System.out.println(Num.sign(Double.MIN_VALUE)); // -1
System.out.println(Num.sign(Double.NEGATIVE_INFINITY)); // -1
System.out.println(Num.sign(Float.POSITIVE_INFINITY)); // 1
System.out.println(Num.sign(Float.MAX_VALUE)); // 1
System.out.println(Num.sign(0.5f)); // 1
System.out.println(Num.sign(0.f)); // 0
System.out.println(Num.sign(-0.5f)); // -1
System.out.println(Num.sign(Float.MIN_VALUE)); // -1
System.out.println(Num.sign(Float.NEGATIVE_INFINITY)); // -1
System.out.println(Num.sign(Float.NaN)); // Throws an exception
}
}
This code covers all cases and types:
public static boolean isNegative(Number number) {
return (Double.doubleToLongBits(number.doubleValue()) & Long.MIN_VALUE) == Long.MIN_VALUE;
}
This method accepts any of the wrapper classes (Integer, Long, Float and Double) and thanks to auto-boxing any of the primitive numeric types (int, long, float and double) and simply checks it the high bit, which in all types is the sign bit, is set.
It returns true when passed any of:
any negative int/Integer
any negative long/Long
any negative float/Float
any negative double/Double
Double.NEGATIVE_INFINITY
Float.NEGATIVE_INFINITY
and false otherwise.
Untested, but illustrating my idea:
boolean IsNegative<T>(T v) {
return (v & ((T)-1));
}
It seems arbitrary to me because I don't know how you would get the number as any type, but what about checking Abs(number) != number? Maybe && number != 0
Integers are trivial; this you already know. The deep problem is how to deal with floating-point values. At that point, you've got to know a bit more about how floating point values actually work.
The key is Double.doubleToLongBits(), which lets you get at the IEEE representation of the number. (The method's really a direct cast under the hood, with a bit of magic for dealing with NaN values.) Once a double has been converted to a long, you can just use 0x8000000000000000L as a mask to select the sign bit; if zero, the value is positive, and if one, it's negative.
If it is a valid answer
boolean IsNegative(char[] v) throws NullPointerException, ArrayIndexOutOfBoundException
{
return v[0]=='-';
}
one more option I could think of
private static boolean isPositive(Object numberObject) {
Long number = Long.valueOf(numberObject.toString());
return Math.sqrt((number * number)) != number;
}
private static boolean isPositive(Object numberObject) {
Long number = Long.valueOf(numberObject.toString());
long signedLeftShifteredNumber = number << 1; // Signed left shift
long unsignedRightShifterNumber = signedLeftShifteredNumber >>> 1; // Unsigned right shift
return unsignedRightShifterNumber == number;
}
This one is roughly based on ItzWarty's answer, but it runs in logn time! Caveat: Only works for integers.
Boolean isPositive(int a)
{
if(a == -1) return false;
if(a == 0) return false;
if(a == 1) return true;
return isPositive(a/2);
}
I think there is a very simple solution:
public boolean isPositive(int|float|double|long i){
return (((i-i)==0)? true : false);
}
tell me if I'm wrong!
Try this without the code: (x-SQRT(x^2))/(2*x)
Write it using the conditional then take a look at the assembly code generated.
Why not get the square root of the number? If its negative - java will throw an error and we will handle it.
try {
d = Math.sqrt(THE_NUMBER);
}
catch ( ArithmeticException e ) {
console.putln("Number is negative.");
}
I don't know how exactly Java coerces numeric values, but the answer is pretty simple, if put in pseudocode (I leave the details to you):
sign(x) := (x == 0) ? 0 : (x/x)
If you are allowed to use "==" as seems to be the case, you can do something like that taking advantage of the fact that an exception will be raised if an array index is out of bounds. The code is for double, but you can cast any numeric type to a double (here the eventual loss of precision would not be important at all).
I have added comments to explain the process (bring the value in ]-2.0; -1.0] union [1.0; 2.0[) and a small test driver as well.
class T {
public static boolean positive(double f)
{
final boolean pos0[] = {true};
final boolean posn[] = {false, true};
if (f == 0.0)
return true;
while (true) {
// If f is in ]-1.0; 1.0[, multiply it by 2 and restart.
try {
if (pos0[(int) f]) {
f *= 2.0;
continue;
}
} catch (Exception e) {
}
// If f is in ]-2.0; -1.0] U [1.0; 2.0[, return the proper answer.
try {
return posn[(int) ((f+1.5)/2)];
} catch (Exception e) {
}
// f is outside ]-2.0; 2.0[, divide by 2 and restart.
f /= 2.0;
}
}
static void check(double f)
{
System.out.println(f + " -> " + positive(f));
}
public static void main(String args[])
{
for (double i = -10.0; i <= 10.0; i++)
check(i);
check(-1e24);
check(-1e-24);
check(1e-24);
check(1e24);
}
The output is:
-10.0 -> false
-9.0 -> false
-8.0 -> false
-7.0 -> false
-6.0 -> false
-5.0 -> false
-4.0 -> false
-3.0 -> false
-2.0 -> false
-1.0 -> false
0.0 -> true
1.0 -> true
2.0 -> true
3.0 -> true
4.0 -> true
5.0 -> true
6.0 -> true
7.0 -> true
8.0 -> true
9.0 -> true
10.0 -> true
-1.0E24 -> false
-1.0E-24 -> false
1.0E-24 -> true
1.0E24 -> true
Well, taking advantage of casting (since we don't care what the actual value is) perhaps the following would work. Bear in mind that the actual implementations do not violate the API rules. I've edited this to make the method names a bit more obvious and in light of #chris' comment about the {-1,+1} problem domain. Essentially, this problem does not appear to solvable without recourse to API methods within Float or Double that reference the native bit structure of the float and double primitives.
As everybody else has said: Stupid interview question. Grr.
public class SignDemo {
public static boolean isNegative(byte x) {
return (( x >> 7 ) & 1) == 1;
}
public static boolean isNegative(short x) {
return (( x >> 15 ) & 1) == 1;
}
public static boolean isNegative(int x) {
return (( x >> 31 ) & 1) == 1;
}
public static boolean isNegative(long x) {
return (( x >> 63 ) & 1) == 1;
}
public static boolean isNegative(float x) {
return isNegative((int)x);
}
public static boolean isNegative(double x) {
return isNegative((long)x);
}
public static void main(String[] args) {
// byte
System.out.printf("Byte %b%n",isNegative((byte)1));
System.out.printf("Byte %b%n",isNegative((byte)-1));
// short
System.out.printf("Short %b%n",isNegative((short)1));
System.out.printf("Short %b%n",isNegative((short)-1));
// int
System.out.printf("Int %b%n",isNegative(1));
System.out.printf("Int %b%n",isNegative(-1));
// long
System.out.printf("Long %b%n",isNegative(1L));
System.out.printf("Long %b%n",isNegative(-1L));
// float
System.out.printf("Float %b%n",isNegative(Float.MAX_VALUE));
System.out.printf("Float %b%n",isNegative(Float.NEGATIVE_INFINITY));
// double
System.out.printf("Double %b%n",isNegative(Double.MAX_VALUE));
System.out.printf("Double %b%n",isNegative(Double.NEGATIVE_INFINITY));
// interesting cases
// This will fail because we can't get to the float bits without an API and
// casting will round to zero
System.out.printf("{-1,1} (fail) %b%n",isNegative(-0.5f));
}
}
This solution uses no conditional operators, but relies on catching two excpetions.
A division error equates to the number originally being "negative". Alternatively, the number will eventually fall off the planet and throw a StackOverFlow exception if it is positive.
public static boolean isPositive( f)
{
int x;
try {
x = 1/((int)f + 1);
return isPositive(x+1);
} catch (StackOverFlow Error e) {
return true;
} catch (Zero Division Error e) {
return false;
}
}
What about the following?
T sign(T x) {
if(x==0) return 0;
return x/Math.abs(x);
}
Should work for every type T...
Alternatively, one can define abs(x) as Math.sqrt(x*x),
and if that is also cheating, implement your own square root function...
if (((Double)calcYourDouble()).toString().contains("-"))
doThis();
else doThat();
Combined generics with double API. Guess it's a bit of cheating, but at least we need to write only one method:
static <T extends Number> boolean isNegative(T number)
{
return ((number.doubleValue() * Double.POSITIVE_INFINITY) == Double.NEGATIVE_INFINITY);
}
Two simple solutions. Works also for infinities and numbers -1 <= r <= 1
Will return "positive" for NaNs.
String positiveOrNegative(double number){
return (((int)(number/0.0))>>31 == 0)? "positive" : "negative";
}
String positiveOrNegative(double number){
return (number==0 || ((int)(number-1.0))>>31==0)? "positive" : "negative";
}
There is a function is the math library called signnum.
http://www.tutorialspoint.com/java/lang/math_signum_float.htm
http://www.tutorialspoint.com/java/lang/math_signum_double.htm
It's easy to do this like
private static boolean isNeg(T l) {
return (Math.abs(l-1)>Math.abs(l));
}
static boolean isNegative(double v) {
return new Double(v).toString().startsWith("-");
}

Categories

Resources