Data Structures, Algorithms, & Applications in Java
Chapter 1, Exercise 16

The code for the class applications.WeightAsLong which uses the metric system is given below.


package applications;

import utilities.*;

public class WeightAsLong
{
   // class constants
   public static final boolean PLUS = true;
   public static final boolean MINUS = false;

   // instance data member
   private long grams;

   // constructors
   /** @throws IllegalArgumentException when theMetricTons < 0
     * or theKilograms < 0 or theKilograms > 999
     * or theMilliMetricTons < 0 or theGrams > 999 */
   public WeightAsLong(boolean theSign, long theMetricTons,
                 int theKilograms, int theGrams)
   {
      if (theMetricTons < 0)
         throw new IllegalArgumentException
               ("MetricTons value must be >= 0, it is " + theMetricTons);

      if (theKilograms < 0 || theKilograms > 999)
         throw new IllegalArgumentException
               ("Kilograms must be between 0 and 999, it is "
                + theKilograms);

      if (theGrams < 0 || theGrams > 999)
         throw new IllegalArgumentException
               ("Grams must be between 0 and 999, it is "
                + theGrams);

      grams = theMetricTons * 1000000 + theKilograms * 1000 + theGrams;
      if (theSign == MINUS)
         grams = -grams;
   }

   /** initialize instance to 0 */
   public WeightAsLong()
      {this(PLUS, 0L, 0, 0);}

   /** initialize with weight = theValue metricTons */
   public WeightAsLong(double theValue)
      {setValue(theValue);}

   /** initialize with grams = theGrams */
   public WeightAsLong(long theGrams)
      {grams = theGrams;}

   // accessor methods
   /** @return sign 
     * For this to work millimeters amount must be nonzero. */
   public boolean getSign()
   {
      if (grams < 0)
         return MINUS;
      else
         return PLUS;
   }

   /** @return metricTons */
   public long getMetricTons()
   {
      if (grams < 0)
         return - grams / 1000000;
      else
         return grams / 1000000;
   }

   /** @return kilograms */
   public int getKilograms()
   {
      if (grams < 0)
         return (int) ((-grams - getMetricTons() * 1000000) / 1000);
      else
         return (int) ((grams - getMetricTons() * 1000000) / 1000);
   }

   /** @return grams */
   public int getGrams()
   {
      if (grams < 0)
         return (int) ((-grams - getMetricTons() * 1000000) % 1000);
      else
         return (int) ((grams - getMetricTons() * 1000000) % 1000);
   }

   // mutator methods
   /** set sign = theSign 
     * For this to work millimeters amount must be nonzero. */
   public void setSign(boolean theSign)
   {
      // change the sign as necessary
      if ((grams < 0 && theSign == PLUS) ||
          (grams > 0 && theSign == MINUS))
         grams = -grams;
   }
 
   /** set metricTons = theMetricTons
     * @throws IllegalArgumentException when theMetricTons < 0 */
   public void setMetricTons(long theMetricTons)
   {
      if (theMetricTons < 0)
         throw new IllegalArgumentException
               ("MetricTons value must be >= 0, it is " + theMetricTons);

      boolean sign = getSign();           // save the sign
      if (grams < 0)                      // make sign PLUS
         grams = -grams;
      long six = grams % 1000000;         // save kg and gm
      grams = theMetricTons * 1000000 + six;
      if (sign == MINUS)
         grams = -grams;
   }

   /** set kilograms = theKilograms
     * @throws IllegalArgumentException when theKilograms < 0 or > 999 */
   public void setKilograms(int theKilograms)
   {
      if (theKilograms < 0 || theKilograms > 999)
         throw new IllegalArgumentException
               ("Kilograms must be between 0 and 999, it is "
                + theKilograms);

      boolean sign = getSign();             // save the sign
      if (grams < 0)                        // make sign PLUS
         grams = -grams;
      long metricTons = grams / 1000000;    // save tons
      long theGrams = grams % 1000;        // save grams
      grams = metricTons * 1000000 + theKilograms * 1000 + theGrams;
      if (sign == MINUS)
         grams = -grams;
   }

   /** set grams = theGrams
     * @throws IllegalArgumentException when theGrams < 0 or > 999 */
   public void setGrams(int theGrams)
   {
      if (theGrams < 0 || theGrams > 999)
         throw new IllegalArgumentException
               ("Grams must be between 0 and 999, it is "
                + theGrams);

      boolean sign = getSign();           // save the sign
      if (grams < 0)                      // make sign PLUS
         grams = -grams;
      grams = (grams / 1000) * 1000 + theGrams;
      if (sign == MINUS)
         grams = -grams;
   }

   /** set length = theValue metricTons */
   public void setValue(double theValue)
   {
      if (theValue < 0 )
         grams = (long) (theValue * 1000000 - 0.5);
      else
         grams = (long) (theValue * 1000000 + 0.5);
   }

   public void setValue(WeightAsLong x)
      {grams = x.grams;}

   /** input a weight */
   public void input()
   {
      // define the input stream to be the standard input stream
      MyInputStream keyboard = new MyInputStream();

      // input the weight as a double
      System.out.println("Enter the weight in metricTons as a real number");
      double theValue = keyboard.readDouble();

      // set the value
      setValue(theValue);
   }
   
   /** convert to a string */
   public String toString()
   {
      if (grams >= 0)
         {return getMetricTons() + "." + grams % 1000000;}
      else
         {return "-" + getMetricTons() + "." + (-grams) % 1000000;}
   }

   // arithmetic methods
   /** @return this + x */
   public WeightAsLong add(WeightAsLong x)
      {return new WeightAsLong(grams + x.grams);}
   
   /** @return this - x */
   public WeightAsLong subtract(WeightAsLong x)
      {return new WeightAsLong(grams - x.grams);}
   
   
   /** @return this * x */
   public WeightAsLong multiply(int x)
      {return new WeightAsLong(x * grams);}
   
   /** @return value of this computed at the rate $x per kilogram */
   public Currency value(Currency x)
   {
      // convert x to a double
      double a1 = x.getDollars() + ((double) x.getCents()) / 100;
      if (x.getSign() == MINUS)
         a1 = -a1;
      return new Currency(grams * a1 / 1000);
   }
   
   /** test program */
   public static void main(String [] args)
   {
      // test constructors
      WeightAsLong g = new WeightAsLong(),
             h = new WeightAsLong(PLUS, 3L, 502, 421),
             i = new WeightAsLong(-2.507633),
             j = new WeightAsLong();

      // test input
      j.input();

      // test toString
      System.out.println("The initial values are " + g +
                         " " + h + " " + i + " " + j);
      System.out.println();

      // test mutators
      // first make g nonzero
      g.setMetricTons(2);
      g.setSign(MINUS);
      g.setKilograms(256);
      g.setGrams(123);
      i.setValue(-6.453210);
      System.out.println("New values are " + g + " " + i);
      System.out.println();

      // do some arithmetic
      j = h.add(g);
      System.out.println(h + " + " + g + " = " + j);

      j = i.add(g).subtract(h);
      System.out.println(i + " + " + g + " - " + h +
                         " = " + j);
      System.out.println();

      j = i.multiply(2);
      System.out.println(i + " * 2 = "  + j);
      System.out.println();

      Currency x = new Currency(3.0);
      Currency y = i.value(x);
      System.out.println("Value of " + i + " metricTons at $3 per "
                         + "kilogram is "  + y);
      System.out.println();
   }
}