001: // Copyright (c) 1997 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.math;
005:
006: /** A Dimensions object represents the product or ratio of BaseUnits.
007: * The idea is that in order to add two Quantities (such as 3mm + 5cm)
008: * their Dimensions have to match. Equal dimensions are also ==.
009: * @author Per Bothner.
010: */
011:
012: public class Dimensions {
013: /** The BaseUnits that this dimension is defined in terms of.
014: * The BaseUnits are in order of their index, and the last
015: * element is Unit.Empty. */
016: BaseUnit[] bases;
017:
018: /** For each baseunit in bases[i], powers[i] is the corresponding exponent.
019: * It is never zero (as long as i is less than the index of Unit.Empty). */
020: short[] powers;
021:
022: int hash_code;
023:
024: /* Points to the next Dimension in the same has bucket of hashTable. */
025: private Dimensions chain;
026:
027: private static Dimensions[] hashTable = new Dimensions[100];
028:
029: public final int hashCode() {
030: return hash_code;
031: }
032:
033: private void enterHash(int hash_code) {
034: this .hash_code = hash_code;
035: int index = (hash_code & 0x7FFFFFFF) % hashTable.length;
036: chain = hashTable[index];
037: hashTable[index] = this ;
038: }
039:
040: /** The empty Dimensions that pure numbers have. */
041: public static Dimensions Empty = new Dimensions();
042:
043: // Only used to create Dimensions.Empty. */
044: private Dimensions() {
045: bases = new BaseUnit[1];
046: bases[0] = Unit.Empty;
047: enterHash(0);
048: }
049:
050: /* Only used by BaseUnit constructor. */
051: Dimensions(BaseUnit unit) {
052: bases = new BaseUnit[2];
053: powers = new short[1];
054: bases[0] = unit;
055: bases[1] = Unit.Empty;
056: powers[0] = 1;
057: enterHash(unit.index);
058: }
059:
060: /** Create a new Dimensions corresponding to a^mul_a*b^mul_b. */
061: private Dimensions(Dimensions a, int mul_a, Dimensions b,
062: int mul_b, int hash_code) {
063: int a_i = 0, b_i = 0;
064: this .hash_code = hash_code;
065: for (a_i = 0; a.bases[a_i] != Unit.Empty; a_i++)
066: ;
067: for (b_i = 0; b.bases[b_i] != Unit.Empty; b_i++)
068: ;
069: int t_i = a_i + b_i + 1;
070: bases = new BaseUnit[t_i];
071: powers = new short[t_i];
072: a_i = b_i = t_i = 0;
073: for (;;) {
074: BaseUnit a_base = a.bases[a_i];
075: BaseUnit b_base = b.bases[b_i];
076: int pow;
077: if (a_base.index < b_base.index) {
078: pow = a.powers[a_i] * mul_a;
079: a_i++;
080: } else if (b_base.index < a_base.index) {
081: a_base = b_base;
082: pow = b.powers[b_i] * mul_b;
083: b_i++;
084: } else if (b_base == Unit.Empty)
085: break;
086: else {
087: pow = a.powers[a_i] * mul_a + b.powers[b_i] * mul_b;
088: a_i++;
089: b_i++;
090: if (pow == 0)
091: continue;
092: }
093: if ((short) pow != pow)
094: throw new ArithmeticException("overflow in dimensions");
095: bases[t_i] = a_base;
096: powers[t_i++] = (short) pow;
097: }
098: bases[t_i] = Unit.Empty;
099: enterHash(hash_code);
100: }
101:
102: /** True if this == (a^mul_a)*(b^mul_b). */
103: private boolean matchesProduct(Dimensions a, int mul_a,
104: Dimensions b, int mul_b) {
105: int a_i = 0, b_i = 0;
106: for (int t_i = 0;;) {
107: BaseUnit a_base = a.bases[a_i];
108: BaseUnit b_base = b.bases[b_i];
109: int pow;
110: if (a_base.index < b_base.index) {
111: pow = a.powers[a_i] * mul_a;
112: a_i++;
113: } else if (b_base.index < a_base.index) {
114: a_base = b_base;
115: pow = b.powers[b_i] * mul_b;
116: b_i++;
117: } else if (b_base == Unit.Empty)
118: return bases[t_i] == b_base;
119: else {
120: pow = a.powers[a_i] * mul_a + b.powers[b_i] * mul_b;
121: a_i++;
122: b_i++;
123: if (pow == 0)
124: continue;
125: }
126: if (bases[t_i] != a_base || powers[t_i] != pow)
127: return false;
128: t_i++;
129: }
130: }
131:
132: public static Dimensions product(Dimensions a, int mul_a,
133: Dimensions b, int mul_b) {
134: int hash = a.hashCode() * mul_a + b.hashCode() * mul_b;
135: int index = (hash & 0x7FFFFFFF) % hashTable.length;
136: Dimensions dim = hashTable[index];
137: for (; dim != null; dim = dim.chain) {
138: if (dim.hash_code == hash
139: && dim.matchesProduct(a, mul_a, b, mul_b))
140: return dim;
141: }
142: return new Dimensions(a, mul_a, b, mul_b, hash);
143: }
144:
145: /** Get the exponent for a BaseUnit in this Dimensions object. */
146: public int getPower(BaseUnit unit) {
147: for (int i = 0; bases[i].index <= unit.index; i++) {
148: if (bases[i] == unit)
149: return powers[i];
150: }
151: return 0;
152: }
153:
154: public String toString() {
155: StringBuffer buf = new StringBuffer();
156: for (int i = 0; bases[i] != Unit.Empty; i++) {
157: if (i > 0)
158: buf.append('*');
159: buf.append(bases[i]);
160: int pow = powers[i];
161: if (pow != 1) {
162: buf.append('^');
163: buf.append(pow);
164: }
165: }
166: return buf.toString();
167: }
168: }
|