質問: ((dividend * MILLION_TIMES) / divisor)-(integer * MILLION_TIMES) ; // 商に除数をかければ被除数になる printf("[double]\n"); printf("%d / %d =%lf\n", dividend, divisor, dDiv); printf("%f * %d =%lf\n", dDiv, divisor, dDiv*divisor); printf("\n"); printf("[int]\n"); printf("%d / %d =%d.%06d\n", dividend, divisor, integer, idec); printf("%d.%d * %d =%d\n", integer, idec, divisor, divisor*integer+(divisor*idec)/ MILLION_TIMES); return 0; } ``` > > [double] > > 87 / 31 =2.806452 > > 2.806452 * 31 =87.000000 > > > [int] > > 87 / 31 =2.806451 > > 2.806451 * 31 =86 > > > これ以外にも負数の場合の動作も考える必要があって悩んでいます。 これ以上は無理なのでしょうか?
回答: こんにちは。 組込みの場合は、浮動小数点計算負荷が許容できないケースが多いですね。 そのような時は、固定小数点を良く使います。掲示されてるソースは正に固定小数点処理です。 端数がうまくあわないのは丸め処理の問題です。0.999999999でも切り捨てると0です。本来丸めて1にしたいところです。浮動小数点処理はこのような丸め処理をしています。 > > divisor*integer+(divisor*idec)/ MILLION_TIMES > > > は、下記処理でお手軽な四捨五入になります。 > > (divisor*integer+(divisor*idec) + MILLION_TIMES/2)/ MILLION_TIMES > > > 負の数では妥当ではない気もしますので、良く検討下さい。 (負の数の四捨五入を考え出すと、丸め処理は様々な考え方があるので頭痛いです。) 【追記】 書こうと思いつつ忘れてました。 小数点位置を10進数で決めると計算が重くなるし、オーバーフローするしないの桁数が曖昧になるので、2進数で決めると良いです。固定小数点処理をシフト演算で済ませられるので高速なのです。なれない2進数で検討するのは少したいへんですが、10進数変換誤差がない分 楽ですよ。