Search code examples
pythonstringnumbers

Convert float number to string with engineering notation (with SI prefix) in Python


I have a float number such as x=23392342.1

I would like to convert it to a string with engineering notation (with metric prefix)

http://en.wikipedia.org/wiki/Engineering_notation http://en.wikipedia.org/wiki/Metric_prefix

So in my example 23392342.1 = 23.3923421E6 = 23.3923421 M (mega)

I would like to display 23.3923421 M


Solution

  • Here is a function inspired from Formatting a number with a metric prefix?

    metric.py

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    import math
    
    
    def to_si(d, sep=' '):
        """
        Convert number to string with SI prefix
    
        :Example:
    
        >>> to_si(2500.0)
        '2.5 k'
    
        >>> to_si(2.3E6)
        '2.3 M'
    
        >>> to_si(2.3E-6)
        '2.3 µ'
    
        >>> to_si(-2500.0)
        '-2.5 k'
    
        >>> to_si(0)
        '0'
    
        """
    
        inc_prefixes = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
        dec_prefixes = ['m', 'µ', 'n', 'p', 'f', 'a', 'z', 'y']
    
        if d == 0:
            return str(0)
    
        degree = int(math.floor(math.log10(math.fabs(d)) / 3))
    
        prefix = ''
    
        if degree != 0:
            ds = degree / math.fabs(degree)
            if ds == 1:
                if degree - 1 < len(inc_prefixes):
                    prefix = inc_prefixes[degree - 1]
                else:
                    prefix = inc_prefixes[-1]
                    degree = len(inc_prefixes)
    
            elif ds == -1:
                if -degree - 1 < len(dec_prefixes):
                    prefix = dec_prefixes[-degree - 1]
                else:
                    prefix = dec_prefixes[-1]
                    degree = -len(dec_prefixes)
    
            scaled = float(d * math.pow(1000, -degree))
    
            s = "{scaled}{sep}{prefix}".format(scaled=scaled,
                                               sep=sep,
                                               prefix=prefix)
    
        else:
            s = "{d}".format(d=d)
    
        return s
    
    
    if __name__ == "__main__":
        import doctest
        doctest.testmod()
    

    and its usage:

    from metric import to_si
    d = 23392342.1
    print(to_si(d))
    

    It will display

    23.3923421 M