Dimensions.java 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // Copyright (c) 1997 Per M.A. Bothner.
  2. // This is free software; for terms and warranty disclaimer see ./COPYING.
  3. package gnu.math;
  4. /** A Dimensions object represents the product or ratio of BaseUnits.
  5. * The idea is that in order to add two Quantities (such as 3mm + 5cm)
  6. * their Dimensions have to match. Equal dimensions are also ==.
  7. * @author Per Bothner.
  8. */
  9. public class Dimensions
  10. {
  11. /** The BaseUnits that this dimension is defined in terms of.
  12. * The BaseUnits are in order of their index, and the last
  13. * element is Unit.Empty. */
  14. BaseUnit[] bases;
  15. /** For each baseunit in bases[i], powers[i] is the corresponding exponent.
  16. * It is never zero (as long as i is less than the index of Unit.Empty). */
  17. short[] powers;
  18. int hash_code;
  19. /* Points to the next Dimension in the same has bucket of hashTable. */
  20. private Dimensions chain;
  21. private static Dimensions[] hashTable = new Dimensions[100];
  22. public final int hashCode () { return hash_code; }
  23. private void enterHash (int hash_code)
  24. {
  25. this.hash_code = hash_code;
  26. int index = (hash_code & 0x7FFFFFFF) % hashTable.length;
  27. chain = hashTable[index];
  28. hashTable[index] = this;
  29. }
  30. /** The empty Dimensions that pure numbers have. */
  31. public static Dimensions Empty = new Dimensions ();
  32. // Only used to create Dimensions.Empty. */
  33. private Dimensions ()
  34. {
  35. bases = new BaseUnit[1];
  36. bases[0] = Unit.Empty;
  37. enterHash (0);
  38. }
  39. /* Only used by BaseUnit constructor. */
  40. Dimensions (BaseUnit unit)
  41. {
  42. bases = new BaseUnit[2];
  43. powers = new short[1];
  44. bases[0] = unit;
  45. bases[1] = Unit.Empty;
  46. powers[0] = 1;
  47. enterHash (unit.index);
  48. }
  49. /** Create a new Dimensions corresponding to a^mul_a*b^mul_b. */
  50. private Dimensions (Dimensions a, int mul_a, Dimensions b, int mul_b,
  51. int hash_code)
  52. {
  53. int a_i = 0, b_i = 0;
  54. this.hash_code = hash_code;
  55. for (a_i = 0; a.bases[a_i] != Unit.Empty; a_i++) ;
  56. for (b_i = 0; b.bases[b_i] != Unit.Empty; b_i++) ;
  57. int t_i = a_i + b_i + 1;
  58. bases = new BaseUnit[t_i];
  59. powers = new short[t_i];
  60. a_i = b_i = t_i = 0;
  61. for (;;)
  62. {
  63. BaseUnit a_base = a.bases[a_i];
  64. BaseUnit b_base = b.bases[b_i];
  65. int pow;
  66. if (a_base.index < b_base.index)
  67. {
  68. pow = a.powers[a_i] * mul_a;
  69. a_i++;
  70. }
  71. else if (b_base.index < a_base.index)
  72. {
  73. a_base = b_base;
  74. pow = b.powers[b_i] * mul_b;
  75. b_i++;
  76. }
  77. else if (b_base == Unit.Empty)
  78. break;
  79. else
  80. {
  81. pow = a.powers[a_i] * mul_a + b.powers[b_i] * mul_b;
  82. a_i++; b_i++;
  83. if (pow == 0)
  84. continue;
  85. }
  86. if ((short) pow != pow)
  87. throw new ArithmeticException ("overflow in dimensions");
  88. bases[t_i] = a_base;
  89. powers[t_i++] = (short) pow;
  90. }
  91. bases[t_i] = Unit.Empty;
  92. enterHash (hash_code);
  93. }
  94. /** True if this == (a^mul_a)*(b^mul_b). */
  95. private boolean matchesProduct (Dimensions a, int mul_a,
  96. Dimensions b, int mul_b)
  97. {
  98. int a_i = 0, b_i = 0;
  99. for (int t_i = 0; ; )
  100. {
  101. BaseUnit a_base = a.bases[a_i];
  102. BaseUnit b_base = b.bases[b_i];
  103. int pow;
  104. if (a_base.index < b_base.index)
  105. {
  106. pow = a.powers[a_i] * mul_a;
  107. a_i++;
  108. }
  109. else if (b_base.index < a_base.index)
  110. {
  111. a_base = b_base;
  112. pow = b.powers[b_i] * mul_b;
  113. b_i++;
  114. }
  115. else if (b_base == Unit.Empty)
  116. return bases[t_i] == b_base;
  117. else
  118. {
  119. pow = a.powers[a_i] * mul_a + b.powers[b_i] * mul_b;
  120. a_i++; b_i++;
  121. if (pow == 0)
  122. continue;
  123. }
  124. if (bases[t_i] != a_base || powers[t_i] != pow)
  125. return false;
  126. t_i++;
  127. }
  128. }
  129. public static Dimensions product (Dimensions a, int mul_a,
  130. Dimensions b, int mul_b)
  131. {
  132. int hash = a.hashCode () * mul_a + b.hashCode () * mul_b;
  133. int index = (hash & 0x7FFFFFFF) % hashTable.length;
  134. Dimensions dim = hashTable[index];
  135. for ( ; dim != null; dim = dim.chain)
  136. {
  137. if (dim.hash_code == hash && dim.matchesProduct (a, mul_a, b, mul_b))
  138. return dim;
  139. }
  140. return new Dimensions (a, mul_a, b, mul_b, hash);
  141. }
  142. /** Get the exponent for a BaseUnit in this Dimensions object. */
  143. public int getPower (BaseUnit unit)
  144. {
  145. for (int i = 0; bases[i].index <= unit.index; i++)
  146. {
  147. if (bases[i] == unit)
  148. return powers[i];
  149. }
  150. return 0;
  151. }
  152. public String toString ()
  153. {
  154. StringBuffer buf = new StringBuffer ();
  155. for (int i = 0; bases[i] != Unit.Empty; i++)
  156. {
  157. if (i > 0)
  158. buf.append('*');
  159. buf.append (bases[i]);
  160. int pow = powers[i];
  161. if (pow != 1)
  162. {
  163. buf.append ('^');
  164. buf.append (pow);
  165. }
  166. }
  167. return buf.toString ();
  168. }
  169. }