Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_units/tests/rounding.rs

4.9 KiB, 1 run

created by r1870400018:17549, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1//! External-oracle tests for significant figure rounding.
2//!
3//! Every expected value here is worked out by hand from the decimal digits and
4//! not read off the implementation. Write the magnitude as `d.ddd x 10^k`, keep
5//! the tracked number of digits of the significand, and round the last of them
6//! half away from zero. A sign plays no part in that: the digits kept for
7//! -0.475 are the digits kept for 0.475.
8
9use oxedyne_fe2o3_units::{
10 dimension::Dimension,
11 quantity::Quantity,
12};
13
14use oxedyne_fe2o3_core::prelude::*;
15
16#[test]
17fn test_rounded_above_one_01() -> Outcome<()> {
18 // 1234 m is 1.234 x 10^3 m; three figures keep 1.23, so 1230 m.
19 assert_eq!(res!(Quantity::metres(1234.0, 3)).rounded(), 1230.0);
20 // 1236 m rounds the third figure up, so 1240 m.
21 assert_eq!(res!(Quantity::metres(1236.0, 3)).rounded(), 1240.0);
22 // 98765 s is 9.8765 x 10^4 s; two figures keep 9.9, so 99000 s.
23 assert_eq!(res!(Quantity::seconds(98765.0, 2)).rounded(), 99000.0);
24 // 9.99 kg to two figures carries into a new decade: 10 kg.
25 assert_eq!(res!(Quantity::kilograms(9.99, 2)).rounded(), 10.0);
26 Ok(())
27}
28
29#[test]
30fn test_rounded_negative_above_one_01() -> Outcome<()> {
31 assert_eq!(res!(Quantity::metres(-1234.0, 3)).rounded(), -1230.0);
32 assert_eq!(res!(Quantity::metres(-1236.0, 3)).rounded(), -1240.0);
33 assert_eq!(res!(Quantity::seconds(-98765.0, 2)).rounded(), -99000.0);
34 assert_eq!(res!(Quantity::kilograms(-9.99, 2)).rounded(), -10.0);
35 Ok(())
36}
37
38#[test]
39fn test_rounded_below_one_01() -> Outcome<()> {
40 // 0.4749 is 4.749 x 10^-1; two figures keep 4.7.
41 assert_eq!(res!(Quantity::dimensionless(0.4749, 2)).rounded(), 0.47);
42 // 0.4751 rounds the second figure up.
43 assert_eq!(res!(Quantity::dimensionless(0.4751, 2)).rounded(), 0.48);
44 // 0.05512 is 5.512 x 10^-2; two figures keep 5.5.
45 assert_eq!(res!(Quantity::dimensionless(0.05512, 2)).rounded(), 0.055);
46 // 0.9996 carries through the decade to 1.00.
47 assert_eq!(res!(Quantity::dimensionless(0.9996, 3)).rounded(), 1.0);
48 Ok(())
49}
50
51/// A slope is dimensionless and usually smaller than one, which is the case
52/// that went wrong: a gradient of -0.475 read to two figures is -0.48, and one
53/// of -0.5496 is -0.55.
54#[test]
55fn test_rounded_negative_below_one_01() -> Outcome<()> {
56 assert_eq!(res!(Quantity::dimensionless(-0.475, 2)).rounded(), -0.48);
57 assert_eq!(res!(Quantity::dimensionless(-0.5496, 2)).rounded(), -0.55);
58 assert_eq!(res!(Quantity::dimensionless(-0.055, 2)).rounded(), -0.055);
59 assert_eq!(res!(Quantity::dimensionless(-0.4749, 2)).rounded(), -0.47);
60 assert_eq!(res!(Quantity::dimensionless(-0.0999, 2)).rounded(), -0.1);
61 Ok(())
62}
63
64/// A gradient formed by dividing a rise by a run keeps the coarser figure
65/// count and rounds by the same rule as a value entered directly.
66#[test]
67fn test_rounded_slope_from_division_01() -> Outcome<()> {
68 // -0.95 m over 2.0 m is -0.475, dimensionless, to two figures: -0.48.
69 let rise = res!(Quantity::metres(-0.95, 2));
70 let run = res!(Quantity::metres(2.0, 3));
71 let slope = rise.div(&run);
72 assert_eq!(slope.sf(), 2);
73 assert!(slope.dim().is_dimensionless());
74 assert_eq!(slope.rounded(), -0.48);
75 Ok(())
76}
77
78/// An exact power of ten is already at one figure, so it survives any count
79/// unchanged, either sign.
80#[test]
81fn test_rounded_powers_of_ten_01() -> Outcome<()> {
82 for exp in -18i32..=18 {
83 let v = match format!("1e{}", exp).parse::<f64>() {
84 Ok(v) => v,
85 Err(_) => continue,
86 };
87 for sf in 1..=5u8 {
88 assert_eq!(res!(Quantity::dimensionless(v, sf)).rounded(), v,
89 "10^{} at {} sf", exp, sf);
90 assert_eq!(res!(Quantity::dimensionless(-v, sf)).rounded(), -v,
91 "-10^{} at {} sf", exp, sf);
92 }
93 }
94 Ok(())
95}
96
97/// A tie is settled away from zero, so 0.125 to two figures is 0.13 and 2.5 to
98/// one figure is 3.
99#[test]
100fn test_rounded_ties_away_from_zero_01() -> Outcome<()> {
101 assert_eq!(res!(Quantity::dimensionless(0.125, 2)).rounded(), 0.13);
102 assert_eq!(res!(Quantity::dimensionless(-0.125, 2)).rounded(), -0.13);
103 assert_eq!(res!(Quantity::dimensionless(2.5, 1)).rounded(), 3.0);
104 assert_eq!(res!(Quantity::dimensionless(-2.5, 1)).rounded(), -3.0);
105 Ok(())
106}
107
108/// A zero carries no scale, so it rounds to zero rather than to a
109/// not-a-number.
110#[test]
111fn test_rounded_zero_01() -> Outcome<()> {
112 assert_eq!(res!(Quantity::dimensionless(0.0, 3)).rounded(), 0.0);
113 assert_eq!(res!(Quantity::new(0.0, 1, Dimension::force())).rounded(), 0.0);
114 Ok(())
115}
116
117/// The displayed form uses the rounded magnitude, so a negative slope reads
118/// with the figures it was measured to.
119#[test]
120fn test_display_uses_rounded_magnitude_01() -> Outcome<()> {
121 let q = res!(Quantity::dimensionless(-0.475, 2));
122 assert!(format!("{}", q).starts_with("-0.48"), "displayed as {}", q);
123 Ok(())
124}