将浮点转换为定点

Converting floating point to fixed point

本文关键字:转换      更新时间:2023-10-16

在C++中,将任何浮点值(float)转换为定点(int,16:16或24:8)的通用方法是什么?

编辑:为了澄清,定点值有两部分:整数部分和小数部分。整数部分可以由有符号或无符号整数数据类型表示。小数部分由无符号数据整数数据类型表示。

为了清楚起见,让我们用金钱来比喻一下。小数部分可能代表美分——一美元的小数部分。"美分"数据类型的范围为0到99。如果一个8位无符号整数用于定点数学,那么小数部分将被拆分为256个可整除的部分。

我希望这能澄清问题。

开始:

// A signed fixed-point 16:16 class
class FixedPoint_16_16
{
    short          intPart;
    unsigned short fracPart;
public:
    FixedPoint_16_16(double d)
    {
        *this = d; // calls operator=
    }
    FixedPoint_16_16& operator=(double d)
    {
        intPart = static_cast<short>(d);
        fracPart = static_cast<unsigned short>
                    (numeric_limits<unsigned short> + 1.0)*d);
        return *this;
    }
    // Other operators can be defined here
};

EDIT:这是一个更通用的类,基于另一种处理定点数的常见方法(KPexEA指出了这一点):

template <class BaseType, size_t FracDigits>
class fixed_point
{
    const static BaseType factor = 1 << FracDigits;
    BaseType data;
public:
    fixed_point(double d)
    {
        *this = d; // calls operator=
    }
    fixed_point& operator=(double d)
    {
        data = static_cast<BaseType>(d*factor);
        return *this;
    }
    BaseType raw_data() const
    {
        return data;
    }
    // Other operators can be defined here
};

fixed_point<int, 8> fp1;           // Will be signed 24:8 (if int is 32-bits)
fixed_point<unsigned int, 16> fp1; // Will be unsigned 16:16 (if int is 32-bits)

从float到integer的强制转换会丢弃小数部分,所以如果你想将小数保持在固定点附近,那么在强制转换之前只需乘以float。请注意,下面的代码不会检查溢出。

如果您想要16:16

double f = 1.2345;
int n;
n=(int)(f*65536);

如果您想要24:8

double f = 1.2345;
int n;
n=(int)(f*256);

***编辑**:我的第一条评论适用于Kevin编辑之前的,但我将把它留在这里留给后人。答案有时变化如此之快

Kevin的方法的问题是,使用固定点,您通常会打包到有保证的字大小(通常为32位)。单独声明这两个部分会让您对编译器的结构打包产生突发奇想。是的,你可以强制它,但它不适用于16:16表示以外的任何内容。

KPexEA通过将所有内容打包到int中更接近标记——尽管我会使用"signed long"来尝试在32位上显式。然后,您可以使用他的方法来生成不动点,并且位切片可以再次提取组成部分。他的建议也涵盖了24:8的情况。

(还有其他建议使用static_cast的人……你在想什么?;)

我把答案给了写最好答案的人,但我确实使用了一个指向这里的相关问题代码。

它使用了模板,并且很容易放弃对boostlib的依赖。

这对于从浮点转换为整数很好,但O.p.也需要固定点。

现在,我不知道你在C++中是如何做到这一点的(C++不是我能轻易思考的东西)。也许可以尝试一种缩放整数的方法,即使用32或64位整数,并以编程方式将最后一位,例如,6位数字分配给小数点右侧的数字。

C++中没有任何内置的对不动点数字的支持。您最好的选择是编写一个包装器"FixedInt"类,该类接受doubles并转换它们。

至于要转换的泛型方法。。。int部分很简单,只需获取值的整数部分并将其存储在高位。。。小数部分的内容大致如下:

for (int i = 1; i <= precision; i++)
{
   if (decimal_part > 1.f/(float)(i + 1)
   {
      decimal_part -= 1.f/(float)(i + 1);
      fixint_value |= (1 << precision - i);
   }
}

尽管这可能仍然包含错误