2012-04-02 7 views
1

のない精度を高めることができる今、私は次のようにやっている:は、どのように私は山車C

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

floatまたはdoubleを使用せずに、これをより正確に行うにはどうすればよいでしょうか。最も重要なのはですコードサイズを大きくしすぎることはありません。

種類よろしく Sonite

+0

私はuint24_tを持っているので、ManualFlow * 10をManualflow * 100に増やすことになります。それははるかに正確になります。 "1000" * 10/6 * "100"/100 * 414 = 689724 – Christian

+0

あなたはそこにビットを無駄にしています...あなたがuint8_tとuint24_tを持っているなら、 uint8_tを16ビットだけ増やします。これは100倍に比べて約600倍正確で、ビットシフトに比べてはるかに高速ですが、乗算は非常に高価です。 –

答えて

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 

他にも役立つことを願っています。

種類よろしく Sonite

0

乗算、すべての例えば、 (1 < < 8)をより大きなデータ型に変換し、必要な数式を実行してから、答えを(1 < < 8)で割ります。

1

あなたは結果がオーバーフローし、分裂する前に、乗算のすべてを行うことはありませんと確信している場合:あなたは整数精度よりも多くを必要とするが、浮動小数点を回避したい場合

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

fixed-point arithmeticを使用することを検討してください代わりに。

+0

ああ...それは近いです。私がここで持つことができる最大の価値は、400 *(100)* 414 /(6 * 14)= 16560000です。あなたが言うように、それはオーバーフローしないことを確実にしなければなりません。 もう一度お伺いします。 – Christian

1

(浮動小数点ではなく)固定小数点演算を指しています。整数のサイズを常にuint64_tのようなものに増やし、10を掛けて希望の精度を達成することができます。

しかし、私はベース2の固定小数点を使用することをお勧めします(つまり、一定の乗数に10を乗算するのではなく、特定のビット数だけ左にシフトすること)。それは(はるかに)速く、より正確にすることができます。

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 

注:これはあまりで読み取り可能なコードであるが、これは、パフォーマンスが重要なアルゴリズムであれば、この最適化は(控えめに)使用することができます。