【问题标题】:How to convert packed integer (16.16) fixed-point to float?如何将压缩整数(16.16)定点转换为浮点数?
【发布时间】:2011-12-26 20:04:48
【问题描述】:

如何将“32 位有符号定点数(16.16)”转换为浮点数?

(fixed >> 16) + (fixed & 0xffff) / 65536.0 好吗? -2.5 怎么样?还有-0.5?

或者fixed / 65536.0 是正确的方式?

(PS:带符号的定点“-0.5”在内存中看起来如何?)

【问题讨论】:

  • 考虑它的一个好方法是以<16 bit integer part in hex>.<16 bit fractional part in hex> 格式可视化简单值。 1 = 0b1 = 0x0001.0000 = 65536。因此,如果 1 等价于 65536,则 2 将是 2 x 65536,以此类推

标签: floating-point fixed-point


【解决方案1】:

我假设二进制补码 32 位整数和运算符在 C# 中工作。

如何进行转换?

fixed / 65536.0

正确且易于理解。


(fixed >> 16) + (fixed & 0xffff) / 65536.0

等价于上面的正整数,但更慢,更难阅读。您基本上是在使用分配定律将单个分区分成两个分区,并使用位移位写入第一个分区。

对于负整数 fixed & 0xffff 不给你小数位,所以它对于负数是不正确的。

查看应该映射到-1/65536 的原始整数-1。此代码改为返回 65535/65536


根据您的编译器,它可能会更快:

fixed * (1/65536.0)

但我认为大多数现代编译器已经进行了这种优化。

有符号定点“-0.5”在内存中的样子如何?

反转转换给我们:

RoundToInt(float*65536)

设置float=-0.5 给我们:-32768

【讨论】:

    【解决方案2】:
    class FixedPointUtils {
      public static final int ONE = 0x10000;
    
      /**
       * Convert an array of floats to 16.16 fixed-point
       * @param arr The array
       * @return A newly allocated array of fixed-point values.
       */
      public static int[] toFixed(float[] arr) {
        int[] res = new int[arr.length];
        toFixed(arr, res);
        return res;
      }
    
      /**
       * Convert a float to  16.16 fixed-point representation
       * @param val The value to convert
       * @return The resulting fixed-point representation
       */
      public static int toFixed(float val) {
        return (int)(val * 65536F);
      }
    
      /**
       * Convert an array of floats to 16.16 fixed-point
       * @param arr The array of floats
       * @param storage The location to store the fixed-point values.
       */
      public static void toFixed(float[] arr, int[] storage)
      {
        for (int i=0;i<storage.length;i++) {
          storage[i] = toFixed(arr[i]);
        }
      }
    
      /**
       * Convert a 16.16 fixed-point value to floating point
       * @param val The fixed-point value
       * @return The equivalent floating-point value.
       */
      public static float toFloat(int val) {
        return ((float)val)/65536.0f;
      }
    
      /**
       * Convert an array of 16.16 fixed-point values to floating point
       * @param arr The array to convert
       * @return A newly allocated array of floats.
       */
      public static float[] toFloat(int[] arr) {
        float[] res = new float[arr.length];
        toFloat(arr, res);
        return res;
      }
    
      /**
       * Convert an array of 16.16 fixed-point values to floating point
       * @param arr The array to convert
       * @param storage Pre-allocated storage for the result.
       */
      public static void toFloat(int[] arr, float[] storage)
      {
        for (int i=0;i<storage.length;i++) {
          storage[i] = toFloat(arr[i]);
        }
      }
    
    }
    

    【讨论】:

      【解决方案3】:

      看了CodesInChaos的回答,我写了一个C++函数模板,很方便。您可以传递小数部分的长度(例如,BMP 文件格式使用 2.30 定点数)。如果省略小数部分长度,则函数假定小数部分和整数部分具有相同的长度

      #include <math.h> // for NaN
      #include <limits.h> // for CHAR_BIT = 8
      
      template<class T> inline double fixed_point2double(const T& x, int frac_digits = (CHAR_BIT * sizeof(T)) / 2 )
      {
        if (frac_digits >= CHAR_BIT * sizeof(T)) return NAN;
        return double(x) / double( T(1) << frac_digits) );
      }
      

      如果你想从内存中读取这样的数字,我写了一个函数模板

      #include <math.h> // for NaN
      #include <limits.h> // for CHAR_BIT = 8
      
      template<class T> inline double read_little_endian_fixed_point(const unsigned char *x, int frac_digits = (CHAR_BIT * sizeof(T)) / 2)
      // ! do not use for single byte types 'T'
      {
        if (frac_digits >= CHAR_BIT * sizeof(T)) return NAN;
      
        T res = 0;
      
        for (int i = 0, shift = 0; i < sizeof(T); ++i, shift += CHAR_BIT)
          res |= ((T)x[i]) << shift;
      
        return double(res) / double( T(1) << frac_digits) );
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多