Repository: jagerber48/sciform

Issue:
Support decimal place rounding for value/uncertainty pairs.
Currently if users are interested in well-controlling the position of the decimal separator within a string they can do so using `round_mode="dec_place"` and `left_pad_dec_place`. E.g. 

```
from sciform import Formatter

formatter = Formatter(
    round_mode="dec_place",
    ndigits=5,
    left_pad_char=0,
    left_pad_dec_place=4,
)

for number in (123, 3453.39485345, 39.532, 9, 42, 8923.9823423):
    print(formatter(number))

# 00123.00000
# 03453.39485
# 00039.53200
# 00009.00000
# 00042.00000
# 08923.98234

```

Because `dec_place` rounding is not supported for value/uncertainty formatting this same strategy is not possible.

Discussion:
@jagerber48: I've leaned away from including this feature because I think `dec_place` rounding is a bad practice for value/uncertainty formatting. The official recommendations indicate that value/uncertainty pairs should be formatted according to significant digits of the uncertainty. However, it seems there is anyways demand to "line up" decimal symbols by controlling the digits to the right of the decimal symbol with `dec_place` and `ndigits` and the decimal to the left of the decimal symbol with `left_pad_dec_place`.

I will include this feature along with a recipe for how to line up decimal symbols in the examples. But I'll include in the documentation caution against using `round_mode="dec_place"` and explanation for the caution. The main issues are (1) if too few digits of uncertainty are shown then the uncertainty may be rendered as something like `0.0000` and (2) too many digits of uncertainty may be shown such as `1.23456789` when really only the first one or two are typically known or needed.

Solution patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index fe7a1574..3b28c241 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -11,6 +11,9 @@ Unreleased
 Added
 ^^^^^
 
+* Digits-past-the-decimal formatting (``round_mode="dec_place"``) is now supported for
+  value/uncertainty pairs.
+  [`#170 <https://github.com/jagerber48/sciform/issues/170>`_]
 * Added a dark theme option (default on) for readthedocs documentation.
 * Added code coverage breakdown for unit and feature tests to codecov CI.
 
diff --git a/src/sciform/format_utils/make_strings.py b/src/sciform/format_utils/make_strings.py
index 7ef69ad0..bfb6d1d1 100644
--- a/src/sciform/format_utils/make_strings.py
+++ b/src/sciform/format_utils/make_strings.py
@@ -3,7 +3,7 @@
 from __future__ import annotations
 
 import decimal
-from typing import TYPE_CHECKING
+from decimal import Decimal
 
 from sciform.format_utils.numbers import (
     get_top_dec_place,
@@ -14,9 +14,6 @@
     SignModeEnum,
 )
 
-if TYPE_CHECKING:  # pragma: no cover
-    from decimal import Decimal
-
 
 def get_sign_str(num: Decimal, sign_mode: SignModeEnum) -> str:
     """Get the format sign string."""
@@ -95,11 +92,26 @@ def construct_num_str(
     return f"{sign_str}{pad_str}{abs_num_str}"
 
 
+def parse_mantissa_str_to_dec(
+    mantissa_str: str,
+    decimal_separator: DecimalSeparatorEnums,
+) -> Decimal:
+    """Convert a string, possibly with non-standard separators, to a decimal."""
+    clean_mantissa_str = mantissa_str
+    for separator in SeparatorEnum:
+        if separator != decimal_separator:
+            clean_mantissa_str = clean_mantissa_str.replace(
+                separator,
+                "",
+            )
+    clean_mantissa_str = clean_mantissa_str.replace(decimal_separator, ".")
+    mantissa_dec = Decimal(clean_mantissa_str)
+    return mantissa_dec
+
+
 def construct_val_unc_str(  # noqa: PLR0913
     val_mantissa_str: str,
     unc_mantissa_str: str,
-    val_mantissa: Decimal,
-    unc_mantissa: Decimal,
     decimal_separator: DecimalSeparatorEnums,
     *,
     paren_uncertainty: bool,
@@ -113,22 +125,20 @@ def construct_val_unc_str(  # noqa: PLR0913
             pm_symb = f" {pm_symb} "
         val_unc_str = f"{val_mantissa_str}{pm_symb}{unc_mantissa_str}"
     else:
-        if (
-            paren_uncertainty_trim
-            and unc_mantissa.is_finite()
-            and val_mantissa.is_finite()
-            and 0 < unc_mantissa < abs(val_mantissa)
-        ):
-            """
-            Don't strip the unc_mantissa_str if val_mantissa is non-finite.
-            Don't strip the unc_mantissa_str if unc_mantissa == 0 (because then the
-              empty string would remain).
-            Don't left strip the unc_mantissa_str if unc_mantissa >= val_mantissa
-            """
-            for separator in SeparatorEnum:
-                if separator != decimal_separator:
-                    unc_mantissa_str = unc_mantissa_str.replace(separator, "")
-            unc_mantissa_str = unc_mantissa_str.lstrip("0" + decimal_separator)
+        if paren_uncertainty_trim:
+            val_dec = parse_mantissa_str_to_dec(val_mantissa_str, decimal_separator)
+            unc_dec = parse_mantissa_str_to_dec(unc_mantissa_str, decimal_separator)
+            if unc_dec.is_finite() and val_dec.is_finite():
+                if unc_dec == 0:
+                    unc_mantissa_str = "0"
+                elif unc_dec < abs(val_dec):
+                    for separator in SeparatorEnum:
+                        if separator != decimal_separator:
+                            unc_mantissa_str = unc_mantissa_str.replace(
+                                separator,
+                                "",
+                            )
+                    unc_mantissa_str = unc_mantissa_str.lstrip("0" + decimal_separator)
         val_unc_str = f"{val_mantissa_str}({unc_mantissa_str})"
     return val_unc_str
 
diff --git a/src/sciform/formatting/number_formatting.py b/src/sciform/formatting/number_formatting.py
index f8b86470..3771fccb 100644
--- a/src/sciform/formatting/number_formatting.py
+++ b/src/sciform/formatting/number_formatting.py
@@ -5,7 +5,6 @@
 from dataclasses import replace
 from decimal import Decimal
 from typing import TYPE_CHECKING, cast
-from warnings import warn
 
 from sciform.api.formatted_number import FormattedNumber
 from sciform.format_utils.exponents import get_exp_str, get_val_unc_exp
@@ -180,7 +179,7 @@ def format_num(num: Decimal, options: FinalizedOptions) -> str:
     return result
 
 
-def format_val_unc(val: Decimal, unc: Decimal, options: FinalizedOptions) -> str:
+def format_val_unc(val: Decimal, unc: Decimal, options: FinalizedOptions) -> str:  # noqa: PLR0915
     """Format value/uncertainty pair according to input options."""
     exp_mode = options.exp_mode
 
@@ -190,13 +189,6 @@ def format_val_unc(val: Decimal, unc: Decimal, options: FinalizedOptions) -> str
         )
         raise NotImplementedError(msg)
 
-    if options.round_mode is RoundModeEnum.DEC_PLACE:
-        msg = (
-            "Precision round mode not available for value/uncertainty formatting. "
-            "Rounding is always applied as significant figures for the uncertainty."
-        )
-        warn(msg, stacklevel=2)
-
     unc = abs(unc)
     if exp_mode is ExpModeEnum.PERCENT:
         val *= 100
@@ -210,31 +202,72 @@ def format_val_unc(val: Decimal, unc: Decimal, options: FinalizedOptions) -> str
         """
         exp_mode = ExpModeEnum.FIXEDPOINT
 
-    """
-    We round twice in case the first rounding changes the digits place
-    to which we need to round. E.g. rounding 999.999 ± 123.456 to two
-    significant figures will lead to 1000.000 ± 0120.000 on the first
-    pass, but we must re-round to get 1000.000 ± 0100.000.
-    """
-    val_rounded, unc_rounded, _ = round_val_unc(
-        val,
-        unc,
-        options.round_mode,
-        options.ndigits,
-    )
-    val_rounded, unc_rounded, round_digit = round_val_unc(
-        val_rounded,
-        unc_rounded,
-        options.round_mode,
-        options.ndigits,
-    )
+    if options.round_mode is RoundModeEnum.DEC_PLACE:
+        """
+        We calculate the exponent twice in case rounding the mantissa changes the
+        required exponent. For example, 0.0999 ± 0.0999 displayed in scientific notation
+        would be (9.99 ± 9.99)e-02 but rounded to zero digits-past-the-decimal gives
+        (10 ± 10)e-02, so we need to recalculate the exponent to get (1 ± 1)e-01.
+        """
+        exp_val = get_val_unc_exp(
+            val,
+            unc,
+            options.exp_mode,
+            options.exp_val,
+        )
+        val_mantissa = val * Decimal(10) ** (-Decimal(exp_val))
+        unc_mantissa = unc * Decimal(10) ** (-Decimal(exp_val))
+        val_mantissa_rounded, unc_mantissa_rounded, _ = round_val_unc(
+            val_mantissa,
+            unc_mantissa,
+            options.round_mode,
+            options.ndigits,
+        )
+        val_rounded = val_mantissa_rounded * Decimal(10) ** Decimal(exp_val)
+        unc_rounded = unc_mantissa_rounded * Decimal(10) ** Decimal(exp_val)
+        exp_val = get_val_unc_exp(
+            val_rounded,
+            unc_rounded,
+            options.exp_mode,
+            options.exp_val,
+        )
+        """
+        ndigits that will be used for separate digits-past-the-decimal rounding for the
+        value and uncertainty.
+        """
+        ndigits = options.ndigits
+    else:
+        """
+        We round twice in case the first rounding changes the digits place to which we
+        need to round. E.g. rounding 0.0999 ± 0.0999 to one significant figure would
+        naively result in rounding to the -2 place, leaving us with 0.10 ± 0.10. But the
+        -2 place actually corresponds to two significant figures, so we re-round to the
+        -1 place to get 0.1 ± 0.1.
+        """
+        val_rounded, unc_rounded, _ = round_val_unc(
+            val,
+            unc,
+            options.round_mode,
+            options.ndigits,
+        )
+        val_rounded, unc_rounded, round_digit = round_val_unc(
+            val_rounded,
+            unc_rounded,
+            options.round_mode,
+            options.ndigits,
+        )
 
-    exp_val = get_val_unc_exp(
-        val_rounded,
-        unc_rounded,
-        options.exp_mode,
-        options.exp_val,
-    )
+        exp_val = get_val_unc_exp(
+            val_rounded,
+            unc_rounded,
+            options.exp_mode,
+            options.exp_val,
+        )
+        """
+        ndigits that will be used for separate digits-past-the-decimal rounding for the
+        value and uncertainty.
+        """
+        ndigits = -round_digit + exp_val
 
     val_mantissa, _, _ = get_mantissa_exp_base(
         val_rounded,
@@ -254,8 +287,6 @@ def format_val_unc(val: Decimal, unc: Decimal, options: FinalizedOptions) -> str
         left_pad_matching=options.left_pad_matching,
     )
 
-    ndigits = -round_digit + exp_val
-
     """
     We will format the val and unc mantissas
        * using decimal place rounding mode with the ndigits calculated
@@ -294,8 +325,6 @@ def format_val_unc(val: Decimal, unc: Decimal, options: FinalizedOptions) -> str
     val_unc_str = construct_val_unc_str(
         val_mantissa_str=val_mantissa_str,
         unc_mantissa_str=unc_mantissa_str,
-        val_mantissa=val_mantissa,
-        unc_mantissa=unc_mantissa,
         decimal_separator=options.decimal_separator,
         paren_uncertainty=options.paren_uncertainty,
         pm_whitespace=options.pm_whitespace,


Test patch:
diff --git a/tests/feature/test_val_unc_formatter.py b/tests/feature/test_val_unc_formatter.py
index dde7e571..cf7ca03b 100644
--- a/tests/feature/test_val_unc_formatter.py
+++ b/tests/feature/test_val_unc_formatter.py
@@ -426,10 +426,6 @@ def test_pdg_sig_figs(self):
 
         self.run_val_unc_formatter_cases(cases_list)
 
-    def test_dec_place_warn(self):
-        formatter = Formatter(round_mode="dec_place")
-        self.assertWarns(Warning, formatter, 42, 24)
-
     def test_left_pad_matching(self):
         formatter = Formatter(left_pad_matching=True)
         result = formatter(123, 0.123)
diff --git a/tests/feature/test_val_unc_fsml.py b/tests/feature/test_val_unc_fsml.py
index 3f3d4f20..55f15764 100644
--- a/tests/feature/test_val_unc_fsml.py
+++ b/tests/feature/test_val_unc_fsml.py
@@ -34,6 +34,15 @@ def test_fixed(self):
                     ("!3f", "123.456 ± 0.789"),
                     ("!4f", "123.4560 ± 0.7890"),
                     ("!2f()", "123.46(79)"),
+                    (".-3f", "0 ± 0"),
+                    (".-2f", "100 ± 0"),
+                    (".-1f", "120 ± 0"),
+                    (".0f", "123 ± 1"),
+                    (".1f", "123.5 ± 0.8"),
+                    (".2f", "123.46 ± 0.79"),
+                    (".3f", "123.456 ± 0.789"),
+                    (".4f", "123.4560 ± 0.7890"),
+                    (".2f()", "123.46(79)"),
                 ],
             ),
             (
@@ -45,6 +54,15 @@ def test_fixed(self):
                     ("!3f", "-123.456 ± 0.789"),
                     ("!4f", "-123.4560 ± 0.7890"),
                     ("!2f()", "-123.46(79)"),
+                    (".-3f", "0 ± 0"),
+                    (".-2f", "-100 ± 0"),
+                    (".-1f", "-120 ± 0"),
+                    (".0f", "-123 ± 1"),
+                    (".1f", "-123.5 ± 0.8"),
+                    (".2f", "-123.46 ± 0.79"),
+                    (".3f", "-123.456 ± 0.789"),
+                    (".4f", "-123.4560 ± 0.7890"),
+                    (".2f()", "-123.46(79)"),
                 ],
             ),
             (
@@ -65,6 +83,28 @@ def test_fixed(self):
                     ("!5f()", "0.79(123.46)"),
                     ("!6f()", "0.789(123.456)"),
                     ("!7f()", "0.7890(123.4560)"),
+                    (".-3f", "0 ± 0"),
+                    (".-2f", "0 ± 100"),
+                    (".-1f", "0 ± 120"),
+                    (".0f", "1 ± 123"),
+                    (".1f", "0.8 ± 123.5"),
+                    (".2f", "0.79 ± 123.46"),
+                    (".3f", "0.789 ± 123.456"),
+                    (".4f", "0.7890 ± 123.4560"),
+                    (".5f", "0.78900 ± 123.45600"),
+                    (".6f", "0.789000 ± 123.456000"),
+                    (".7f", "0.7890000 ± 123.4560000"),
+                    (".-3f()", "0(0)"),
+                    (".-2f()", "0(100)"),
+                    (".-1f()", "0(120)"),
+                    (".0f()", "1(123)"),
+                    (".1f()", "0.8(123.5)"),
+                    (".2f()", "0.79(123.46)"),
+                    (".3f()", "0.789(123.456)"),
+                    (".4f()", "0.7890(123.4560)"),
+                    (".5f()", "0.78900(123.45600)"),
+                    (".6f()", "0.789000(123.456000)"),
+                    (".7f()", "0.7890000(123.4560000)"),
                 ],
             ),
             (
@@ -85,6 +125,28 @@ def test_fixed(self):
                     ("!5f()", "-0.79(123.46)"),
                     ("!6f()", "-0.789(123.456)"),
                     ("!7f()", "-0.7890(123.4560)"),
+                    (".-3f", "0 ± 0"),
+                    (".-2f", "0 ± 100"),
+                    (".-1f", "0 ± 120"),
+                    (".0f", "-1 ± 123"),
+                    (".1f", "-0.8 ± 123.5"),
+                    (".2f", "-0.79 ± 123.46"),
+                    (".3f", "-0.789 ± 123.456"),
+                    (".4f", "-0.7890 ± 123.4560"),
+                    (".5f", "-0.78900 ± 123.45600"),
+                    (".6f", "-0.789000 ± 123.456000"),
+                    (".7f", "-0.7890000 ± 123.4560000"),
+                    (".-3f()", "0(0)"),
+                    (".-2f()", "0(100)"),
+                    (".-1f()", "0(120)"),
+                    (".0f()", "-1(123)"),
+                    (".1f()", "-0.8(123.5)"),
+                    (".2f()", "-0.79(123.46)"),
+                    (".3f()", "-0.789(123.456)"),
+                    (".4f()", "-0.7890(123.4560)"),
+                    (".5f()", "-0.78900(123.45600)"),
+                    (".6f()", "-0.789000(123.456000)"),
+                    (".7f()", "-0.7890000(123.4560000)"),
                 ],
             ),
         ]
@@ -102,6 +164,15 @@ def test_scientific(self):
                     ("!3e", "(1.23456 ± 0.00789)e+02"),
                     ("!4e", "(1.234560 ± 0.007890)e+02"),
                     ("!2e()", "1.2346(79)e+02"),
+                    (".-3e", "(0 ± 0)e+00"),
+                    (".-2e", "(0 ± 0)e+00"),
+                    (".-1e", "(0 ± 0)e+00"),
+                    (".0e", "(1 ± 0)e+02"),
+                    (".1e", "(1.2 ± 0.0)e+02"),
+                    (".2e", "(1.23 ± 0.01)e+02"),
+                    (".3e", "(1.235 ± 0.008)e+02"),
+                    (".4e", "(1.2346 ± 0.0079)e+02"),
+                    (".2e()", "1.23(1)e+02"),
                 ],
             ),
             (
@@ -122,6 +193,28 @@ def test_scientific(self):
                     ("!5e()", "0.0079(1.2346)e+02"),
                     ("!6e()", "0.00789(1.23456)e+02"),
                     ("!7e()", "0.007890(1.234560)e+02"),
+                    (".-3e", "(0 ± 0)e+00"),
+                    (".-2e", "(0 ± 0)e+00"),
+                    (".-1e", "(0 ± 0)e+00"),
+                    (".0e", "(0 ± 1)e+02"),
+                    (".1e", "(0.0 ± 1.2)e+02"),
+                    (".2e", "(0.01 ± 1.23)e+02"),
+                    (".3e", "(0.008 ± 1.235)e+02"),
+                    (".4e", "(0.0079 ± 1.2346)e+02"),
+                    (".5e", "(0.00789 ± 1.23456)e+02"),
+                    (".6e", "(0.007890 ± 1.234560)e+02"),
+                    (".7e", "(0.0078900 ± 1.2345600)e+02"),
+                    (".-3e()", "0(0)e+00"),
+                    (".-2e()", "0(0)e+00"),
+                    (".-1e()", "0(0)e+00"),
+                    (".0e()", "0(1)e+02"),
+                    (".1e()", "0.0(1.2)e+02"),
+                    (".2e()", "0.01(1.23)e+02"),
+                    (".3e()", "0.008(1.235)e+02"),
+                    (".4e()", "0.0079(1.2346)e+02"),
+                    (".5e()", "0.00789(1.23456)e+02"),
+                    (".6e()", "0.007890(1.234560)e+02"),
+                    (".7e()", "0.0078900(1.2345600)e+02"),
                 ],
             ),
             (
@@ -142,6 +235,26 @@ def test_scientific(self):
                     ("!5e()", "0.0000(1.2346)e+02"),
                     ("!6e()", "0.00000(1.23456)e+02"),
                     ("!7e()", "0.000000(1.234560)e+02"),
+                    (".-3e", "(0 ± 0)e+00"),
+                    (".-2e", "(0 ± 0)e+00"),
+                    (".-1e", "(0 ± 0)e+00"),
+                    (".0e", "(0 ± 1)e+02"),
+                    (".1e", "(0.0 ± 1.2)e+02"),
+                    (".2e", "(0.00 ± 1.23)e+02"),
+                    (".3e", "(0.000 ± 1.235)e+02"),
+                    (".4e", "(0.0000 ± 1.2346)e+02"),
+                    (".5e", "(0.00000 ± 1.23456)e+02"),
+                    (".6e", "(0.000000 ± 1.234560)e+02"),
+                    (".7e", "(0.0000000 ± 1.2345600)e+02"),
+                    (".-1e()", "0(0)e+00"),
+                    (".0e()", "0(1)e+02"),
+                    (".1e()", "0.0(1.2)e+02"),
+                    (".2e()", "0.00(1.23)e+02"),
+                    (".3e()", "0.000(1.235)e+02"),
+                    (".4e()", "0.0000(1.2346)e+02"),
+                    (".5e()", "0.00000(1.23456)e+02"),
+                    (".6e()", "0.000000(1.234560)e+02"),
+                    (".7e()", "0.0000000(1.2345600)e+02"),
                 ],
             ),
         ]
@@ -159,6 +272,15 @@ def test_engineering(self):
                     ("!3r", "(1.234560 ± 0.000789)e+03"),
                     ("!4r", "(1.2345600 ± 0.0007890)e+03"),
                     ("!2r()", "1.23456(79)e+03"),
+                    (".-3r", "(0 ± 0)e+00"),
+                    (".-2r", "(0 ± 0)e+00"),
+                    (".-1r", "(0 ± 0)e+00"),
+                    (".0r", "(1 ± 0)e+03"),
+                    (".1r", "(1.2 ± 0.0)e+03"),
+                    (".2r", "(1.23 ± 0.00)e+03"),
+                    (".3r", "(1.235 ± 0.001)e+03"),
+                    (".4r", "(1.2346 ± 0.0008)e+03"),
+                    (".2r()", "1.23(0)e+03"),
                 ],
             ),
             (
@@ -179,6 +301,24 @@ def test_engineering(self):
                     ("!5r()", "0.79(123.46)e+00"),
                     ("!6r()", "0.789(123.456)e+00"),
                     ("!7r()", "0.7890(123.4560)e+00"),
+                    (".-3r", "(0 ± 0)e+00"),
+                    (".-2r", "(0 ± 100)e+00"),
+                    (".-1r", "(0 ± 120)e+00"),
+                    (".0r", "(1 ± 123)e+00"),
+                    (".1r", "(0.8 ± 123.5)e+00"),
+                    (".2r", "(0.79 ± 123.46)e+00"),
+                    (".3r", "(0.789 ± 123.456)e+00"),
+                    (".4r", "(0.7890 ± 123.4560)e+00"),
+                    (".5r", "(0.78900 ± 123.45600)e+00"),
+                    (".6r", "(0.789000 ± 123.456000)e+00"),
+                    (".7r", "(0.7890000 ± 123.4560000)e+00"),
+                    (".1r()", "0.8(123.5)e+00"),
+                    (".2r()", "0.79(123.46)e+00"),
+                    (".3r()", "0.789(123.456)e+00"),
+                    (".4r()", "0.7890(123.4560)e+00"),
+                    (".5r()", "0.78900(123.45600)e+00"),
+                    (".6r()", "0.789000(123.456000)e+00"),
+                    (".7r()", "0.7890000(123.4560000)e+00"),
                 ],
             ),
         ]
@@ -196,6 +336,13 @@ def test_engineering_shifted(self):
                     ("#!3r", "(0.123456 ± 0.000789)e+03"),
                     ("#!4r", "(0.1234560 ± 0.0007890)e+03"),
                     ("#!2r()", "0.12346(79)e+03"),
+                    ("#.-1r", "(0 ± 0)e+00"),
+                    ("#.0r", "(0 ± 0)e+00"),
+                    ("#.1r", "(0.1 ± 0.0)e+03"),
+                    ("#.2r", "(0.12 ± 0.00)e+03"),
+                    ("#.3r", "(0.123 ± 0.001)e+03"),
+                    ("#.4r", "(0.1235 ± 0.0008)e+03"),
+                    ("#.2r()", "0.12(0)e+03"),
                 ],
             ),
             (
@@ -216,6 +363,28 @@ def test_engineering_shifted(self):
                     ("#!5r()", "0.00079(0.12346)e+03"),
                     ("#!6r()", "0.000789(0.123456)e+03"),
                     ("#!7r()", "0.0007890(0.1234560)e+03"),
+                    ("#.-3r", "(0 ± 0)e+00"),
+                    ("#.-2r", "(0 ± 0)e+00"),
+                    ("#.-1r", "(0 ± 0)e+00"),
+                    ("#.0r", "(0 ± 0)e+00"),
+                    ("#.1r", "(0.0 ± 0.1)e+03"),
+                    ("#.2r", "(0.00 ± 0.12)e+03"),
+                    ("#.3r", "(0.001 ± 0.123)e+03"),
+                    ("#.4r", "(0.0008 ± 0.1235)e+03"),
+                    ("#.5r", "(0.00079 ± 0.12346)e+03"),
+                    ("#.6r", "(0.000789 ± 0.123456)e+03"),
+                    ("#.7r", "(0.0007890 ± 0.1234560)e+03"),
+                    ("#.-3r()", "0(0)e+00"),
+                    ("#.-2r()", "0(0)e+00"),
+                    ("#.-1r()", "0(0)e+00"),
+                    ("#.0r()", "0(0)e+00"),
+                    ("#.1r()", "0.0(0.1)e+03"),
+                    ("#.2r()", "0.00(0.12)e+03"),
+                    ("#.3r()", "0.001(0.123)e+03"),
+                    ("#.4r()", "0.0008(0.1235)e+03"),
+                    ("#.5r()", "0.00079(0.12346)e+03"),
+                    ("#.6r()", "0.000789(0.123456)e+03"),
+                    ("#.7r()", "0.0007890(0.1234560)e+03"),
                 ],
             ),
         ]
@@ -385,14 +554,18 @@ def test_rounding(self):
                 (0.0999, 0.0999),
                 [
                     ("!1e", "(1 ± 1)e-01"),
+                    ("!2e", "(1.0 ± 1.0)e-01"),
+                    (".0e", "(1 ± 1)e-01"),
                 ],
             ),
             (
                 (0.0999, 0.999),
                 [
                     ("!1e", "(0 ± 1)e+00"),
+                    (".0e", "(0 ± 1)e+00"),
                 ],
             ),
+            ((999.999, 123.456), [("!2f", "1000 ± 120")]),
         ]
         self.run_val_unc_fsml_cases(cases_list)
 
diff --git a/tests/unit/format_utils/test_make_strings.py b/tests/unit/format_utils/test_make_strings.py
index 1c28edf0..23b2249f 100644
--- a/tests/unit/format_utils/test_make_strings.py
+++ b/tests/unit/format_utils/test_make_strings.py
@@ -143,8 +143,6 @@ def test_construct_val_unc_str(self):
                 {
                     "val_mantissa_str": "123.456",
                     "unc_mantissa_str": "0.123",
-                    "val_mantissa": Decimal("123.456"),
-                    "unc_mantissa": Decimal("0.123"),
                     "decimal_separator": ".",
                     "paren_uncertainty": False,
                     "pm_whitespace": True,
@@ -156,8 +154,6 @@ def test_construct_val_unc_str(self):
                 {
                     "val_mantissa_str": "123.456",
                     "unc_mantissa_str": "0.123",
-                    "val_mantissa": Decimal("123.456"),
-                    "unc_mantissa": Decimal("0.123"),
                     "decimal_separator": ".",
                     "paren_uncertainty": False,
                     "pm_whitespace": False,
@@ -169,8 +165,6 @@ def test_construct_val_unc_str(self):
                 {
                     "val_mantissa_str": "123,456",
                     "unc_mantissa_str": "0,123",
-                    "val_mantissa": Decimal("123.456"),
-                    "unc_mantissa": Decimal("0.123"),
                     "decimal_separator": ",",
                     "paren_uncertainty": False,
                     "pm_whitespace": True,
@@ -182,8 +176,6 @@ def test_construct_val_unc_str(self):
                 {
                     "val_mantissa_str": "123.456",
                     "unc_mantissa_str": "0.123",
-                    "val_mantissa": Decimal("123.456"),
-                    "unc_mantissa": Decimal("0.123"),
                     "decimal_separator": ".",
                     "paren_uncertainty": False,
                     "pm_whitespace": True,
@@ -195,8 +187,6 @@ def test_construct_val_unc_str(self):
                 {
                     "val_mantissa_str": "123,456",
                     "unc_mantissa_str": "0,123",
-                    "val_mantissa": Decimal("123.456"),
-                    "unc_mantissa": Decimal("0.123"),
                     "decimal_separator": ",",
                     "paren_uncertainty": True,
                     "pm_whitespace": True,
@@ -208,8 +198,6 @@ def test_construct_val_unc_str(self):
                 {
                     "val_mantissa_str": "123,456",
                     "unc_mantissa_str": "0,123",
-                    "val_mantissa": Decimal("123.456"),
-                    "unc_mantissa": Decimal("0.123"),
                     "decimal_separator": ",",
                     "paren_uncertainty": True,
                     "pm_whitespace": True,
@@ -221,8 +209,6 @@ def test_construct_val_unc_str(self):
                 {
                     "val_mantissa_str": "123,456,789.123_456",
                     "unc_mantissa_str": "0.123_456",
-                    "val_mantissa": Decimal("123456789.123456"),
-                    "unc_mantissa": Decimal("0.123456"),
                     "decimal_separator": ",",
                     "paren_uncertainty": True,
                     "pm_whitespace": True,
@@ -234,9 +220,7 @@ def test_construct_val_unc_str(self):
                 {
                     "val_mantissa_str": "123,456,789.123_456",
                     "unc_mantissa_str": "0.123_456",
-                    "val_mantissa": Decimal("123456789.123456"),
-                    "unc_mantissa": Decimal("0.123456"),
-                    "decimal_separator": ",",
+                    "decimal_separator": ".",
                     "paren_uncertainty": True,
                     "pm_whitespace": True,
                     "paren_uncertainty_trim": True,
@@ -247,8 +231,6 @@ def test_construct_val_unc_str(self):
                 {
                     "val_mantissa_str": "0.123",
                     "unc_mantissa_str": "123,456.456",
-                    "val_mantissa": Decimal("0.123"),
-                    "unc_mantissa": Decimal("123456.456"),
                     "decimal_separator": ",",
                     "paren_uncertainty": True,
                     "pm_whitespace": True,