dec_number/
dec_context.rs

1/// Rounding modes.
2#[derive(Debug, Copy, Clone, PartialEq)]
3#[repr(u8)]
4pub enum Rounding {
5  /// Round towards `+infinity`.
6  DecRoundCeiling = 0,
7  /// Round away from 0.
8  DecRoundUp = 1,
9  /// 0.5 rounds up.
10  DecRoundHalfUp = 2,
11  /// 0.5 rounds to nearest even.
12  DecRoundHalfEven = 3,
13  /// 0.5 rounds down.
14  DecRoundHalfDown = 4,
15  /// Round towards 0 (truncate).
16  DecRoundDown = 5,
17  /// Round towards `-infinity`.
18  DecRoundFloor = 6,
19  /// Round for re-round.
20  DecRound05up = 7,
21}
22
23/// Default rounding mode is [Rounding::DecRoundHalfEven].
24pub const DEC_ROUND_DEFAULT: Rounding = Rounding::DecRoundHalfEven;
25
26/// Context for operations.
27pub struct DecContext {
28  /// Working precision.
29  pub digits: i32,
30  /// Maximum positive exponent.
31  pub emax: i32,
32  /// Minimum negative exponent.
33  pub emin: i32,
34  /// Rounding mode.
35  pub round: Rounding,
36  /// Trap-enabler flags.
37  pub traps: u32,
38  /// Status flags.
39  pub status: u32,
40  /// Flag: apply IEEE exponent clamp.
41  pub clamp: u8,
42  /// Flag: special-values allowed.
43  #[cfg(feature = "dec-subset")]
44  pub extended: u8,
45}
46
47// Maxima and Minima for context settings.
48
49/// Max digits.
50pub const DEC_MAX_DIGITS: i32 = 999999999;
51/// Min digits.
52pub const DEC_MIN_DIGITS: i32 = 1;
53/// Max emax.
54pub const DEC_MAX_EMAX: i32 = 999999999;
55/// Min emax.
56pub const DEC_MIN_EMAX: i32 = 0;
57/// Max emin.
58pub const DEC_MAX_EMIN: i32 = 0;
59/// Min emin.
60pub const DEC_MIN_EMIN: i32 = -999999999;
61/// Max emax, etc., for mathematical functions.
62pub const DEC_MAX_MATH: i32 = 999999;
63
64/// Classifications for decimal numbers, aligned with IEEE 754
65/// (note that 'normal' and 'subnormal' are meaningful only with
66/// a [DecContext] or a fixed size format.
67pub enum DecClass {
68  DecClassSNaN = 0,
69  DecClassQNaN = 1,
70  DecClassNegInf = 2,
71  DecClassNegNormal = 3,
72  DecClassNegSubnormal = 4,
73  DecClassNegZero = 5,
74  DecClassPosZero = 6,
75  DecClassPosSubnormal = 7,
76  DecClassPosNormal = 8,
77  DecClassPosInf = 9,
78}
79
80// Strings for the DecClasses.
81
82/// String for [DecClass::DecClassSNaN].
83pub const DEC_CLASS_STRING_SN: &str = "sNaN";
84/// String for [DecClass::DecClassQNaN].
85pub const DEC_CLASS_STRING_QN: &str = "NaN";
86/// String for [DecClass::DecClassNegInf].
87pub const DEC_CLASS_STRING_NI: &str = "-Infinity";
88/// String for [DecClass::DecClassNegNormal].
89pub const DEC_CLASS_STRING_NN: &str = "-Normal";
90/// String for [DecClass::DecClassNegSubnormal].
91pub const DEC_CLASS_STRING_NS: &str = "-Subnormal";
92/// String for [DecClass::DecClassNegZero].
93pub const DEC_CLASS_STRING_NZ: &str = "-Zero";
94/// String for [DecClass::DecClassPosZero].
95pub const DEC_CLASS_STRING_PZ: &str = "+Zero";
96/// String for [DecClass::DecClassPosSubnormal].
97pub const DEC_CLASS_STRING_PS: &str = "+Subnormal";
98/// String for [DecClass::DecClassPosNormal].
99pub const DEC_CLASS_STRING_PN: &str = "+Normal";
100/// String for [DecClass::DecClassPosInf].
101pub const DEC_CLASS_STRING_PI: &str = "+Infinity";
102/// String for invalid value.
103pub const DEC_CLASS_STRING_UN: &str = "Invalid";
104
105// Trap-enabler and Status flags (exceptional conditions), and their names.
106// The top byte is reserved for internal use.
107
108// Extended flags.
109#[cfg(feature = "dec-ext-flag")]
110pub const DEC_CONVERSION_SYNTAX: u32 = 0x00000001;
111#[cfg(feature = "dec-ext-flag")]
112pub const DEC_DIVISION_BY_ZERO: u32 = 0x00000002;
113#[cfg(feature = "dec-ext-flag")]
114pub const DEC_DIVISION_IMPOSSIBLE: u32 = 0x00000004;
115#[cfg(feature = "dec-ext-flag")]
116pub const DEC_DIVISION_UNDEFINED: u32 = 0x00000008;
117#[cfg(feature = "dec-ext-flag")]
118pub const DEC_INSUFFICIENT_STORAGE: u32 = 0x00000010; /* [when malloc fails]  */
119#[cfg(feature = "dec-ext-flag")]
120pub const DEC_INEXACT: u32 = 0x00000020;
121#[cfg(feature = "dec-ext-flag")]
122pub const DEC_INVALID_CONTEXT: u32 = 0x00000040;
123#[cfg(feature = "dec-ext-flag")]
124pub const DEC_INVALID_OPERATION: u32 = 0x00000080;
125#[cfg(all(feature = "dec-ext-flag", feature = "dec-subset"))]
126pub const DEC_LOST_DIGITS: u32 = 0x00000100;
127#[cfg(feature = "dec-ext-flag")]
128pub const DEC_OVERFLOW: u32 = 0x00000200;
129#[cfg(feature = "dec-ext-flag")]
130pub const DEC_CLAMPED: u32 = 0x00000400;
131#[cfg(feature = "dec-ext-flag")]
132pub const DEC_ROUNDED: u32 = 0x00000800;
133#[cfg(feature = "dec-ext-flag")]
134pub const DEC_SUBNORMAL: u32 = 0x00001000;
135#[cfg(feature = "dec-ext-flag")]
136pub const DEC_UNDERFLOW: u32 = 0x00002000;
137
138// IEEE flags only.
139#[cfg(not(feature = "dec-ext-flag"))]
140pub const DEC_CONVERSION_SYNTAX: u32 = 0x00000010;
141#[cfg(not(feature = "dec-ext-flag"))]
142pub const DEC_DIVISION_BY_ZERO: u32 = 0x00000002;
143#[cfg(not(feature = "dec-ext-flag"))]
144pub const DEC_DIVISION_IMPOSSIBLE: u32 = 0x00000010;
145#[cfg(not(feature = "dec-ext-flag"))]
146pub const DEC_DIVISION_UNDEFINED: u32 = 0x00000010;
147#[cfg(not(feature = "dec-ext-flag"))]
148pub const DEC_INSUFFICIENT_STORAGE: u32 = 0x00000010; /* [when malloc fails]  */
149#[cfg(not(feature = "dec-ext-flag"))]
150pub const DEC_INEXACT: u32 = 0x00000001;
151#[cfg(not(feature = "dec-ext-flag"))]
152pub const DEC_INVALID_CONTEXT: u32 = 0x00000010;
153#[cfg(not(feature = "dec-ext-flag"))]
154pub const DEC_INVALID_OPERATION: u32 = 0x00000010;
155#[cfg(all(not(feature = "dec-ext-flag"), feature = "dec-subset"))]
156pub const DEC_LOST_DIGITS: u32 = 0x00000000;
157#[cfg(not(feature = "dec-ext-flag"))]
158pub const DEC_OVERFLOW: u32 = 0x00000008;
159#[cfg(not(feature = "dec-ext-flag"))]
160pub const DEC_CLAMPED: u32 = 0x00000000;
161#[cfg(not(feature = "dec-ext-flag"))]
162pub const DEC_ROUNDED: u32 = 0x00000000;
163#[cfg(not(feature = "dec-ext-flag"))]
164pub const DEC_SUBNORMAL: u32 = 0x00000000;
165#[cfg(not(feature = "dec-ext-flag"))]
166pub const DEC_UNDERFLOW: u32 = 0x00000004;
167
168// IEEE 754 groupings for the flags.
169// (DEC_Clamped, DEC_Lost_digits, DEC_Rounded, and DEC_Subnormal are not in IEEE 754)
170
171pub const DEC_IEEE_754_DIVISION_BY_ZERO: u32 = DEC_DIVISION_BY_ZERO;
172#[cfg(feature = "dec-subset")]
173pub const DEC_IEEE_754_INEXACT: u32 = DEC_INEXACT | DEC_LOST_DIGITS;
174#[cfg(not(feature = "dec-subset"))]
175pub const DEC_IEEE_754_INEXACT: u32 = DEC_INEXACT;
176
177pub const DEC_IEEE_754_INVALID_OPERATION: u32 = DEC_CONVERSION_SYNTAX
178  | DEC_DIVISION_IMPOSSIBLE
179  | DEC_DIVISION_UNDEFINED
180  | DEC_INSUFFICIENT_STORAGE
181  | DEC_INVALID_CONTEXT
182  | DEC_INVALID_OPERATION;
183pub const DEC_IEEE_754_OVERFLOW: u32 = DEC_OVERFLOW;
184pub const DEC_IEEE_754_UNDERFLOW: u32 = DEC_UNDERFLOW;
185
186/// Flags which are normally errors (result is qNaN, infinite, or 0).
187pub const DEC_ERRORS: u32 = DEC_IEEE_754_DIVISION_BY_ZERO
188  | DEC_IEEE_754_INVALID_OPERATION
189  | DEC_IEEE_754_OVERFLOW
190  | DEC_IEEE_754_UNDERFLOW;
191
192/// Flags which cause a result to become qNaN.
193pub const DEC_NANS: u32 = DEC_IEEE_754_INVALID_OPERATION;
194
195/// Flags which are normally for information only (finite results).
196#[cfg(feature = "dec-subset")]
197pub const DEC_INFORMATION: u32 =
198  DEC_CLAMPED | DEC_ROUNDED | DEC_INEXACT | DEC_LOST_DIGITS;
199/// Flags which are normally for information only (finite results).
200#[cfg(not(feature = "dec-subset"))]
201pub const DEC_INFORMATION: u32 = DEC_CLAMPED | DEC_ROUNDED | DEC_INEXACT;
202
203// IEEE 854 names (for compatibility with older decNumber versions).
204
205pub const DEC_IEEE_854_DIVISION_BY_ZERO: u32 = DEC_IEEE_754_DIVISION_BY_ZERO;
206pub const DEC_IEEE_854_INEXACT: u32 = DEC_IEEE_754_INEXACT;
207pub const DEC_IEEE_854_INVALID_OPERATION: u32 = DEC_IEEE_754_INVALID_OPERATION;
208pub const DEC_IEEE_854_OVERFLOW: u32 = DEC_IEEE_754_OVERFLOW;
209pub const DEC_IEEE_854_UNDERFLOW: u32 = DEC_IEEE_754_UNDERFLOW;
210
211// Initialization descriptors, used by dec_context_default function.
212
213/// ANSI X3-274 defaults.
214pub const DEC_INIT_BASE: i32 = 0;
215/// IEEE 754 defaults, 32-bit.
216pub const DEC_INIT_DECIMAL32: i32 = 32;
217/// IEEE 754 defaults, 64-bit.
218pub const DEC_INIT_DECIMAL64: i32 = 64;
219/// IEEE 754 defaults, 128-bit.
220pub const DEC_INIT_DECIMAL128: i32 = 128;
221
222// Synonyms.
223
224/// Synonym for [DEC_INIT_DECIMAL32].
225pub const DEC_INIT_DEC_SINGLE: i32 = DEC_INIT_DECIMAL32;
226/// Synonym for [DEC_INIT_DECIMAL64].
227pub const DEC_INIT_DEC_DOUBLE: i32 = DEC_INIT_DECIMAL64;
228/// Synonym for [DEC_INIT_DECIMAL128].
229pub const DEC_INIT_DEC_QUAD: i32 = DEC_INIT_DECIMAL128;
230
231impl Default for DecContext {
232  fn default() -> Self {
233    Self {
234      digits: 9,                       // 9 digits
235      emax: DEC_MAX_EMAX,              // 9-digit exponents
236      emin: DEC_MIN_EMIN,              // .. balanced
237      round: Rounding::DecRoundHalfUp, // 0.5 rises
238      traps: DEC_ERRORS,               // all but informational
239      status: 0,                       // cleared
240      clamp: 0,                        // no clamping
241      #[cfg(feature = "dec-subset")]
242      extended: 0, // cleared
243    }
244  }
245}
246
247impl DecContext {
248  /// Clear bits in current status.
249  ///
250  /// `dec_context_clear_status` - clear bits in current status.
251  ///
252  /// `context` is the context structure to be queried.
253  ///
254  /// `mask` indicates the bits to be cleared (the status bit that corresponds
255  /// to each 1 bit in the mask is cleared).
256  ///
257  /// Returns updated context.
258  ///
259  /// No error is possible.
260  ///
261  pub fn dec_context_clear_status(
262    context: &mut DecContext,
263    mask: u32,
264  ) -> &DecContext {
265    context.status &= !mask;
266    context
267  }
268
269  /// Initializes a context structure.
270  ///
271  /// `dec_context_default` - initialize a context structure.
272  ///
273  /// `context` is the structure to be initialized.
274  ///
275  /// `kind` selects the required set of default values, one of:
276  ///  - DEC_INIT_BASE       - select ANSI X3-274 defaults
277  ///  - DEC_INIT_DECIMAL32  - select IEEE 754 defaults, 32-bit
278  ///  - DEC_INIT_DECIMAL64  - select IEEE 754 defaults, 64-bit
279  ///  - DEC_INIT_DECIMAL128 - select IEEE 754 defaults, 128-bit
280  ///
281  ///  For any other value a valid context is returned, but with
282  ///  Invalid_operation set in the status field.
283  ///
284  ///  Returns a context structure with the appropriate initial values.
285  ///
286  pub fn dec_context_default(
287    context: &mut DecContext,
288    kind: i32,
289  ) -> &DecContext {
290    match kind {
291      DEC_INIT_BASE => {
292        // Use defaults, when the context is initialized, it has already
293        // default values set, see implementation of the Default for DecContext.
294        // So there is nothing to do in this case.
295      }
296      DEC_INIT_DECIMAL32 => {
297        context.digits = 7; // digits
298        context.emax = 96; // Emax
299        context.emin = -95; // Emin
300        context.round = Rounding::DecRoundHalfEven; // 0.5 to nearest even
301        context.traps = 0; // no traps set
302        context.clamp = 1; // clamp exponents
303        #[cfg(feature = "dec-subset")]
304        {
305          context.extended = 1; // set
306        }
307      }
308      DEC_INIT_DECIMAL64 => {
309        context.digits = 16; // digits
310        context.emax = 384; // Emax
311        context.emin = -383; // Emin
312        context.round = Rounding::DecRoundHalfEven; // 0.5 to nearest even
313        context.traps = 0; // no traps set
314        context.clamp = 1; // clamp exponents
315        #[cfg(feature = "dec-subset")]
316        {
317          context.extended = 1; // set
318        }
319      }
320      DEC_INIT_DECIMAL128 => {
321        context.digits = 34; // digits
322        context.emax = 6144; // Emax
323        context.emin = -6143; // Emin
324        context.round = Rounding::DecRoundHalfEven; // 0.5 to nearest even
325        context.traps = 0; // no traps set
326        context.clamp = 1; // clamp exponents
327        #[cfg(feature = "dec-subset")]
328        {
329          context.extended = 1; // set
330        }
331      }
332      _ => {
333        // invalid kind, use defaults, and trap
334        Self::dec_context_set_status(context, DEC_INVALID_OPERATION);
335      }
336    }
337    context
338  }
339
340  /// Returns current rounding mode.
341  ///
342  /// `dec_context_get_rounding` - return current rounding mode.
343  ///
344  /// `context` is the context structure to be queried.
345  ///
346  /// Returns the rounding mode.
347  ///
348  /// No error is possible.
349  ///
350  pub fn dec_context_get_rounding(context: &DecContext) -> Rounding {
351    context.round
352  }
353
354  /// Sets status and raises trap if appropriate.
355  ///
356  /// `dec_context_set_status` - set status and raise trap if appropriate.
357  ///
358  /// `context` is the context structure to be updated.
359  ///
360  /// `status`  is the error code.
361  ///
362  /// Returns the context structure with updated status.
363  ///
364  /// Control may never return from this routine, if there is a signal handler and it panics.
365  ///
366  pub fn dec_context_set_status(
367    context: &mut DecContext,
368    status: u32,
369  ) -> &DecContext {
370    context.status |= status;
371    if (status & context.traps) != 0 {
372      panic!("SIGFPE");
373    }
374    context
375  }
376}
377
378#[cfg(test)]
379mod tests {
380  use super::*;
381
382  #[test]
383  fn test_rounding_values() {
384    assert_eq!(0, Rounding::DecRoundCeiling as u8);
385    assert_eq!(1, Rounding::DecRoundUp as u8);
386    assert_eq!(2, Rounding::DecRoundHalfUp as u8);
387    assert_eq!(3, Rounding::DecRoundHalfEven as u8);
388    assert_eq!(4, Rounding::DecRoundHalfDown as u8);
389    assert_eq!(5, Rounding::DecRoundDown as u8);
390    assert_eq!(6, Rounding::DecRoundFloor as u8);
391    assert_eq!(7, Rounding::DecRound05up as u8);
392  }
393
394  #[test]
395  fn test_default_rounding() {
396    assert_eq!(DEC_ROUND_DEFAULT, Rounding::DecRoundHalfEven);
397  }
398
399  #[test]
400  fn test_dec_context_clear_status() {
401    let mut context = DecContext::default();
402    assert_eq!(0, context.status);
403    context.status = !0;
404    assert_eq!(0xFFFFFFFF, context.status);
405    DecContext::dec_context_clear_status(&mut context, 0xF);
406    assert_eq!(0xFFFFFFF0, context.status);
407    DecContext::dec_context_clear_status(&mut context, 0xF0000000);
408    assert_eq!(0x0FFFFFF0, context.status);
409    DecContext::dec_context_clear_status(&mut context, 0x1000);
410    assert_eq!(0x0FFFEFF0, context.status);
411  }
412
413  #[test]
414  fn test_dec_context_default_base() {
415    let mut context = DecContext::default();
416    DecContext::dec_context_default(&mut context, DEC_INIT_BASE);
417    assert_eq!(9, context.digits);
418    assert_eq!(DEC_MAX_EMAX, context.emax);
419    assert_eq!(DEC_MIN_EMIN, context.emin);
420    assert_eq!(Rounding::DecRoundHalfUp, context.round);
421    assert_eq!(DEC_ERRORS, context.traps);
422    assert_eq!(0, context.status);
423    assert_eq!(0, context.clamp);
424    #[cfg(feature = "dec-subset")]
425    assert_eq!(0, context.extended);
426  }
427
428  #[test]
429  fn test_dec_context_default_decimal_32() {
430    let mut context = DecContext::default();
431    DecContext::dec_context_default(&mut context, DEC_INIT_DECIMAL32);
432    assert_eq!(7, context.digits);
433    assert_eq!(96, context.emax);
434    assert_eq!(-95, context.emin);
435    assert_eq!(Rounding::DecRoundHalfEven, context.round);
436    assert_eq!(0, context.traps);
437    assert_eq!(0, context.status);
438    assert_eq!(1, context.clamp);
439    #[cfg(feature = "dec-subset")]
440    assert_eq!(1, context.extended);
441  }
442
443  #[test]
444  fn test_dec_context_default_decimal_62() {
445    let mut context = DecContext::default();
446    DecContext::dec_context_default(&mut context, DEC_INIT_DECIMAL64);
447    assert_eq!(16, context.digits);
448    assert_eq!(384, context.emax);
449    assert_eq!(-383, context.emin);
450    assert_eq!(Rounding::DecRoundHalfEven, context.round);
451    assert_eq!(0, context.traps);
452    assert_eq!(0, context.status);
453    assert_eq!(1, context.clamp);
454    #[cfg(feature = "dec-subset")]
455    assert_eq!(1, context.extended);
456  }
457
458  #[test]
459  fn test_dec_context_default_decimal_128() {
460    let mut context = DecContext::default();
461    DecContext::dec_context_default(&mut context, DEC_INIT_DECIMAL128);
462    assert_eq!(34, context.digits);
463    assert_eq!(6144, context.emax);
464    assert_eq!(-6143, context.emin);
465    assert_eq!(Rounding::DecRoundHalfEven, context.round);
466    assert_eq!(0, context.traps);
467    assert_eq!(0, context.status);
468    assert_eq!(1, context.clamp);
469    #[cfg(feature = "dec-subset")]
470    assert_eq!(1, context.extended);
471  }
472
473  #[test]
474  #[should_panic]
475  fn test_dec_context_default_decimal_other() {
476    let mut context = DecContext::default();
477    DecContext::dec_context_default(&mut context, 37);
478  }
479
480  #[test]
481  fn test_dec_context_get_rounding() {
482    let mut context = DecContext::default();
483    assert_eq!(
484      Rounding::DecRoundHalfUp,
485      DecContext::dec_context_get_rounding(&context)
486    );
487    DecContext::dec_context_default(&mut context, DEC_INIT_DECIMAL32);
488    assert_eq!(
489      Rounding::DecRoundHalfEven,
490      DecContext::dec_context_get_rounding(&context)
491    );
492  }
493}