C++ 将浮点数转换为定点数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/187713/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:33:33  来源:igfitidea点击:

Converting floating point to fixed point

c++fixed-point

提问by CVertex

In C++, what's the generic way to convert any floating point value (float) to fixed point(int, 16:16 or 24:8)?

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

EDIT:For clarification, fixed-point values have two parts to them: an integer part and a fractional part. The integer part can be represented by a signed or unsigned integer data type. The fractional part is represented by an unsigned data integer data type.

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

Let's make an analogy with money for the sake of clarity. The fractional part may represent cents -- a fractional part of a dollar. The range of the 'cents' data type would be 0 to 99. If a 8-bit unsigned integer were to be used for fixed-point math, then the fractional part would be split into 256 evenly divisible parts.

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

I hope that clears things up.

我希望这能解决问题。

回答by Kevin

Here you go:

干得好:

// 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:Here's a more general class based on anothercommon way to deal with fixed-point numbers (and which KPexEA pointed out):

编辑:这是一个更通用的类,基于另一种处理定点数的常用方法(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)

回答by KPexEA

A cast from float to integer will throw away the fractional portion so if you want to keep that fraction around as fixed point then you just multiply the float before casting it. The below code will not check for overflow mind you.

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

If you want 16:16

如果你想要 16:16

double f = 1.2345;
int n;

n=(int)(f*65536);

if you want 24:8

如果你想要 24:8

double f = 1.2345;
int n;

n=(int)(f*256);

回答by Greg Whitfield

**** Edit** : My first comment applies to before Kevin's edit,but I'll leave it here for posterity. Answers change so quickly here sometimes!

**** 编辑** :我的第一条评论适用于凯文编辑之前,但我会将它留在这里以供后代使用。有时这里的答案变化如此之快!

The problem with Kevin's approach is that with Fixed Point you are normally packing into a guaranteed word size (typically 32bits). Declaring the two parts separately leaves you to the whim of your compiler's structure packing. Yes you could force it, but it does not work for anything other than 16:16 representation.

Kevin 方法的问题在于,使用 Fixed Point 时,您通常会打包成有保证的字长(通常为 32 位)。分别声明这两个部分会让您陷入编译器结构打包的心血来潮。是的,您可以强制使用它,但它不适用于 16:16 表示以外的任何其他内容。

KPexEA is closer to the mark by packing everything into int - although I would use "signed long" to try and be explicit on 32bits. Then you can use his approach for generating the fixed point value, and bit slicing do extract the component parts again. His suggestion also covers the 24:8 case.

KPexEA 通过将所有内容打包到 int 中更接近标记 - 尽管我会使用“signed long”来尝试在 32 位上明确表示。然后你可以使用他的方法来生成定点值,然后位切片再次提取组成部分。他的建议也涵盖了 24:8 的情况。

( And everyone else who suggested just static_cast.....what were you thinking? ;) )

(以及其他建议只使用 static_cast 的人......你在想什么?;))

回答by CVertex

I gave the answer to the guy that wrote the best answer, but I really used a related questions code that points here.

我把答案给了写最佳答案的家伙,但我确实使用了指向此处的相关问题代码。

It used templates and was easy to ditch dependencies on the boost lib.

它使用模板并且很容易摆脱对 boost 库的依赖。

回答by bugmagnet

This is fine for converting from floating point to integer, but the O.P. also wanted fixed point.

这对于从浮点数转换为整数很好,但 OP 也需要fixed point

Now how you'd do that in C++, I don't know (C++ not being something I can think in readily). Perhaps try a scaled-integer approach, i.e. use a 32 or 64 bit integer and programmatically allocate the last, say, 6 digits to what's on the right hand side of the decimal point.

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

回答by workmad3

There isn't any built in support in C++ for fixed point numbers. Your best bet would be to write a wrapper 'FixedInt' class that takes doubles and converts them.

C++ 中没有对定点数的任何内置支持。最好的办法是编写一个包装器 'FixedInt' 类,它接受双精度并转换它们。

As for a generic method to convert... the int part is easy enough, just grab the integer part of the value and store it in the upper bits... decimal part would be something along the lines of:

至于转换的通用方法...... 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);
   }
}

although this is likely to contain bugs still

虽然这可能仍然包含错误