将浮点数转换为定点数

26
在C++中,将任何浮点值(float)转换为定点(int,16:16或24:8)的通用方法是什么? 编辑:为了澄清,固定点值有两部分:整数部分和小数部分。整数部分可以由有符号或无符号整数数据类型表示。小数部分由无符号整数数据类型表示。
为了更好地理解,让我们拿钱来打个比方。小数部分可能代表美分 - 美元的小数部分。'cents'数据类型的范围将是0到99。如果要使用8位无符号整数进行定点数学运算,则小数部分将被平均分成256个可整除的部分。
我希望这能澄清事情。

如果你正在使用Visual C++,在考虑重构所有浮点数到定点数之前,请尝试使用/fp:fast开关进行实验。这个浮点模型开关允许优化,可以使浮点数轻松地在速度上击败定点数。绝对是一个被低估的功能。 - Special Sauce
这里是此内容的微软文档。有人知道这是否是仅适用于Microsoft的吗? - Mawg says reinstate Monica
6个回答

31

给您:

// 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
};

编辑:这里是另一种处理定点数的常见方式,基于此创建了更通用的类(由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)

4
这更多地涉及如何分解浮点数,而不是将其转换为定点表示。 - Trap
3
这里的“DataType”是什么?它在哪里定义的? - dicroce
1
另外,如何实现从定点数到双精度的转换? - dicroce

25

将浮点数转换为整数会丢弃小数部分,因此如果您想将该小数部分保留为定点,则只需在转换之前将浮点数乘以它。请注意,下面的代码不会检查溢出。

如果您想要16:16

double f = 1.2345;
int n;

n=(int)(f*65536);

如果您想要 24:8

double f = 1.2345;
int n;

n=(int)(f*256);

7
**编辑**:我的第一条评论适用于Kevin编辑之前的内容,但是我会将其保留下来以备后人参考。有时候答案在这里变化得太快了!
Kevin的方法存在问题,因为在定点表示法中,通常需要将数据打包到保证的字长(通常为32位)中。分别声明两个部分会让编译器随意进行结构打包。是的,你可以强制规定,但它只适用于16:16表示法。
KPexEA更接近正确的做法,将所有内容都打包到int中,尽管我会使用“signed long”来明确32位。然后,您可以使用他的方法生成定点值,并使用位切片再次提取组件部分。他的建议也涵盖了24:8情况。
(而那些只建议使用static_cast的人……你们在想什么呢?;))

1
我给那个写出最好答案的人回复了答案,但是我实际上使用了一个相关问题代码,指向这里
它使用模板,并且很容易抛弃对boost库的依赖。

链接已损坏(404)。 - Ivan Black
下次最好链接相关的问题。正如上面Ivan通过评论所指出的,问题保持相关性。这个答案不再提供任何信息。 - Jake Millington
在帖子发布日期之后,更新到archive.org的副本链接。 - mskfisher

0

这种方法适用于将浮点数转换为整数,但是O.P.还想要固定点

现在如何在C ++中做到这一点,我不知道(因为我不熟练使用C ++)。也许可以尝试缩放整数的方法,即使用32位或64位整数,并以编程方式将最后6位分配给小数点右侧的内容。


-3

C++ 中没有内置支持固定点数的功能。你最好的选择是编写一个包装器 'FixedInt' 类,它接受双精度浮点数并将其转换。

至于通用的转换方法... 整数部分很容易,只需获取值的整数部分并将其存储在高位中... 小数部分则应该是以下内容:

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);
   }
}

虽然这可能仍然包含错误


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接