使用无符号整数需要浮点精度

时间:2013-12-11 13:28:51

标签: c floating-point integer

然而,我正在使用没有浮点精度空间的微芯片。我需要考虑一些方程式中的小数值。到目前为止,我已经运气好了使用旧的* 100 - > / 100方法如下:

increment = (short int)(((value1 - value2)*100 / totalSteps));

// later in the code I loop through the number of totolSteps
// adding back the increment to arrive at the total I want at the precise time
// time I need it. 
newValue = oldValue + (increment / 100);

这适用于0-255之间的值除以最多300的totalSteps。在300之后,小数点右边的小数值变得很重要,因为它们会随着时间的推移而累加。

我很好奇是否有人有更好的方法在整数范式内保存小数精度?我尝试使用* 1000/1000,但这根本不起作用。

提前谢谢你。

5 个答案:

答案 0 :(得分:2)

带整数的分数称为定点数学。

尝试谷歌搜索“固定点”。

固定点提示和技巧超出了SO答案的范围......

示例:5点击FIR滤波器

// C是使用2.8固定精度的滤波器系数。 // 2 MSB(10)是整数部分,8 LSB(10)是分数部分。 //这里的实际分数精度是1/256。

int FIR_5(int* in,    // input samples
          int inPrec, // sample fraction precision
          int* c,     // filter coefficients
          int cPrec)  // coefficients fraction precision
{
    const int coefHalf = (cPrec > 0) ? 1 << (cPrec - 1) : 0; // value of 0.5 using cPrec
    int sum = 0; 
    for ( int i = 0; i < 5; ++i )
    {
        sum += in[i] * c[i];
    }

    // sum's precision is X.N. where N = inPrec + cPrec;
    // return to original precision (inPrec)
    sum = (sum + coefHalf) >> cPrec; // adding coefHalf for rounding
    return sum;
}

int main()
{
    const int filterPrec = 8;
    int C[5] = { 8, 16, 208, 16, 8 }; // 1.0 == 256 in 2.8 fixed point. Filter value are 8/256, 16/256, 208/256, etc.
    int W[5] = { 10, 203, 40, 50, 72}; // A sampling window (example)
    int res = FIR_5(W, 0, C, filterPrec);
    return 0;
}

备注:

在上面的例子中:

  • 样本是整数(无分数)
  • coefs的分数为8位。
  • 8位分数意味着1的每个变化都被视为1/256。 1 << 8 == 256
  • 有用的表示法是Y.Xu或Y.Xs.其中Y是为整数部分分配了多少位,为分数分配了X. u / s表示签名/未签名。
  • 当乘以2个定点数时,它们的精度(分数位的大小)相互相加。
  • 实施例A为0.8u,B为0.2U。 C = A * B。 C为0.10u
  • 分割时,使用移位操作降低结果精度。转移量取决于您。在降低精度之前,最好添加half以降低错误。
  • 示例:A = 129,0.8u,略高于0.5(129/256)。我们想要整数部分,所以我们将其右移8.在此之前我们想要添加half,其为128(1 <&lt; 7)。所以A =(A + 128)>&gt; 8 - &gt; 1。
  • 如果不添加一半,您将在最终结果中收到更大的错误。

答案 1 :(得分:1)

不要使用这种方法。

新范例:不要使用FP数学或定点数学累积。使用整数数学进行累积和其他方程式。任何时候你需要获得一些缩放值,除以你的比例因子(100),但用原始的,未缩放的值做“加起来”部分。

答案 2 :(得分:1)

如果您真的无法在每一步直接插值,那么可以快速尝试插值的精确理性(Bresenham-esque)版本。

div_t frac_step = div(target - source, num_steps);
if(frac_step.rem < 0) {
    // Annoying special case to deal with rounding towards zero.
    // Alternatively check for the error term slipping to < -num_steps as well
    frac_step.rem = -frac_step.rem;
    --frac_step.quot;
}

unsigned int error = 0;

do {
    // Add the integer term plus an accumulated fraction
    error += frac_step.rem;
    if(error >= num_steps) {
        // Time to carry
        error -= num_steps;
        ++source;
    }
    source += frac_step.quot;
} while(--num_steps);

与定点解决方案相比,一个主要缺点是,如果您使用该函数以不同的步长连续走向移动目标,则小数项在迭代之间得到舍入。

哦,为了记录,您的原始代码似乎没有在步进时正确累积分数,例如无论步数采取多少次,在加法中总是将1/100增量截断为0。相反,你真的想要将增量添加到更高精度的定点累加器,然后在每次迭代时将其除以100(或者最好是右移以除以2的幂),以便计算整数“位置”。

请注意计算中所需的不同整数类型和范围。乘以1000将溢出16位整数,除非一个项是long。完成计算并跟踪每一步的输入范围和余量,然后选择要匹配的整数类型。

答案 3 :(得分:0)

也许你可以通过保存来模拟浮点行为 它使用IEEE 754规范

因此,您将mantisse,exponent和sign保存为unsigned int值。

对于计算,您使用然后按位添加mantisse和exponent等等。 乘法和除法可以通过按位加法运算替换。

我认为很多编程人员都会模仿,但它应该有用。

答案 4 :(得分:0)

您选择的类型是问题:short int可能是16位宽。这就是为什么大型乘法器不起作用的原因 - 你被限制在+/- 32767。假设您的编译器支持它,请使用32位long int。顺便说一下,它是什么芯片,以及什么编译器?