package Current.search.basic;
import java.util.TreeMap;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.lang.Object;
import java.lang.Integer;
/** This class decides definitively whether a polynomial in
* some double values is positive or negative. "Definitively" means
* without the possibility of computer error.
*
*
* This may be useful, for example, in the field of computational geometry.
* For my particular application, I need to know whether or not a triangle
* with double coordinates has a positive or negative signed area.
*
*
* This is essentially an extremely unplesant problem. Let me give some examples:
*
*
* Suppose x is about 10^100 and y is about -10^100 and z is about 10^-100. So x and y are
* huge and similar in magnitude, but z is miniscule. Decide the sign of x+y+z.
*
*
* Now suppose x=a*b and y=c*d. Then because of round off error, when java runs it computes
* y=-x. But, it is extremely unlikely that c*d=-a*b. The obvious computation of
* (x+y)+z will equal z. But the sign of (a*b+c*d)+z is much more likely to depend on
* a*b and c*d. This class solves these annoying problems.
*
*
* This class implements some trivial case of arbitrary precision arithmetic. But,
* you would not want to do this by simply storing a huge list of consequtive digits.
* This is because 2^1000 + 2^(-1000) would require storing 2000 binary digits.
*/
public class SignDecider {
// Java can be extremely irritating some times.
// You can't get a reverse_iterator, so instead we order the integers from
// greatest to smallest.
private static class IntegerComparator implements Comparator {
public IntegerComparator(){}
public int compare(Object o1,
Object o2) {
return ((Integer)o2).compareTo((Integer)o1);
}
}
/**
* If v is non-zero return an integer exp, so that (0.5 <= |v|*2^(-exp) < 1).
* this is analogous to the integer part of the return value of frexp in C.
* If v is zero return 0.
*/
public static int getExp(double v) {
if (v==0)
return 0;
return (int)((0x7ff0000000000000L & Double.doubleToLongBits(v))>>52)-1022;
}
static IntegerComparator comp=new IntegerComparator();
TreeMap pos, neg;
// these tree maps will be maps integer multiples of 62
// to longs
// if val->exp then the key represents the number val*2^exp
// the value of the SignDecider is the sup of all positive
// keys minus the sum of all negative keys
/** Construct zero
*/
public SignDecider(){
pos=new TreeMap(comp);
neg=new TreeMap(comp);
}
/** Converts a double into a SignDecider
*/
public SignDecider(double v){
pos=new TreeMap(comp);
neg=new TreeMap(comp);
if (v==0)
return;
// take the integral part
long ip=(Double.doubleToLongBits(v) & 0x000fffffffffffffL)
| 0x0010000000000000L;
int exp=getExp(v)-53;
// now |v| = ip*2^exp
// set a to be the greatest multiple of 62 less than exp
int a=62*((exp >= 0) ? (exp / 62) : ( (exp - 61 ) / 62 ));
if (exp-a<10) {
if (v>=0) {
pos.put(new Integer(a),
new Long(ip<<(exp-a)));
} else {
neg.put(new Integer(a),
new Long(ip<<(exp-a)));
}
} else {
if (v>0) {
long first=((ip<<(exp-a)) & 0x3fffffffffffffffL);
if (first != 0) {
pos.put(new Integer(a),
new Long(first));
}
pos.put(new Integer(62+a),
new Long(ip>>(62+a-exp)));
} else {
long first=((ip<<(exp-a)) & 0x3fffffffffffffffL);
if (first != 0) {
neg.put(new Integer(a),
new Long(first));
}
neg.put(new Integer(62+a),
new Long(ip>>(62+a-exp)));
}
}
}
/**
* Multiplies this SignDecider by negative one. This changes your Signdecider (into its negative).
* Then it is returned for convienience.
*/
public SignDecider negate() {
TreeMap temp=pos;
pos=neg;
neg=temp;
return this;
}
private static void addToTree(Integer a, Long l, TreeMap tree) {
if (l.longValue()==0L) {
return;
}
Object O=tree.get(a);
if (O==null) {
tree.put(a,l);
} else {
long sum=l.longValue()+((Long)O).longValue();
long sum2=sum & 0x3fffffffffffffffL;
if (sum==sum2) {
tree.put(a,
new Long(sum2));
} else {
if (sum2!=0) {
tree.put(a,
new Long(sum2));
} else {
tree.remove(a);
}
// we need to carry a one.
SignDecider.addToTree(new Integer(a.intValue()+62),
new Long(1L),
tree);
}
}
}
/** add sd to this SignDecider. This will be changed into sd+this and then it will be
* returned as well. This allows repeated calls like: sd.add(sd1).add(sd2);
* Warning: you should never add a SignDecider to itself. This could be aranged, but
* whats the point?
*/
public SignDecider add(SignDecider sd){
Set sdset=sd.pos.keySet();
Iterator it=sdset.iterator();
Integer I;
while (it.hasNext()){
I=(Integer)it.next();
SignDecider.addToTree(I,(Long)sd.pos.get(I),pos);
}
sdset=sd.neg.keySet();
it=sdset.iterator();
while (it.hasNext()){
I=(Integer)it.next();
SignDecider.addToTree(I,(Long)sd.neg.get(I),neg);
}
return this;
}
public void outputDebugInfo() {
Integer I;
Long L;
double sum1=0, sum2=0;
System.out.println("Positive Part");
Set sdset=pos.keySet();
Iterator it=sdset.iterator();
while (it.hasNext()){
I=(Integer)it.next();
L=(Long)pos.get(I);
sum1+=L.longValue()*Math.pow(2,I.intValue());
System.out.println(" Storing: "+
L.toString()+"*2^"+I.toString()+" = "+
(L.longValue()*Math.pow(2,I.intValue()))+
" _______ "+
Long.toHexString(L.longValue()));
}
System.out.println("---Total: "+sum1);
System.out.println("Negative Part");
sdset=neg.keySet();
it=sdset.iterator();
while (it.hasNext()){
I=(Integer)it.next();
L=(Long)neg.get(I);
sum2+=L.longValue()*Math.pow(2,I.intValue());
System.out.println(" Storing: "+
L.toString()+"*2^"+I.toString()+" = "+
(L.longValue()*Math.pow(2,I.intValue()))+
" _______ "+
Long.toHexString(L.longValue()));
}
System.out.println("---Total: "+sum2);
System.out.println("Final Total: "+(sum1-sum2));
int s=sign();
if (s==1) {
System.out.println("POSITIVE");
}
if (s==-1) {
System.out.println("NEGATIVE");
}
if (s==0) {
System.out.println("ZERO");
}
}
/** return the left 31 bits of this 62 bit long */
private static long leftHalf(Long l) {
return l.longValue() >> 31;
}
/** return the left 31 bits of this 62 bit long */
private static long leftHalf(long l) {
return l >> 31;
}
/** return the right 31 bits of this 62 bit long */
private static long rightHalf(Long l) {
return l.longValue() & 0x000000007fffffffL;
}
/** return the right 31 bits of this 62 bit long */
private static long rightHalf(long l) {
return l & 0x000000007fffffffL;
}
/** Add sd1*sd2 to sd3 */
private static void addProductToTree(TreeMap sd1,
TreeMap sd2,
TreeMap sd3) {
Set set1=sd1.keySet(),
set2=sd2.keySet();
Iterator it1, it2;
Integer I1,I2;
int exp;
Long L1,L2;
long ls1,ls2,rs1,rs2, temp;
it1=set1.iterator();
while (it1.hasNext()){
I1=(Integer)it1.next();
L1=(Long)sd1.get(I1);
ls1=leftHalf(L1);
rs1=rightHalf(L1);
it2=set2.iterator();
while (it2.hasNext()){
I2=(Integer)it2.next();
L2=(Long)sd2.get(I2);
ls2=leftHalf(L2);
rs2=rightHalf(L2);
exp=I1.intValue()+I2.intValue();
addToTree(new Integer(exp),
new Long(rs1*rs2),
sd3);
addToTree(new Integer(exp+62),
new Long(ls1*ls2),
sd3);
temp=rs1*ls2;
addToTree(new Integer(exp),
new Long(rightHalf(temp) << 31),
sd3);
addToTree(new Integer(exp+62),
new Long(leftHalf(temp)),
sd3);
temp=ls1*rs2;
addToTree(new Integer(exp),
new Long(rightHalf(temp) << 31),
sd3);
addToTree(new Integer(exp+62),
new Long(leftHalf(temp)),
sd3);
}
}
}
/** Adds the product of sd1 and sd2 to this SignDecider. This is modified.
* @return this storing (this + sd1*sd2)
*/
public SignDecider addProductTo( SignDecider sd1,
SignDecider sd2 ) {
addProductToTree(sd1.pos, sd2.pos, pos);
addProductToTree(sd1.pos, sd2.neg, neg);
addProductToTree(sd1.neg, sd2.pos, neg);
addProductToTree(sd1.neg, sd2.neg, pos);
return this;
}
/** Subtracts the product of sd1 and sd2 from this SignDecider. This is modified.
* @return this storing (this - sd1*sd2)
*/
public SignDecider subtractProductFrom( SignDecider sd1,
SignDecider sd2 ) {
addProductToTree(sd1.pos, sd2.pos, neg);
addProductToTree(sd1.pos, sd2.neg, pos);
addProductToTree(sd1.neg, sd2.pos, pos);
addProductToTree(sd1.neg, sd2.neg, neg);
return this;
}
/** At long last: Definatively return the sign of the represented number
* @return -1 if negative, 1 if positive, 0 if zero
*/
public int sign() {
Iterator
pos_it=pos.keySet().iterator(),
neg_it=neg.keySet().iterator();
int pos_i,neg_i;
long pos_l, neg_l;
while (true) {
if (!(pos_it.hasNext())) {
if (!(neg_it.hasNext()))
return 0;
return -1;
}
if (!(neg_it.hasNext()))
return 1;
// both iterators have a next
pos_i=((Integer)pos_it.next()).intValue();
neg_i=((Integer)neg_it.next()).intValue();
if (pos_i > neg_i)
return 1;
if (pos_i < neg_i)
return -1;
// otherwise pos_i == neg_i
pos_l=((Long)pos.get(new Integer(pos_i))).longValue();
neg_l=((Long)neg.get(new Integer(neg_i))).longValue();
if (pos_l > neg_l)
return 1;
if (pos_l < neg_l)
return -1;
}
}
}