如何在没有浮点数C的情况下提高准确度

时间:2012-04-02 21:49:59

标签: c int microchip

现在我正在做如下:

uint8_t ManualFlow = 40; // 0 -> 255     Unsigned Char

uint24_t ME; // 0 -> 16777215 Unsigned Short Long
ME = (uint24_t) ManualFlow*10; // Have to make this hack otherwise malfunction in calculation
ME /= 6;
ME *= (80 - 60);
ME /= 100;
ME *= 414;

最终结果:

40*10 = 400
400/6 = 66
66*20 = 1320
1320/100 = 13
13*414 = 5382

我喜欢的与此类似:

4/60 = 0,0667 * 20 * 4188 * 0,998 = 5576 (more accurate).

如何在不使用floatdouble的情况下更准确地执行此操作,最重要的是 不要太多地增加我的代码大小。

亲切的问候 Sonite

6 个答案:

答案 0 :(得分:4)

您可能需要查看定点运算:

http://en.wikipedia.org/wiki/Fixed-point_arithmetic

来自WG14的18037技术报告(遗憾的是ISO / IEC TR 18037:2008的最新版本不是免费的):

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf

答案 1 :(得分:1)

如果您确定结果永远不会溢出,请在分割之前进行所有乘法运算:

uint24_t ME;
ME = (uint24_t)ManualFlow*10;
ME *= (80 - 60);
ME *= 414;
ME /= (6 * 14);

如果您需要超过整数精度但希望避免浮点,请考虑改为使用fixed-point arithmetic

答案 2 :(得分:1)

您指的是定点算术(与浮点相对)。您总是可以将整数的大小增加到类似uint64_t的值并乘以10以上以获得所需的精度。

但是,我建议使用base-2固定点(即向左移动一定数量的位而不是乘以10到某个功率)。 (更快)它可以更准确。

答案 3 :(得分:0)

将所有输入相乘,例如(1 <&lt; 8)进入更大的数据类型,然后执行所需的数学运算,然后将答案除以(1 <&lt; 8)。

答案 4 :(得分:0)

结论:

我的初始代码没有那么好的准确性而且“很大”。

通过这样做,我用“38字节”增加了代码并获得了更好的准确性

ME = (uint24_t) ManualFlow*100;
ME /= 6;
ME *= (Port[2].AD - Port[3].AD);
ME /= 100;
ME *= 414;
ME /= 10;

我通过固定点获得的最佳准确度,但它将代码增加到“1148字节 - &gt;

// Utility macros for dealing with 16:16 fixed-point numbers
#define I2X(v) ((int32_t) ((v) * 65536.0 + 0.5))    // Int to Fix32
#define X2I(v) ((int16_t) ((v) + 0x8000 >> 16))     // Fix to Int

ME = I2X(ManualFlow*10); //400 * 65536.0 + 0.5 =   26214400
ME = I2X(ME/6); // 26214400 / 6 = 4369066
ME = I2X(ME * 20); // = 87381320
ME = I2X(ME / 100); // = 873813
ME = I2X(ME * 414); // 361758582
ME = X2I(ME); // 158FFF76 + 8000 >> 16 15907F76 >> 16 = 5520

希望它可以帮助其他人!

亲切的问候 Sonite

答案 5 :(得分:0)

对于原版海报,我可能有点迟,但对于后人,还应该注意的是,当速度对于小型处理器来说非常关键时,通常也可以避免定点分割。通过变量进行划分通常是不可避免的,但是人们可以(几乎)总是使用乘法和移位来代替除以常数,这会占用许多处理器周期,特别是对于大于小处理器数据宽度的类型。而不是

uint16_t x = somevalue;  //somevalue known to be between 0 and 65535
x /= 107;

您可以使用:

uint32_t x = somevalue;
x *= 39199;  //chosen to be 2^n/107
             //n chosen to maximum value without exceeding 65536
x >>= 22;    //n = 22 in this case

注意:这是不太可读的代码,但如果这是一个性能至关重要的算法,则可以使用(谨慎)此优化。