1

现在我正在做如下:

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).

我怎样才能在不使用floats 或doubles 的情况下更准确地做到这一点,最重要的是不要过多地增加我的代码大小。

亲切的问候 索尼特

4

6 回答 6

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

于 2012-04-02T21:52:02.293 回答
1

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

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

如果您需要的不仅仅是整数精度,但又想避免使用浮点数,请考虑改用定点算法

于 2012-04-02T21:54:19.310 回答
1

您指的是定点算术(与浮点相反)。您始终可以将整数的大小增加到 uint64_t 之类的大小,然后乘以 10 以上以达到所需的精度。

但是,我建议使用以 2 为底的定点(即左移一定数量的位,而不是乘以 10 的某个幂)。它(快得多)并且可以更准确。

于 2012-04-02T21:55:24.957 回答
0

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

于 2012-04-02T21:52:43.650 回答
0

结论:

我最初的代码没有那么好的准确性,而且“这么大”。

通过在下面执行此操作,我用“38 字节”增加了代码并获得了更好的准确性

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

我通过定点获得的最佳精度,但它将代码增加到“1148字节->

// 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

希望它可以帮助别人!

亲切的问候 索尼特

于 2012-04-03T09:37:19.900 回答
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

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

于 2012-05-04T03:22:17.313 回答