-
Notifications
You must be signed in to change notification settings - Fork 0
/
MathContext.as
529 lines (481 loc) · 21.2 KB
/
MathContext.as
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
package
{
/* ------------------------------------------------------------------ */
/* MathContext -- Math context settings */
/* ------------------------------------------------------------------ */
/* Copyright IBM Corporation, 1997, 2000, 2005. All Rights Reserved. */
/* */
/* The MathContext object encapsulates the settings used by the */
/* BigDecimal class; it could also be used by other arithmetics. */
/* ------------------------------------------------------------------ */
/* Notes: */
/* */
/* 1. The properties are checked for validity on construction, so */
/* the BigDecimal class may assume that they are correct. */
/* ------------------------------------------------------------------ */
/* Author: Mike Cowlishaw */
/* 1997.09.03 Initial version (edited from netrexx.lang.RexxSet) */
/* 1997.09.12 Add lostDigits property */
/* 1998.05.02 Make the class immutable and final; drop set methods */
/* 1998.06.05 Add Round (rounding modes) property */
/* 1998.06.25 Rename from DecimalContext; allow digits=0 */
/* 1998.10.12 change to com.ibm.icu.math package */
/* 1999.02.06 add javadoc comments */
/* 1999.03.05 simplify; changes from discussion with J. Bloch */
/* 1999.03.13 1.00 release to IBM Centre for Java Technology */
/* 1999.07.10 1.04 flag serialization unused */
/* 2000.01.01 1.06 copyright update */
/* ------------------------------------------------------------------ */
/**
* The <code>MathContext</code> immutable class encapsulates the
* settings understood by the operator methods of the {@link BigDecimal}
* class (and potentially other classes). Operator methods are those
* that effect an operation on a number or a pair of numbers.
* <p>
* The settings, which are not base-dependent, comprise:
* <ol>
* <li><code>digits</code>:
* the number of digits (precision) to be used for an operation
* <li><code>form</code>:
* the form of any exponent that results from the operation
* <li><code>lostDigits</code>:
* whether checking for lost digits is enabled
* <li><code>roundingMode</code>:
* the algorithm to be used for rounding.
* </ol>
* <p>
* When provided, a <code>MathContext</code> object supplies the
* settings for an operation directly.
* <p>
* When <code>MathContext.DEFAULT</code> is provided for a
* <code>MathContext</code> parameter then the default settings are used
* (<code>9, SCIENTIFIC, false, ROUND_HALF_UP</code>).
* <p>
* In the <code>BigDecimal</code> class, all methods which accept a
* <code>MathContext</code> object defaults) also have a version of the
* method which does not accept a MathContext parameter. These versions
* carry out unlimited precision fixed point arithmetic (as though the
* settings were (<code>0, PLAIN, false, ROUND_HALF_UP</code>).
* <p>
* The instance variables are shared with default access (so they are
* directly accessible to the <code>BigDecimal</code> class), but must
* never be changed.
* <p>
* The rounding mode constants have the same names and values as the
* constants of the same name in <code>java.math.BigDecimal</code>, to
* maintain compatibility with earlier versions of
* <code>BigDecimal</code>.
*
* @see BigDecimal
* @author Mike Cowlishaw
* @stable ICU 2.0
*/
public class MathContext {
/* ----- Properties ----- */
/* properties public constant */
/**
* Plain (fixed point) notation, without any exponent.
* Used as a setting to control the form of the result of a
* <code>BigDecimal</code> operation.
* A zero result in plain form may have a decimal part of one or
* more zeros.
*
* @see #ENGINEERING
* @see #SCIENTIFIC
* @stable ICU 2.0
*/
public static const NOTATION_PLAIN:int = 0; // [no exponent]
/**
* Standard floating point notation (with scientific exponential
* format, where there is one digit before any decimal point).
* Used as a setting to control the form of the result of a
* <code>BigDecimal</code> operation.
* A zero result in plain form may have a decimal part of one or
* more zeros.
*
* @see #ENGINEERING
* @see #PLAIN
* @stable ICU 2.0
*/
public static const NOTATION_SCIENTIFIC:int = 1; // 1 digit before .
/**
* Standard floating point notation (with engineering exponential
* format, where the power of ten is a multiple of 3).
* Used as a setting to control the form of the result of a
* <code>BigDecimal</code> operation.
* A zero result in plain form may have a decimal part of one or
* more zeros.
*
* @see #PLAIN
* @see #SCIENTIFIC
* @stable ICU 2.0
*/
public static const NOTATION_ENGINEERING:int = 2; // 1-3 digits before .
// The rounding modes match the original BigDecimal class values
/**
* Rounding mode to round to a more positive number.
* Used as a setting to control the rounding mode used during a
* <code>BigDecimal</code> operation.
* <p>
* If any of the discarded digits are non-zero then the result
* should be rounded towards the next more positive digit.
* @stable ICU 2.0
*/
public static const ROUND_CEILING:int = 2;
/**
* Rounding mode to round towards zero.
* Used as a setting to control the rounding mode used during a
* <code>BigDecimal</code> operation.
* <p>
* All discarded digits are ignored (truncated). The result is
* neither incremented nor decremented.
* @stable ICU 2.0
*/
public static const ROUND_DOWN:int = 1;
/**
* Rounding mode to round to a more negative number.
* Used as a setting to control the rounding mode used during a
* <code>BigDecimal</code> operation.
* <p>
* If any of the discarded digits are non-zero then the result
* should be rounded towards the next more negative digit.
* @stable ICU 2.0
*/
public static const ROUND_FLOOR:int = 3;
/**
* Rounding mode to round to nearest neighbor, where an equidistant
* value is rounded down.
* Used as a setting to control the rounding mode used during a
* <code>BigDecimal</code> operation.
* <p>
* If the discarded digits represent greater than half (0.5 times)
* the value of a one in the next position then the result should be
* rounded up (away from zero). Otherwise the discarded digits are
* ignored.
* @stable ICU 2.0
*/
public static const ROUND_HALF_DOWN:int = 5;
/**
* Rounding mode to round to nearest neighbor, where an equidistant
* value is rounded to the nearest even neighbor.
* Used as a setting to control the rounding mode used during a
* <code>BigDecimal</code> operation.
* <p>
* If the discarded digits represent greater than half (0.5 times)
* the value of a one in the next position then the result should be
* rounded up (away from zero). If they represent less than half,
* then the result should be rounded down.
* <p>
* Otherwise (they represent exactly half) the result is rounded
* down if its rightmost digit is even, or rounded up if its
* rightmost digit is odd (to make an even digit).
* @stable ICU 2.0
*/
public static const ROUND_HALF_EVEN:int = 6;
/**
* Rounding mode to round to nearest neighbor, where an equidistant
* value is rounded up.
* Used as a setting to control the rounding mode used during a
* <code>BigDecimal</code> operation.
* <p>
* If the discarded digits represent greater than or equal to half
* (0.5 times) the value of a one in the next position then the result
* should be rounded up (away from zero). Otherwise the discarded
* digits are ignored.
* @stable ICU 2.0
*/
public static const ROUND_HALF_UP:int = 4;
/**
* Rounding mode to assert that no rounding is necessary.
* Used as a setting to control the rounding mode used during a
* <code>BigDecimal</code> operation.
* <p>
* Rounding (potential loss of information) is not permitted.
* If any of the discarded digits are non-zero then an
* <code>ArithmeticException</code> should be thrown.
* @stable ICU 2.0
*/
public static const ROUND_UNNECESSARY:int = 7;
/**
* Rounding mode to round away from zero.
* Used as a setting to control the rounding mode used during a
* <code>BigDecimal</code> operation.
* <p>
* If any of the discarded digits are non-zero then the result will
* be rounded up (away from zero).
* @stable ICU 2.0
*/
public static const ROUND_UP:int = 0;
/* properties shared */
/**
* The number of digits (precision) to be used for an operation.
* A value of 0 indicates that unlimited precision (as many digits
* as are required) will be used.
* <p>
* The {@link BigDecimal} operator methods use this value to
* determine the precision of results.
* Note that leading zeros (in the integer part of a number) are
* never significant.
* <p>
* <code>digits</code> will always be non-negative.
*
* @serial
*/
internal var digits:int;
/**
* The form of results from an operation.
* <p>
* The {@link BigDecimal} operator methods use this value to
* determine the form of results, in particular whether and how
* exponential notation should be used.
*
* @see #ENGINEERING
* @see #PLAIN
* @see #SCIENTIFIC
* @serial
*/
internal var form:int; // values for this must fit in a byte
/**
* Controls whether lost digits checking is enabled for an
* operation.
* Set to <code>true</code> to enable checking, or
* to <code>false</code> to disable checking.
* <p>
* When enabled, the {@link BigDecimal} operator methods check
* the precision of their operand or operands, and throw an
* <code>ArithmeticException</code> if an operand is more precise
* than the digits setting (that is, digits would be lost).
* When disabled, operands are rounded to the specified digits.
*
* @serial
*/
internal var lostDigits:Boolean;
/**
* The rounding algorithm to be used for an operation.
* <p>
* The {@link BigDecimal} operator methods use this value to
* determine the algorithm to be used when non-zero digits have to
* be discarded in order to reduce the precision of a result.
* The value must be one of the public constants whose name starts
* with <code>ROUND_</code>.
*
* @see #ROUND_CEILING
* @see #ROUND_DOWN
* @see #ROUND_FLOOR
* @see #ROUND_HALF_DOWN
* @see #ROUND_HALF_EVEN
* @see #ROUND_HALF_UP
* @see #ROUND_UNNECESSARY
* @see #ROUND_UP
* @serial
*/
internal var roundingMode:int;
/* properties private constant */
// default settings
private static const DEFAULT_FORM:int = NOTATION_SCIENTIFIC;
private static const DEFAULT_DIGITS:int = 9;
private static const DEFAULT_LOSTDIGITS:Boolean = false;
private static const DEFAULT_ROUNDINGMODE:int = ROUND_HALF_UP;
/* properties private constant */
private static const MIN_DIGITS:int = 0; // smallest value for DIGITS.
private static const MAX_DIGITS:int = 999999999; // largest value for DIGITS. If increased,
// the BigDecimal class may need update.
// list of valid rounding mode values, most common two first
private static const ROUNDS:Array = [ROUND_HALF_UP,ROUND_UNNECESSARY,ROUND_CEILING,ROUND_DOWN,ROUND_FLOOR,ROUND_HALF_DOWN,ROUND_HALF_EVEN,ROUND_UP];
private static const ROUNDWORDS:Array = ["ROUND_HALF_UP","ROUND_UNNECESSARY","ROUND_CEILING","ROUND_DOWN","ROUND_FLOOR","ROUND_HALF_DOWN","ROUND_HALF_EVEN","ROUND_UP"]; // matching names of the ROUNDS values
/* properties public constant */
/**
* A <code>MathContext</code> object initialized to the default
* settings for general-purpose arithmetic. That is,
* <code>digits=9 form=SCIENTIFIC lostDigits=false
* roundingMode=ROUND_HALF_UP</code>.
*
* @see #SCIENTIFIC
* @see #ROUND_HALF_UP
* @stable ICU 2.0
*/
public static const DEFAULT:MathContext = new MathContext(DEFAULT_DIGITS,DEFAULT_FORM,DEFAULT_LOSTDIGITS,DEFAULT_ROUNDINGMODE);
public static const PLAIN:MathContext = new MathContext(0,NOTATION_PLAIN); // context for plain unlimited math
/* ----- Constructors ----- */
/**
* Constructs a new <code>MathContext</code> with a specified
* precision, form, lostDigits, and roundingMode setting.
*
* An <code>IllegalArgumentException</code> is thrown if the
* <code>setdigits</code> parameter is out of range
* (<0 or >999999999), or if the value given for the
* <code>setform</code> or <code>setroundingmode</code> parameters is
* not one of the appropriate constants.
*
* @param setdigits The <code>int</code> digits setting
* for this <code>MathContext</code>.
* @param setform The <code>int</code> form setting
* for this <code>MathContext</code>.
* @param setlostdigits The <code>boolean</code> lostDigits
* setting for this <code>MathContext</code>.
* @param setroundingmode The <code>int</code> roundingMode setting
* for this <code>MathContext</code>.
* @throws IllegalArgumentException parameter out of range.
* @stable ICU 2.0
*/
public function MathContext(setdigits:int, setform:int = DEFAULT_FORM, setlostdigits:Boolean = DEFAULT_LOSTDIGITS, setroundingmode:int = DEFAULT_ROUNDINGMODE) {
// set values, after checking
if (setdigits!=DEFAULT_DIGITS) {
if (setdigits<MIN_DIGITS) {
throw new Error("Digits too small:"+" "+setdigits);
}
if (setdigits>MAX_DIGITS) {
throw new Error("Digits too large:"+" "+setdigits);
}
}
{/*select*/
if (setform==NOTATION_SCIENTIFIC) {
// [most common]
} else if (setform==NOTATION_ENGINEERING) {
} else if (setform==NOTATION_PLAIN) {
} else {
throw new Error("Bad form value:"+" "+setform);
}
}
if ((!(isValidRound(setroundingmode)))) {
throw new Error("Bad roundingMode value:"+" "+setroundingmode);
}
digits=setdigits;
form=setform;
lostDigits=setlostdigits; // [no bad value possible]
roundingMode=setroundingmode;
}
/**
* Returns the digits setting.
* This value is always non-negative.
*
* @return an <code>int</code> which is the value of the digits
* setting
* @stable ICU 2.0
*/
public function getDigits():int {
return digits;
}
/**
* Returns the form setting.
* This will be one of
* {@link #ENGINEERING},
* {@link #PLAIN}, or
* {@link #SCIENTIFIC}.
*
* @return an <code>int</code> which is the value of the form setting
* @stable ICU 2.0
*/
public function getForm():int {
return form;
}
/**
* Returns the lostDigits setting.
* This will be either <code>true</code> (enabled) or
* <code>false</code> (disabled).
*
* @return a <code>boolean</code> which is the value of the lostDigits
* setting
* @stable ICU 2.0
*/
public function getLostDigits():Boolean {
return lostDigits;
}
/**
* Returns the roundingMode setting.
* This will be one of
* {@link #ROUND_CEILING},
* {@link #ROUND_DOWN},
* {@link #ROUND_FLOOR},
* {@link #ROUND_HALF_DOWN},
* {@link #ROUND_HALF_EVEN},
* {@link #ROUND_HALF_UP},
* {@link #ROUND_UNNECESSARY}, or
* {@link #ROUND_UP}.
*
* @return an <code>int</code> which is the value of the roundingMode
* setting
* @stable ICU 2.0
*/
public function getRoundingMode():int {
return roundingMode;
}
/** Returns the <code>MathContext</code> as a readable string.
* The <code>String</code> returned represents the settings of the
* <code>MathContext</code> object as four blank-delimited words
* separated by a single blank and with no leading or trailing blanks,
* as follows:
* <ol>
* <li>
* <code>digits=</code>, immediately followed by
* the value of the digits setting as a numeric word.
* <li>
* <code>form=</code>, immediately followed by
* the value of the form setting as an uppercase word
* (one of <code>SCIENTIFIC</code>, <code>PLAIN</code>, or
* <code>ENGINEERING</code>).
* <li>
* <code>lostDigits=</code>, immediately followed by
* the value of the lostDigits setting
* (<code>1</code> if enabled, <code>0</code> if disabled).
* <li>
* <code>roundingMode=</code>, immediately followed by
* the value of the roundingMode setting as a word.
* This word will be the same as the name of the corresponding public
* constant.
* </ol>
* <p>
* For example:
* <br><code>
* digits=9 form=SCIENTIFIC lostDigits=0 roundingMode=ROUND_HALF_UP
* </code>
* <p>
* Additional words may be appended to the result of
* <code>toString</code> in the future if more properties are added
* to the class.
*
* @return a <code>String</code> representing the context settings.
* @stable ICU 2.0
*/
public function toString():String {
var formstr:String = null;
var r:int = 0;
var roundword:String = null;
{/*select*/
if (form==NOTATION_SCIENTIFIC) {
formstr="SCIENTIFIC";
} else if (form==NOTATION_ENGINEERING) {
formstr="ENGINEERING";
} else{
formstr="PLAIN";/* form=PLAIN */
}
}
{
var one:int = ROUNDS.length;
r = 0;
for(; one > 0; one--, r++){
if (roundingMode==ROUNDS[r]) {
roundword=ROUNDWORDS[r];
break;
}
}
}/*r*/
return "digits="+digits+" "+"form="+formstr+" "+"lostDigits="+(lostDigits?"1":"0")+" "+"roundingMode="+roundword;
}
/* <sgml> Test whether round is valid. </sgml> */
// This could be made shared for use by BigDecimal for setScale.
private static function isValidRound(testround:int):Boolean {
var r:int = 0;
{
var two:int = ROUNDS.length;
r=0;
for(; two > 0; two--,r++){
if (testround==ROUNDS[r]) {
return true;
}
}
}/*r*/
return false;
}
}
}