Mega Code Archive

 
Categories / Java / Data Type
 

Ternary Numnber

/*  * @(#)Ternary.java  1.0 Mar 7, 2008  *  *  The MIT License  *  *  Copyright (c) 2008 Malachi de AElfweald <malachid@gmail.com>  *  *  Permission is hereby granted, free of charge, to any person obtaining a copy  *  of this software and associated documentation files (the "Software"), to deal  *  in the Software without restriction, including without limitation the rights  *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  *  copies of the Software, and to permit persons to whom the Software is  *  furnished to do so, subject to the following conditions:  *  *  The above copyright notice and this permission notice shall be included in  *  all copies or substantial portions of the Software.  *  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN  *  THE SOFTWARE.  */ //package org.eoti.math.ternary; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Comparator; import java.util.concurrent.CopyOnWriteArrayList; public class Ternary extends Number implements Comparable<Ternary> {   protected BigInteger biThree = BigInteger.valueOf(3);   protected BigDecimal bdThree = new BigDecimal(biThree);   protected CopyOnWriteArrayList<Trit> trits;   public static void main(String[] args)   {     if(args.length == 0)     {       System.out.format("java org.eoti.lang.Ternary number [[number]...]\n");       System.exit(0);     }     for(String arg : args)     {       BigInteger toConvert = new BigInteger(arg);       Ternary ternary = new Ternary(toConvert);       System.out.format("\nDecimal:\t%s\nTernary:\t%s\n", toConvert, ternary);     }   }   public Ternary(int toConvert)   {     this(BigInteger.valueOf(toConvert));   }   public Ternary(BigInteger toConvert)   {     this();     int position = 0;     BigInteger remaining = toConvert;     BigInteger rounded, left;     while(!remaining.equals(BigInteger.ZERO))     {       rounded = ((new BigDecimal(remaining)).divide(bdThree, 0, BigDecimal.ROUND_HALF_UP)).toBigInteger();       left = remaining.subtract(rounded.multiply(biThree));       if(left.equals(BigInteger.ONE)) setTrit(position++, Trit.POSITIVE);       else if(left.equals(BigInteger.ZERO)) setTrit(position++, Trit.NEUTRAL);       else setTrit(position++, Trit.NEGATIVE);       remaining = rounded;     }   }   public Ternary()   {     super();     trits = new CopyOnWriteArrayList<Trit>();   }   public Ternary(Ternary toClone)   {     this();     trits.addAll(toClone.trits);   }   public Ternary abs()   {     if(signum() >= 0) return new Ternary(this);     return invert(this);   }   public int tritLength()   {     for(int position=trits.size()-1; position>=0; position--)     {       if(!trits.get(position).equals(Trit.NEUTRAL))         return position+1;     }     return 0;     //return trits.size();   }   public void clearTrit(int position){setTrit(position, Trit.NEUTRAL);}   public void setTrit(int position, Trit trit)   {     if(trits.size() <= position)       ensureCapacity(position+1);     trits.set(position, trit);   }   public Trit getTrit(int position)   {     if(position < 0) return Trit.NEUTRAL;     if(trits.size() <= position)       ensureCapacity(position+1);     return trits.get(position);   }   public int signum(){return getTrit(tritLength()-1).toInt();}   public void ensureCapacity(int nTerts)   {     while(trits.size() < nTerts)       trits.add(Trit.NEUTRAL);   }   public void trim()   {     while( (trits.size() > 0) && (trits.get(trits.size()-1).isNeutral()) )       trits.remove(trits.size()-1);   }   public void increment(){increment(0);}   public void increment(int position)   {     Trit t = getTrit(position).rotateUp();     setTrit(position, t);     if(t.isNegative()) // carry       increment(position+1);   }   public void decrement(){decrement(0);}   public void decrement(int position)   {     Trit t = getTrit(position).rotateDown();     setTrit(position, t);     if(t.isPositive()) // borrow       decrement(position+1);   }   public String toString()   {     if(trits.size() == 0) return Trit.NEUTRAL.toString();     StringBuilder sb = new StringBuilder();     for(Trit trit : trits)       sb.append(trit);     return sb.reverse().toString();   }   public int compareTo(Ternary t)   {     // shortcut if one is positive and the other negative     int ourSig = signum();     int theirSig = t.signum();     if(ourSig > theirSig) return 1;     if(theirSig > ourSig) return -1;     // we're the same sign... who has more trits?     int ourLength = tritLength();     int theirLength = t.tritLength();     if(ourLength > theirLength) return (ourSig>0?1:-1);     if(theirLength > ourLength) return (ourSig>0?-1:1);     // same sign, same length... guess we need to find first mismatch     for(int position = ourLength-1; position >= 0; position--)     {       int comparison = getTrit(position).compareTo(t.getTrit(position));       if(comparison != 0) return comparison;     }     // guess we are identical     return 0;   }   public boolean equals(Object obj)   {     if(obj == null) return false;     return toString().equals(obj.toString());   }   public int hashCode()   {     return toString().hashCode();   }   public BigInteger toBigInteger()   {     BigInteger toRet = BigInteger.ZERO;     BigInteger curr;     for(int pos=0; pos<trits.size(); pos++)     {       curr = (biThree.pow(pos)).multiply(BigInteger.valueOf(getTrit(pos).toInt()));       toRet = toRet.add(curr);     }     return toRet;   }   public void shiftLeft(){shiftLeft(1);}   public void shiftLeft(int num)   {     CopyOnWriteArrayList<Trit> newTrits = new CopyOnWriteArrayList<Trit>();     for(int i=0; i<num; i++)         newTrits.add(Trit.NEUTRAL);     newTrits.addAll(trits);     trits = newTrits;   }   public void shiftRight(){shiftRight(1);}   public void shiftRight(int num)   {     ensureCapacity(trits.size() + num);     for(int i=0; i<num; i++)       trits.remove(0);   }   public byte byteValue(){return toBigInteger().byteValue();}   public double doubleValue(){return toBigInteger().doubleValue();}   public float floatValue(){return toBigInteger().floatValue();}   public int intValue(){return toBigInteger().intValue();}   public long longValue(){return toBigInteger().longValue();}   public short shortValue(){return toBigInteger().shortValue();}   /**    * Add the specified addend to this augend    *    * @param addend to be added    * @return ternary summation    */   public Ternary add(Ternary addend)   {     /**      * Try to find a better way of doing this      * using gate logic      * and DON'T just use toBigInteger to do it      */     // make sure the LONGER one is on top     if(tritLength() < addend.tritLength()) return addend.add(this);     Ternary summation = new Ternary(this);     Ternary toCarry = new Ternary();     for(int pos=0; pos<trits.size(); pos++)     {       Trit a = summation.getTrit(pos);       Trit b = addend.getTrit(pos);       switch(a.state)       {         case Negative:           summation.setTrit(pos, b.rotateDown());           break;         case Positive:           summation.setTrit(pos, b.rotateUp());           break;         default:           summation.setTrit(pos, b);       }       if(a.equals(b)) toCarry.setTrit(pos+1, a);     }     if(toCarry.tritLength() == 0)       return summation;     return summation.add(toCarry);   }   /**    * Subtract the specified subtrahend from this minuend    *    * @param subtrahend to be subtracted    * @return ternary difference    */   public Ternary subtract(Ternary subtrahend)   {     return add(invert(subtrahend));   }   public static Ternary invert(Ternary toInvert)   {     Ternary inverted = new Ternary();     for(int i=0; i<toInvert.trits.size(); i++)       inverted.setTrit(i, toInvert.getTrit(i).invert());     return inverted;   }   /**    * Multiply this multiplicand by the specified multiplier    *    * @param multiplier to multiply by    * @return ternary product    */   public Ternary multiply(Ternary multiplier)   {     /**      * Try to find a better way of doing this      * using gate logic      * and DON'T just use toBigInteger to do it      */     // make sure the LONGER one is on top     if(tritLength() < multiplier.tritLength()) return multiplier.multiply(this);     Ternary product = new Ternary();     for(int posB=0; posB<multiplier.trits.size(); posB++)     {       Ternary row = new Ternary();       for(int posA=0; posA<trits.size(); posA++)       {         Trit a = getTrit(posA);         Trit b = multiplier.getTrit(posB);         Trit c = a.equality(b);         if(a.isNeutral() && b.isNeutral())           c = Trit.NEUTRAL;         row.setTrit(posA + posB, c);       }       product = product.add(row);     }     return product;   }   /**    * Divide this divided by the specified divisor    *    * @param divisor to divide by    * @return ternary[] containing {quotient,remainder}    */   public Ternary[] divide(Ternary divisor)   {     /**      * 6/3=2r0      * 6=dividend      * 3=divisor      * 2=quotient      * 0=remainder      */     Ternary dividend = new Ternary(this);     Ternary quotient = new Ternary(0);     Ternary remainder = new Ternary(0);     int dividendSign = dividend.signum();     if(dividendSign == 0) return new Ternary[]{quotient, remainder};     int divisorSign = divisor.signum();     if(divisorSign == 0) throw new ArithmeticException("Divide by Zero not currently supported.");     if(dividendSign != divisorSign)     {       // if one or the other (not both) are negative, then the result will have a negative quotient       Ternary tmp = null;       Ternary[] results = null;       if(dividendSign < 0)       {         tmp = new Ternary(dividend);         tmp = invert(tmp);         //results = tmp.divide(divisor);         results = tmp.divide(divisor);       }else{         tmp = new Ternary(divisor);         tmp = invert(tmp);         //results = dividend.divide(tmp);         results = dividend.divide(tmp);       }       quotient = invert(results[0]);       remainder = dividend.subtract(quotient.multiply(divisor));       return new Ternary[]{quotient, remainder};     }     // two positives or two negatives will be positive results     if(dividendSign < 0)     {       dividend = invert(dividend);       divisor = invert(divisor);     }     int position = dividend.tritLength()-1;     while(position >= 0)     {       remainder = (new Ternary(dividend)).subtract(quotient.multiply(divisor));       remainder.shiftRight(position);       int compare = remainder.compareTo(divisor);       if(compare > 0)       {         quotient.increment();       }else if(compare < 0){         if(position > 0)           quotient.shiftLeft(1);         position--;       }else{         quotient.increment();         position--;       }     }     remainder = (new Ternary(dividend)).subtract(quotient.multiply(divisor));     return new Ternary[]{quotient, remainder};   }   public Ternary sqrt()   {     return sqrt(this);   }   public static Ternary sqrt(Ternary number)   {     return sqrt(number, new Ternary(1));   }   protected static Ternary sqrt(Ternary number, Ternary guess)   {     // ((n/g) + g)/2: until same result twice in a row     Ternary result = new Ternary(0);     Ternary flipA = new Ternary(result);     Ternary flipB = new Ternary(result);     boolean first = true;     while( result.compareTo(guess) != 0)     {           if(!first) guess = result;           else first = false;           result = (number.divide(guess))[0];           result = result.add(guess);           result = (result.divide(new Ternary(2)))[0];       result.trim();           // handle flip flops           if(result.equals(flipB)) return flipA;           flipB = flipA;           flipB.trim();           flipA = result;           flipA.trim();     }     return result;   } } class Trit implements Comparable<Trit>, Comparator<Trit> {   protected enum State   {     Negative(-1, '\u012B'), Neutral(0, '0'), Positive(1, '1');     State(int intValue, char charValue)     {       this.intValue = intValue;       this.charValue = charValue;     }     protected int intValue;     protected char charValue;     public int toInt(){return intValue;}     public char toChar(){return charValue;}   }   // convenience access   public static final Trit NEGATIVE = new Trit(State.Negative);   public static final Trit NEUTRAL = new Trit(State.Neutral);   public static final Trit POSITIVE = new Trit(State.Positive);   protected State state;   public Trit(State state){this.state = state;}   public Trit(Trit trit){this.state = trit.state;}   public boolean isNegative(){return state == State.Negative;}   public boolean isNeutral(){return state == State.Neutral;}   public boolean isPositive(){return state == State.Positive;}   public Trit max(Trit other){return toInt() >= other.toInt() ? this : other;}   public Trit min(Trit other){return toInt() <= other.toInt() ? this : other;}   public Trit or(Trit other){return max(other).clone();}   public Trit and(Trit other){return min(other).clone();}   public Trit xor(Trit other)   {     if(isNegative() && other.isNegative()) return NEGATIVE.clone();     if(isNegative() && other.isPositive()) return POSITIVE.clone();     if(isPositive() && other.isNegative()) return POSITIVE.clone();     return NEUTRAL.clone();   }   public Trit nand(Trit other){return not(and(other));}   public Trit nor(Trit other){return not(or(other));}   public Trit nxor(Trit other){return not(xor(other));}   /**    * Invert unary operation    * ? becomes 1    * 0 becomes 0    * 1 becomes ?    */   public Trit invert(){return not();}   public Trit not()   {     switch(state)     {       case Negative:         return Trit.POSITIVE.clone();       case Positive:         return Trit.NEGATIVE.clone();       default:         return Trit.NEUTRAL.clone();     }   }   public Trit not(Trit other){return inequality(other);}   public Trit inequality(Trit other)   {     Trit eq = equality(other);     if(eq.isPositive()) return NEGATIVE.clone();     if(eq.isNegative()) return POSITIVE.clone();     return NEUTRAL.clone();   }   public Trit disjunction(Trit other){return or(other);}   public Trit conjunction(Trit other){return and(other);}     public Trit equality(Trit other)   {     if(state == other.state) return POSITIVE.clone();     if(isNeutral()) return NEUTRAL.clone();     if(other.isNeutral()) return NEUTRAL.clone();     return NEGATIVE.clone();   }   public Trit implication(Trit other)   {     if(other.isNegative() && isNeutral()) return NEUTRAL.clone();     if(other.isNegative() && isPositive()) return NEGATIVE.clone();     if(other.isNeutral() && isPositive()) return NEUTRAL.clone();     return POSITIVE.clone();   }   public Trit alternation(Trit other){return xor(other);}   /**    * ShiftUp unary operation    * ? becomes 0    * 0 becomes 1    * 1 becomes 1    */   public Trit shiftUp(){return NEUTRAL.implication(this);}   /**    * ShiftDown unary operation    * ? becomes ?    * 0 becomes ?    * 1 becomes 0    */   public Trit shiftDown(){return not(implication(NEUTRAL));}   /**    * RotateUp unary operation    * ? becomes 0    * 0 becomes 1    * 1 becomes ?    */   public Trit rotateUp()   {     /**      * Change to use gate logic?      */     switch(state)     {       case Negative: return NEUTRAL.clone();       case Neutral: return POSITIVE.clone();       default: return NEGATIVE.clone();     }   }   /**    * RotateDown unary operation    * ? becomes 1    * 0 becomes ?    * 1 becomes 0    */   public Trit rotateDown()   {     /**      * Change to use gate logic?      */     switch(state)     {       case Negative: return POSITIVE.clone();       case Neutral: return NEGATIVE.clone();       default: return NEUTRAL.clone();     }   }   public String toString(){return ""+toChar();}   public char toChar(){return state.toChar();}   public int toInt(){return state.toInt();}   public Trit clone(){return new Trit(state);}   public boolean equals(Object obj)   {     if(obj == null) return false;     if(!Trit.class.isAssignableFrom(obj.getClass())) return false;     return (compareTo((Trit)obj) == State.Neutral.toInt());   }   public int compareTo(Trit obj){return compare(this, obj);}   public int compare(Trit t1, Trit t2)   {     if(t1.state.toInt() < t2.state.toInt())       return State.Negative.toInt();     if(t1.state.toInt() > t2.state.toInt())       return State.Positive.toInt();     return State.Neutral.toInt();   }   /**    * Returns a hash code value for the object. This method is supported for the benefit of hashtables such as those    * provided by <code>java.util.Hashtable</code>.    * <p/>    * The general contract of <code>hashCode</code> is: <ul> <li>Whenever it is invoked on the same object more than once    * during an execution of a Java application, the <tt>hashCode</tt> method must consistently return the same integer,    * provided no information used in <tt>equals</tt> comparisons on the object is modified. This integer need not remain    * consistent from one execution of an application to another execution of the same application. <li>If two objects are    * equal according to the <tt>equals(Object)</tt> method, then calling the <code>hashCode</code> method on each of the    * two objects must produce the same integer result. <li>It is <em>not</em> required that if two objects are unequal    * according to the {@link Object#equals(Object)} method, then calling the <tt>hashCode</tt> method on each of the two    * objects must produce distinct integer results.  However, the programmer should be aware that producing distinct    * integer results for unequal objects may improve the performance of hashtables. </ul>    * <p/>    * As much as is reasonably practical, the hashCode method defined by class <tt>Object</tt> does return distinct    * integers for distinct objects. (This is typically implemented by converting the internal address of the object into    * an integer, but this implementation technique is not required by the Java<font size="-2"><sup>TM</sup></font>    * programming language.)    *    * @return a hash code value for this object.    *    * @see Object#equals(Object)    * @see java.util.Hashtable    */   @Override public int hashCode(){     return toString().hashCode();   } } /* package org.eoti.math.ternary; import junit.framework.TestCase; import junit.framework.Test; import junit.framework.TestSuite; public class TernaryTest   extends TestCase {   public TernaryTest(String name){super(name);}   public static Test suite(){return new TestSuite(TernaryTest.class);}   public void testInt()   {     int toTest = 13;     assertEquals("Int", toTest, (new Ternary(toTest)).intValue());   }   public void testSignum()   {     assertEquals("Positive Signum", 1, (new Ternary(10)).signum());     assertEquals("Neutral Signum", 0, (new Ternary(0)).signum());     assertEquals("Negative Signum", -1, (new Ternary(-10)).signum());   }   public void testTritLength()   {     assertTrue("TritLength(13)", (new Ternary(13)).tritLength() == 3);     assertTrue("TritLength(14)", (new Ternary(14)).tritLength() == 4);   }   public void testClearTrit()   {     Ternary tst = new Ternary(13);     tst.clearTrit(1);     Ternary expected = new Ternary(10);     assertEquals("ClearTrit", expected, tst);   }   public void testSetTrit()   {     Ternary tst = new Ternary(10);     tst.setTrit(1, Trit.POSITIVE);     Ternary expected = new Ternary(13);     assertEquals("SetTrit", expected, tst);   }   public void testIncrement()   {     Ternary tst = new Ternary(-1);     tst.increment();     assertEquals("Increment -1->0", 0, tst.intValue());     tst.increment();     assertEquals("Increment 0->1", 1, tst.intValue());     tst.increment();     assertEquals("Increment 1->2", 2, tst.intValue());     tst.increment();     assertEquals("Increment 2->3", 3, tst.intValue());   }   public void testDecrement()   {     Ternary tst = new Ternary(3);     tst.decrement();     assertEquals("Decrement 3->2", 2, tst.intValue());     tst.decrement();     assertEquals("Decrement 2->1", 1, tst.intValue());     tst.decrement();     assertEquals("Decrement 1->0", 0, tst.intValue());     tst.decrement();     assertEquals("Decrement 0->-1", -1, tst.intValue());   }   public void testShiftLeft()   {     Ternary tst = new Ternary(8); // +0-     tst.shiftLeft();     tst.trim();     Ternary expected = new Ternary(24);// +0-0     expected.trim();     assertEquals("ShiftLeft", expected, tst);   }   public void testShiftRight()   {     Ternary tst = new Ternary(24);// +0-0     tst.shiftRight();     tst.trim();     Ternary expected = new Ternary(8); // +0-     expected.trim();     assertEquals("ShiftRight", expected, tst);   }   public void testAdd()   {     assertEquals("Add PosPos", new Ternary(13), (new Ternary(10)).add(new Ternary(3)));     assertEquals("Add PosNeg", new Ternary(7), (new Ternary(10)).add(new Ternary(-3)));     assertEquals("Add NegNeg", new Ternary(-13), (new Ternary(-10)).add(new Ternary(-3)));     assertEquals("Add NegPos", new Ternary(-7), (new Ternary(-10)).add(new Ternary(3)));   }   public void testSubtract()   {     assertEquals("Subtract PosPos", new Ternary(7), (new Ternary(10)).subtract(new Ternary(3)));     assertEquals("Subtract PosNeg", new Ternary(13), (new Ternary(10)).subtract(new Ternary(-3)));     assertEquals("Subtract NegNeg", new Ternary(-7), (new Ternary(-10)).subtract(new Ternary(-3)));     assertEquals("Subtract NegPos", new Ternary(-13), (new Ternary(-10)).subtract(new Ternary(3)));   }   public void testMultiply()   {     assertEquals("Multiply PosPos", new Ternary(15), (new Ternary(5)).multiply(new Ternary(3)));     assertEquals("Multiply PosNeg", new Ternary(-15), (new Ternary(5)).multiply(new Ternary(-3)));     assertEquals("Multiply NegNeg", new Ternary(15), (new Ternary(-5)).multiply(new Ternary(-3)));     assertEquals("Multiply NegPos", new Ternary(-15), (new Ternary(-5)).multiply(new Ternary(3)));   }   public void testDivide()   {     // 6/3=2r0; 6=dividend; 3=divisor; 2=quotient; 0=remainder     Ternary dividend = new Ternary(7);     Ternary divisor = new Ternary(2);     Ternary expectedQuotient = new Ternary(3);     Ternary expectedRemainder = new Ternary(1);     Ternary[] results = dividend.divide(divisor);     results[0].trim();     results[1].trim();     assertEquals("Divide(7/2) Quotient", expectedQuotient, results[0]);     assertEquals("Divide(7/2) Remainder", expectedRemainder, results[1]);     dividend = new Ternary(7);     divisor = new Ternary(-2);     expectedQuotient = new Ternary(-3);     expectedRemainder = new Ternary(1);     results = dividend.divide(divisor);     results[0].trim();     results[1].trim();     assertEquals("Divide(7/-2) Quotient", expectedQuotient, results[0]);     assertEquals("Divide(7/-2) Remainder", expectedRemainder, results[1]);     dividend = new Ternary(-7);     divisor = new Ternary(2);     expectedQuotient = new Ternary(-3);     expectedRemainder = new Ternary(-1);     results = dividend.divide(divisor);     results[0].trim();     results[1].trim();     assertEquals("Divide(-7/2) Quotient", expectedQuotient, results[0]);     assertEquals("Divide(-7/2) Remainder", expectedRemainder, results[1]);     dividend = new Ternary(-7);     divisor = new Ternary(-2);     expectedQuotient = new Ternary(3);     expectedRemainder = new Ternary(1);     results = dividend.divide(divisor);     results[0].trim();     results[1].trim();     assertEquals("Divide(-7/-2) Quotient", expectedQuotient, results[0]);     assertEquals("Divide(-7/-2) Remainder", expectedRemainder, results[1]);     dividend = new Ternary(0);     divisor = new Ternary(2);     expectedQuotient = new Ternary(0);     expectedRemainder = new Ternary(0);     results = dividend.divide(divisor);     results[0].trim();     results[1].trim();     assertEquals("Divide(0/2) Quotient", expectedQuotient, results[0]);     assertEquals("Divide(0/2) Remainder", expectedRemainder, results[1]);     try{       dividend = new Ternary(2);       divisor = new Ternary(0);       results = dividend.divide(divisor);       fail("Divide(2/0): Should have caused ArithmeticException");     }catch(ArithmeticException ae){       // good     }   }   public void testSqrt()   {     if(true)     {       assertTrue("SKIPPING testSqrt", true);       return;     }     assertEquals("SQRT", new Ternary(3), (new Ternary(15)).sqrt());     assertEquals("SQRT", new Ternary(4), (new Ternary(16)).sqrt());     assertEquals("SQRT", new Ternary(4), (new Ternary(17)).sqrt());     assertEquals("SQRT", new Ternary(6), (new Ternary(48)).sqrt());     assertEquals("SQRT", new Ternary(7), (new Ternary(49)).sqrt());     assertEquals("SQRT", new Ternary(7), (new Ternary(50)).sqrt());     assertEquals("SQRT", new Ternary(41), (new Ternary(1702)).sqrt());     assertEquals("SQRT", new Ternary(41), (new Ternary(1703)).sqrt());     assertEquals("SQRT", new Ternary(41), (new Ternary(1704)).sqrt());     assertEquals("SQRT", new Ternary(10), (new Ternary(100)).sqrt());   }   public void testAbs()   {     assertEquals("SQRT", new Ternary(5), (new Ternary(5)).abs());     assertEquals("SQRT", new Ternary(5), (new Ternary(-5)).abs());     assertEquals("SQRT", new Ternary(0), (new Ternary(0)).abs());   } } */