【问题标题】:Converting SIGNED fractions to UNSIGNED fixed point for addition and multiplication将有符号分数转换为无符号定点以进行加法和乘法运算
【发布时间】:2015-12-07 02:54:44
【问题描述】:

我们如何将浮点数转换为它们的“定点表示”,并在加法和乘法等定点运算中使用它们的“定点表示”?定点运算的结果在转换回浮点时必须产生正确的答案。

说:

(double)(xb_double) + (double)(xb_double) = ?

然后我们将两个加数转换为定点表示(整数),

(int)(xa_fixed) + (int)(xb_fixed) = (int) (xsum_fixed)

为了得到 (double)(xsum_double),我们将 (int)(sum_fixed) 转换回浮点数并得到相同的答案,

FixedToDouble(xsum_fixed) => xsum_double

具体来说,如果 xa_double 和 xb_double 的取值范围在 -1.65 和 1.65 之间,我想将 xa_double 和 xb_double 转换为各自的 10 位定点表示形式(0x0000 到 0x03FF)

我已经尝试过什么

int fixed_MAX = 1023;
int fixed_MIN = 0;
double Value_MAX = 1.65;
double Value_MIN = -1.65;

double slope = ((fixed_MAX) - (fixed_MIN))/((Value_MAX) - (Value_MIN));

int DoubleToFixed(double x)
{
return round(((x) - Value_MIN)*slope + fixed_MIN); //via interpolation method
}

double FixedToDouble(int x)
{
return (double)((((x) + fixed_MIN)/slope) + Value_MIN);
}

int sum_fixed(int x, int y)
{
    return (x + y - (1.65*slope)); //analysis, just basic math
}

int subtract_fixed(int x, int y)
{
    return (x - y + (1.65*slope));
}

int product_fixed(int x, int y)
{
    return (((x * y) - (slope*slope*((1.65*FixedToDouble(x)) + (1.65*FixedToDouble(y)) + (1.65*1.65))) + (slope*slope*1.65)) / slope);
}

如果我想添加 (double)(1.00) + (double)(2.00) = 这应该产生 (double)(3.00),

使用我的代码,

xsum_fixed = DoubleToFixed(1.00) + DoubleToFixed(2.00);
xsum_double = FixedToDouble(xsum_fixed);

我得到了答案:

xsum_double = 3.001613

非常接近正确答案(双)(3.00)

另外,如果我执行乘法和减法,我分别得到 2.004839 和 -1.001613。

问题来了:

所以我知道我的代码可以正常工作,但是如何在没有内部浮点运算和数字的情况下对这些定点表示执行加法、乘法和减法。

所以在上面的代码中,函数sum_fixed、product_fixed 和subtract_fixed 具有内部浮点数(斜率和1.65,1.65 是最大浮点输入)。我是通过基本数学推导出我的代码的,真的。

所以我想在没有任何内部浮点运算或数字的情况下实现加法、减法和乘积函数。

更新:

我还发现了一个更简单的将小数转换为定点的代码:

//const int scale = 16; //1/2^16 in 32 bits

#define DoubleToFixed(x) (int)((x) * (double)(1<<scale))
#define FixedToDouble(x) ((double)(x) / (double)(1<<scale))
#define FractionPart(x) ((x) & FractionMask)

#define MUL(x,y) (((long long)(x)*(long long)(y)) >> scale)
#define DIV(x, y) (((long long)(x)<<16)/(y)) 

但是,这只会将 UNSIGNED 分数转换为 UNSIGNED 定点。我想将有符号分数(-1.65 到 1.65)转换为无符号定点(0x0000 到 0x03FF)。如何使用上面的代码来做到这一点?位的范围或数量是否与转换过程有关?此代码仅适用于正分数吗?

感谢@chux

【问题讨论】:

  • 为什么我的问题中有-1?你们这些人怎么了!
  • @chux 是的!应该是负数!
  • @chux 你的转换是正确的,但是你不能直接添加这些定点值来产生正确的答案。此外,我的 add 函数涉及内部浮点运算和数字。
  • 对不起,我不是 Utube,(太旧了),但同一页上的这个看起来像你应该看到的一个 Into to floating point 列出的所有其余视频都是 @987654329 @ 并且没有一个是 conversion from floating point to fixed point`。
  • 这真的取决于你在做什么。如果您从 浮点值 开始,并且想要对这些位执行 anything 并希望在 中获得有意义的 anything >floating point 值与原始 floating point 值有 任何 关系 - 那么是的,您必须涉足所有这些 MUCK。 (这可能就是为什么你没有找到任何关于你正在尝试做的事情的方便视频的原因——不是吗?)

标签: c floating-point signal-processing fixed-point


【解决方案1】:

您可以让数字的浮点表示的尾数等于其定点表示。由于 FP 加法会移动较小操作数的尾数,直到两个操作数具有相同的指数,您可以添加某个“幻数”来强制它。对于双精度,它是 1

union { double f; long long i; } u = { xfloat+(1ll<<52-precision) }; // shift x's mantissa
long long xfixed = u.i & (1ll<<52)-1; // extract the mantissa

之后,您可以在整数数学中使用 xfixed(对于乘法,您必须将结果右移“精度”)。要将其转换回双精度,只需将其乘以 1.0/(1

请注意,它不处理负数。如果您需要它们,则必须手动将它们转换为互补表示(首先制造双精度,然后如果输入为负数,则否定 int 结果)。

【讨论】:

  • 您能进一步解释一下您的代码吗?我不太明白。简而言之,我需要做什么才能执行整数运算?我的范围是 -1.65 到 1.65,我必须将它转换为从 0x0000 到 0x03FF 的 10 位无符号整数。我仍然没有得到浮点表示(尾数、有符号位、指数)
  • 1ll
  • 你能把 cmets 告诉你代码的哪些部分吗?
  • 你必须决定你想要多少个固定精度数字。由于您的范围是 1.65*2=3.3,因此您需要为整数部分保留至少 2 位,因此您的固定数字将为 2.8(即公式中的精度 = 8)。如果您的范围 > 0,您可以直接在整数数学中使用 xfixed。对于负范围,您必须将 1.65 添加到 xfloat。 + 和 - 仍然可以工作,但 *
  • 我的代码将 double 转换为 2.8 固定(除了将 xfloat 替换为 xfloat+1.65,因为您需要底片)。 i 和 f 只是为了访问 double 的二进制表示
猜你喜欢
  • 2019-11-12
  • 2013-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-30
  • 1970-01-01
  • 2016-02-17
相关资源
最近更新 更多