【问题标题】:How to use python to convert a float number to fixed point with predefined number of bits如何使用python将浮点数转换为具有预定义位数的定点
【发布时间】:2016-09-02 22:14:27
【问题描述】:

我有 numpy 格式的 32 个浮点数(假设是正数)。我想将它们转换为具有预定义位数以降低精度的定点数。

例如,数字 3.1415926 在 matlab 中通过使用函数 num2fixpt 变为 3.25。 命令是 num2fixpt(3.1415926,sfix(5),2^(1 + 2-5), 'Nearest','on') 表示整数部分为 3 位,小数部分为 2 位。

我可以用 Python 做同样的事情吗

【问题讨论】:

  • 你的最终目标是什么?
  • 我不希望数字太精确。例如,使用定点数字信号处理器来模拟情况。我希望浮点数以精度较低的定点格式保存。

标签: python fixed-point quantization


【解决方案1】:

numfi是一个模仿matlab的fi定点对象的python库,它更像是simulink中的fixdt,但是你可以通过定义单词/分数长度而不是缩放来将num2fixpt更改为numfi

>>> from numfi import numfi
>>> x = numfi(3.1415926,1,5,2) # 5 word length = 2 fraction + 2 integer + 1 signed
>>> x
numfi([3.25]) s5/2-r/s

【讨论】:

    【解决方案2】:

    您可以使用 fxpmath 模块在 python 中处理小数定点。

    模块存储库:https://github.com/francof2a/fxpmath

    from fxpmath import Fxp
    
    pi_fxp = Fxp(None, signed=False, n_word=5, n_frac=2)    # create fixed-point object (3 bit for intefer, 2 for fractional)
    pi_fxp.rounding = 'around'                              # define rounding method, default is `trunc`.
    pi_fxp(3.1415926)                                       # set value
    
    print(pi_fxp)                                           # printed value = 3.25
    

    【讨论】:

      【解决方案3】:

      您可以舍入到二进制固定精度,而无需显式类型转换,这往往会产生大量解释器开销:

      import numpy as np
      
      n_bits = 2
      f = (1 << n_bits)
      
      a = np.linspace(1, 2, 11)
      a_fix = np.round(a*f)*(1.0/f)
      
      print a
      print a_fix
      

      结果

      [ 1.   1.1  1.2  1.3  1.4  1.5  1.6  1.7  1.8  1.9  2. ]
      [ 1.    1.    1.25  1.25  1.5   1.5   1.5   1.75  1.75  2.    2.  ]
      

      该示例使用 numpy,但这只是为了方便生成示例值列表。 Python 的内置 round 也适用于单个值:

      x=3.1415926
      x_fix = round(x*f)/float(f)
      print x_fix
      

      请注意,f 和 1.0/f 都有精确的浮点表示;因此,乘法和除法是精确的,没有舍入误差。另请注意,在大型数组的情况下,乘以 1.0/f 比直接除法快约 3 倍。

      这种方法不控制整数部分的位数,所以如果你希望数字被限制或在它们太大时环绕,你必须做更多的位移。

      【讨论】:

        【解决方案4】:

        如果您了解 IEEE 浮点表示法的工作原理,您就可以做到。基本上,您需要转换为 python LONG,执行按位运算符,然后隐蔽返回。例如:

        import time,struct,math
        long2bits = lambda L: ("".join([str(int(1 << i & L > 0)) for i in range(64)]))[::-1]
        double2long = lambda d: struct.unpack("Q",struct.pack("d",d))[0]
        double2bits = lambda d: long2bits(double2long(d))
        long2double = lambda L: struct.unpack('d',struct.pack('Q',L))[0]
        bits2double = lambda b: long2double(bits2long(b))
        bits2long=lambda z:sum([bool(z[i] == '1')*2**(len(z)-i-1) for i in range(len(z))[::-1]])
        
        >>> pi = 3.1415926
        >>> double2bits(pi)
        '0100000000001001001000011111101101001101000100101101100001001010'
        >>> bits2long('1111111111111111000000000000000000000000000000000000000000000000')
        18446462598732840960L
        >>> double2long(pi)
        4614256656431372362
        >>> long2double(double2long(pi) & 18446462598732840960L)
        3.125
        >>>
        
        def rshift(x,n=1):
            while n > 0:
                x = 9223372036854775808L | (x >> 1)
                n -= 1
            return x
        
        >>> L = bits2long('1'*12 + '0'*52)
        >>> L
        18442240474082181120L
        >>> long2double(rshift(L,0) & double2long(pi))
        2.0
        >>> long2double(rshift(L,1) & double2long(pi))
        3.0
        >>> long2double(rshift(L,4) & double2long(pi))
        3.125
        >>> long2double(rshift(L,7) & double2long(pi))
        3.140625
        

        这只会截断位数,而不是四舍五入。 rshift 函数是必要的,因为 python 的右移运算符用零填充最左边的空位。请参阅 IEEE 浮点 here 的描述。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-01-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-11-17
          • 1970-01-01
          • 2012-05-25
          相关资源
          最近更新 更多