C浮点到定点转换

xzabzqsa  于 2023-03-07  发布在  其他
关注(0)|答案(3)|浏览(167)

嗨,我正在尝试做一个浮点数和定点数之间的转换器,而不使用任何库函数。到目前为止,定点数是16位,10位是整数部分,6位是小数部分。我一直在谷歌搜索,发现了一个可能的解决方案。

inline fixed_point_t double_to_fixed(double input)
{
    return (fixed_point_t)(input * (1 << FIXED_POINT_FRACTIONAL_BITS));
}

inline double fixed_to_double(fixed_point_t input)
{
    return ((double)input / (double)(1 << FIXED_POINT_FRACTIONAL_BITS));
}

我很难理解它背后的逻辑。有人能帮我解释一下吗?在这种情况下,小数位如何被C截断到只有6位😅

rmbxnbpk

rmbxnbpk1#

这样如何:
样本数量= 123.4567890(基数为10)
仍然以10为基数,用“3个定点小数”表示相同的数字。
要形成该值,请乘以10^3并去掉其余小数。
123.456789 * 1000 =〉整数== 123457(或123_457,其中“_”表示“固定小数点”。)
这是以10为基数转换为固定小数的示例。
很明显,除以1000可以将其反转。(丢失的精度丢失,无法恢复。
现在,不再以10为基数进行运算,而是对以2为基数表示的浮点值(floatdouble)执行同样的操作。
就这么简单。只是程度的问题...

xxhby3vn

xxhby3vn2#

假设你想要一个使用2个小数位的定点类型。

000...0000111  (7 decimal)

代表的是
现在考虑浮点计算

7 / (1 << 2) = 7 / (2^2) = 7 / 4 = 1.75  (where ^ is power-of)

这就是它的工作原理。
通过除以“2的NUMBER-OF-FracCTIONAL-BITS次幂”,可以将定点变量的全整数表示转换为浮点值

3qpi33ja

3qpi33ja3#

来理解它背后的逻辑。
大致如下:
fixed_point_t double_to_fixed(double input):将input乘以26并转换为整数。
double fixed_to_double(fixed_point_t input):转换为double并除以26。
找到了一个可能的解决方案。
以下是一些缺点:

inline fixed_point_t double_to_fixed(double input)
{
    return (fixed_point_t)(input * (1 << FIXED_POINT_FRACTIONAL_BITS));
}
  • "在这种情况下,C如何将小数位截断为6位"--〉是的,input中值小于2 - 6的位将被默默地丢弃。考虑 * 舍入 *。
  • (fixed_point_t)的强制转换,一些整数类型,风险 * 未定义的行为 * 如果input远远超出(fixed_point_t)范围。
  • 1 << FIXED_POINT_FRACTIONAL_BITSFIXED_POINT_FRACTIONAL_BITS > 15启动时出现问题。请为1使用大小合适的类型。
  • 由于要处理上面的附加代码,可能需要删除inline

示例:

#include <errno.h>
#include <stdint.h>

#define FIXED_POINT_FRACTIONAL_BITS 6
typedef int16_t fixed_point_t;
#define FIXED_POINT_I_MAX INT16_MAX
#define FIXED_POINT_I_MIN INT16_MIN
// Use the right width type for forming constants.
#define FIXED_POINT_C INT16_C

fixed_point_t double_to_fixed(double input) {
  input *= FIXED_POINT_C(1) << FIXED_POINT_FRACTIONAL_BITS;
  // Round ties away from zero by adding 0.5. (Other rounding modes possible.)
  // Works OK when the sum is exact.
  input += (input < 0) ? -0.5 : 0.5;

  // Avoid this form as FIXED_POINT_I_MAX + 1 may wrap
  // if (input >= (FIXED_POINT_I_MAX + 1)) {
  if (input >= (FIXED_POINT_I_MAX/2 + 1)*2.0) {
    errno = ERANGE;
    return FIXED_POINT_I_MAX;
  }

  // Avoid this form as FIXED_POINT_I_MIN - 1 as a FP may be inexact
  // if (input <= (FIXED_POINT_I_MIN - 1)) {
  if (input - FIXED_POINT_I_MIN <= -1) {
    errno = ERANGE;
    return FIXED_POINT_I_MIN;
  }

  return (fixed_point_t)input;
}

double fixed_to_double(fixed_point_t input)基本上是可以的。当固定点的精度(OP的情况下为6)超过double(53)时,这是一个问题。

相关问题