1#[derive(Debug, Copy, Clone, PartialEq)]
3#[repr(u8)]
4pub enum Rounding {
5 DecRoundCeiling = 0,
7 DecRoundUp = 1,
9 DecRoundHalfUp = 2,
11 DecRoundHalfEven = 3,
13 DecRoundHalfDown = 4,
15 DecRoundDown = 5,
17 DecRoundFloor = 6,
19 DecRound05up = 7,
21}
22
23pub const DEC_ROUND_DEFAULT: Rounding = Rounding::DecRoundHalfEven;
25
26pub struct DecContext {
28 pub digits: i32,
30 pub emax: i32,
32 pub emin: i32,
34 pub round: Rounding,
36 pub traps: u32,
38 pub status: u32,
40 pub clamp: u8,
42 #[cfg(feature = "dec-subset")]
44 pub extended: u8,
45}
46
47pub const DEC_MAX_DIGITS: i32 = 999999999;
51pub const DEC_MIN_DIGITS: i32 = 1;
53pub const DEC_MAX_EMAX: i32 = 999999999;
55pub const DEC_MIN_EMAX: i32 = 0;
57pub const DEC_MAX_EMIN: i32 = 0;
59pub const DEC_MIN_EMIN: i32 = -999999999;
61pub const DEC_MAX_MATH: i32 = 999999;
63
64pub 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
80pub const DEC_CLASS_STRING_SN: &str = "sNaN";
84pub const DEC_CLASS_STRING_QN: &str = "NaN";
86pub const DEC_CLASS_STRING_NI: &str = "-Infinity";
88pub const DEC_CLASS_STRING_NN: &str = "-Normal";
90pub const DEC_CLASS_STRING_NS: &str = "-Subnormal";
92pub const DEC_CLASS_STRING_NZ: &str = "-Zero";
94pub const DEC_CLASS_STRING_PZ: &str = "+Zero";
96pub const DEC_CLASS_STRING_PS: &str = "+Subnormal";
98pub const DEC_CLASS_STRING_PN: &str = "+Normal";
100pub const DEC_CLASS_STRING_PI: &str = "+Infinity";
102pub const DEC_CLASS_STRING_UN: &str = "Invalid";
104
105#[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; #[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#[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; #[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
168pub 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
186pub 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
192pub const DEC_NANS: u32 = DEC_IEEE_754_INVALID_OPERATION;
194
195#[cfg(feature = "dec-subset")]
197pub const DEC_INFORMATION: u32 =
198 DEC_CLAMPED | DEC_ROUNDED | DEC_INEXACT | DEC_LOST_DIGITS;
199#[cfg(not(feature = "dec-subset"))]
201pub const DEC_INFORMATION: u32 = DEC_CLAMPED | DEC_ROUNDED | DEC_INEXACT;
202
203pub 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
211pub const DEC_INIT_BASE: i32 = 0;
215pub const DEC_INIT_DECIMAL32: i32 = 32;
217pub const DEC_INIT_DECIMAL64: i32 = 64;
219pub const DEC_INIT_DECIMAL128: i32 = 128;
221
222pub const DEC_INIT_DEC_SINGLE: i32 = DEC_INIT_DECIMAL32;
226pub const DEC_INIT_DEC_DOUBLE: i32 = DEC_INIT_DECIMAL64;
228pub const DEC_INIT_DEC_QUAD: i32 = DEC_INIT_DECIMAL128;
230
231impl Default for DecContext {
232 fn default() -> Self {
233 Self {
234 digits: 9, emax: DEC_MAX_EMAX, emin: DEC_MIN_EMIN, round: Rounding::DecRoundHalfUp, traps: DEC_ERRORS, status: 0, clamp: 0, #[cfg(feature = "dec-subset")]
242 extended: 0, }
244 }
245}
246
247impl DecContext {
248 pub fn dec_context_clear_status(
262 context: &mut DecContext,
263 mask: u32,
264 ) -> &DecContext {
265 context.status &= !mask;
266 context
267 }
268
269 pub fn dec_context_default(
287 context: &mut DecContext,
288 kind: i32,
289 ) -> &DecContext {
290 match kind {
291 DEC_INIT_BASE => {
292 }
296 DEC_INIT_DECIMAL32 => {
297 context.digits = 7; context.emax = 96; context.emin = -95; context.round = Rounding::DecRoundHalfEven; context.traps = 0; context.clamp = 1; #[cfg(feature = "dec-subset")]
304 {
305 context.extended = 1; }
307 }
308 DEC_INIT_DECIMAL64 => {
309 context.digits = 16; context.emax = 384; context.emin = -383; context.round = Rounding::DecRoundHalfEven; context.traps = 0; context.clamp = 1; #[cfg(feature = "dec-subset")]
316 {
317 context.extended = 1; }
319 }
320 DEC_INIT_DECIMAL128 => {
321 context.digits = 34; context.emax = 6144; context.emin = -6143; context.round = Rounding::DecRoundHalfEven; context.traps = 0; context.clamp = 1; #[cfg(feature = "dec-subset")]
328 {
329 context.extended = 1; }
331 }
332 _ => {
333 Self::dec_context_set_status(context, DEC_INVALID_OPERATION);
335 }
336 }
337 context
338 }
339
340 pub fn dec_context_get_rounding(context: &DecContext) -> Rounding {
351 context.round
352 }
353
354 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}