1 | |
2 | package rossi.dfp; |
3 | |
4 | /** Subclass of dfp which hides the radix-10000 artifacts of the superclass. This |
5 | * should give outward apperances of being a decimal number with DIGITS*4-3 decimal |
6 | * digits. This class can be subclassed to appear to be an arbitrary number of |
7 | * decimal digits less than DIGITS*4-3. |
8 | */ |
9 | public class dfpdec extends dfp |
10 | { |
11 | protected final static int maxdigits = DIGITS*4-3; |
12 | |
13 | public dfpdec() |
14 | { |
15 | super(); |
16 | } |
17 | |
18 | public dfpdec(dfp d) |
19 | { |
20 | super(d); |
21 | round(0); |
22 | } |
23 | |
24 | public dfpdec(String s) |
25 | { |
26 | super(s); |
27 | round(0); |
28 | } |
29 | |
30 | public dfp newInstance() |
31 | { |
32 | return new dfpdec(); |
33 | } |
34 | |
35 | public dfp newInstance(dfp d) |
36 | { |
37 | return new dfpdec(d); |
38 | } |
39 | |
40 | public dfp newInstance(String s) |
41 | { |
42 | return new dfpdec(s); |
43 | } |
44 | |
45 | /** |
46 | * Return the number of decimal digits this class is going to |
47 | * represent. Default implementation returns DIGITS*4-3. Subclasses |
48 | * can override this to return something less. |
49 | */ |
50 | protected int getDecimalDigits() |
51 | { |
52 | return DIGITS*4-3; |
53 | } |
54 | |
55 | /** round this given the next digit n using the current rounding mode |
56 | * returns a flag if an exception occured |
57 | */ |
58 | protected int round(int in) |
59 | { |
60 | int r, rh, rl; |
61 | boolean inc=false; |
62 | int n; |
63 | int digits = getDecimalDigits(); |
64 | int lsbshift; |
65 | int lsbthreshold = 1000; |
66 | int lsb; |
67 | int cmaxdigits = DIGITS*4; |
68 | int msb = mant[DIGITS-1]; |
69 | int lsd = 0; // position of least sig radix 10k digit |
70 | int discarded = 0; |
71 | |
72 | if (msb == 0) // special case -- this == zero |
73 | return 0; |
74 | |
75 | while (lsbthreshold > msb) |
76 | { |
77 | lsbthreshold /= 10; |
78 | cmaxdigits --; |
79 | } |
80 | |
81 | |
82 | lsbshift = cmaxdigits - digits; |
83 | lsd = lsbshift / 4; |
84 | |
85 | lsbthreshold = 1; |
86 | for (int i=0;i<(lsbshift%4); i++) |
87 | lsbthreshold *= 10; |
88 | |
89 | lsb = mant[lsd]; |
90 | |
91 | //System.out.println("LSBShift = "+lsbshift); |
92 | //System.out.println("LSBThreshold = "+lsbthreshold); |
93 | |
94 | if (lsbthreshold <= 1 && digits == maxdigits) |
95 | return super.round(in); |
96 | |
97 | discarded |= in; // not looking at this after this point |
98 | |
99 | if (lsbthreshold == 1) // look to the next digit for rounding |
100 | { |
101 | n = (mant[lsd-1] / 1000) % 10; |
102 | mant[lsd-1] %= 1000; |
103 | discarded |= mant[lsd-1]; |
104 | } |
105 | else |
106 | { |
107 | n = (lsb * 10 / lsbthreshold) % 10; |
108 | discarded |= (lsb % (lsbthreshold/10)); |
109 | } |
110 | //System.out.println("discardedA = "+discarded); |
111 | |
112 | for (int i=0; i<lsd; i++) |
113 | { |
114 | discarded |= mant[i]; // need to know if thre are any discarded bits |
115 | mant[i] = 0; |
116 | } |
117 | |
118 | //System.out.println("N = "+n); |
119 | //System.out.println("discardedB = "+discarded); |
120 | //System.out.println("oddeven = "+(lsb/lsbthreshold)); |
121 | |
122 | mant[lsd] = lsb / lsbthreshold * lsbthreshold; |
123 | |
124 | switch (rMode) |
125 | { |
126 | case ROUND_DOWN: |
127 | inc = false; |
128 | break; |
129 | |
130 | case ROUND_UP: |
131 | inc = (n!=0 || discarded != 0); // round up if n!=0 |
132 | break; |
133 | |
134 | case ROUND_HALF_UP: |
135 | inc = (n >= 5); // round half up |
136 | break; |
137 | |
138 | case ROUND_HALF_DOWN: |
139 | inc = (n > 5); // round half down |
140 | break; |
141 | |
142 | case ROUND_HALF_EVEN: |
143 | inc = (n > 5 || (n == 5 && discarded != 0) || (n == 5 && discarded == 0 && ((lsb/lsbthreshold)&1)==1)); // round half-even |
144 | break; |
145 | |
146 | case ROUND_HALF_ODD: |
147 | inc = (n > 5 || (n == 5 && discarded != 0) || (n == 5 && discarded == 0 && ((lsb/lsbthreshold)&1)==0)); // round half-odd |
148 | break; |
149 | |
150 | case ROUND_CEIL: |
151 | inc = (sign == 1 && (n != 0 || discarded != 0)); // round ceil |
152 | break; |
153 | |
154 | case ROUND_FLOOR: |
155 | inc = (sign == -1 && (n != 0 || discarded !=0)); // round floor |
156 | break; |
157 | } |
158 | |
159 | if (inc) // increment if necessary |
160 | { |
161 | rh = lsbthreshold; |
162 | for (int i=lsd; i<DIGITS; i++) |
163 | { |
164 | r = mant[i] + rh; |
165 | rh = r / radix; |
166 | rl = r % radix; |
167 | mant[i] = rl; |
168 | } |
169 | |
170 | if (rh != 0) |
171 | { |
172 | shiftRight(); |
173 | mant[DIGITS-1]=rh; |
174 | } |
175 | } |
176 | |
177 | /* Check for exceptional cases and raise signals if necessary */ |
178 | if (exp < minExp) // Gradual Underflow |
179 | { |
180 | ieeeFlags |= FLAG_UNDERFLOW; |
181 | return FLAG_UNDERFLOW; |
182 | } |
183 | |
184 | if (exp > maxExp) // Overflow |
185 | { |
186 | ieeeFlags |= FLAG_OVERFLOW; |
187 | return FLAG_OVERFLOW; |
188 | } |
189 | |
190 | if (n != 0 || discarded != 0) // Inexact |
191 | { |
192 | ieeeFlags |= FLAG_INEXACT; |
193 | return FLAG_INEXACT; |
194 | } |
195 | return 0; |
196 | } |
197 | |
198 | /** Returns the next number greater than this one in the direction |
199 | * of x. If this==x then simply returns this. */ |
200 | |
201 | public dfp nextAfter(dfp x) |
202 | { |
203 | boolean up = false; |
204 | dfp result, inc; |
205 | |
206 | // if this is greater than x |
207 | if (this.lessThan(x)) |
208 | up = true; |
209 | |
210 | if (compare(this, x) == 0) |
211 | return newInstance(x); |
212 | |
213 | if (lessThan(zero)) |
214 | up = !up; |
215 | |
216 | if (up) |
217 | { |
218 | inc = power10(log10() - getDecimalDigits() + 1); |
219 | inc = copysign(inc, this); |
220 | |
221 | if (this.equal(zero)) |
222 | inc = power10K(minExp-DIGITS-1); |
223 | |
224 | if (inc.equal(zero)) |
225 | result = copysign(newInstance(zero), this); |
226 | else |
227 | result = add(inc); |
228 | } |
229 | else |
230 | { |
231 | inc = power10(log10()); |
232 | inc = copysign(inc, this); |
233 | |
234 | if (this.equal(inc)) |
235 | inc = inc.divide(power10(getDecimalDigits())); |
236 | else |
237 | inc = inc.divide(power10(getDecimalDigits() - 1)); |
238 | |
239 | if (this.equal(zero)) |
240 | inc = power10K(minExp-DIGITS-1); |
241 | |
242 | if (inc.equal(zero)) |
243 | result = copysign(newInstance(zero), this); |
244 | else |
245 | result = subtract(inc); |
246 | } |
247 | if (result.classify() == INFINITE && this.classify() != INFINITE) |
248 | { |
249 | ieeeFlags |= FLAG_INEXACT; |
250 | result = dotrap(FLAG_INEXACT, "nextAfter", x, result); |
251 | } |
252 | |
253 | if (result.equal(zero) && this.equal(zero) == false) |
254 | { |
255 | ieeeFlags |= FLAG_INEXACT; |
256 | result = dotrap(FLAG_INEXACT, "nextAfter", x, result); |
257 | } |
258 | |
259 | return result; |
260 | } |
261 | } |