Search code examples
pythonrounding

Keep only two digits after the first digit other than zero


I know how to keep only two decimal places after the decimal point. For example (there are other methods):

>>> print(f'{10000.01908223295211791992:.2f}')
10000.02

But I want to keep the first two digits other than zero after the decimal point:

10000.01908223295211791992 will give: 10000.019

0.0000456576578765 will give: 0.000046

Is there an built-in method that I'm missing? Or is the only solution to code a test for (almost) every case?


Solution

  • The following should be able to match the string and then round the value by applying a magnitude transformation.

    import math
    import re
    
    TWO_DIGITS_AFTER_ZERO = re.compile(r'(\d+\.(?:(?:[1-9]*)?|0+)0[1-9]{2})')
    
    def truncate(n: float) -> float:
        if result := TWO_DIGITS_AFTER_ZERO.match(format(n, 'f')):
            value = result.group(0)
            magnitude = 10**len(value.split('.')[1])
            return round(float(value) * magnitude) / magnitude
        else:
            return n
     
    
    if __name__ == '__main__':
        assert math.isclose(truncate(10000.01908223295211791992), 10000.019)
        assert math.isclose(truncate(0.0000456576578765), 0.000046)
    

    Here is an example utilizing the ndigits keyword argument of the round() function:

    from math import floor, isclose, log10, modf
    from typing import Callable
    
    f: Callable[[float],float] = lambda n: round(n, -int(floor(log10(abs(modf(n)[0]))))+1)
    
    if __name__ == '__main__':
        assert isclose(f(10000.01908223295211791992), 10000.019)
        assert isclose(f(0.0000456576578765), 0.000046)