自作のグラフソフトでバグが見つかった。
以下の計算において、majorTickIncrement = 0.5, minorTickIncrement = 0.1の時に以下の計算が結果minorTickCount が3になる(本来は4)。
int minorTickCount = axisPtr->majorTickIncrement / axisPtr->minorTickIncrement - 1;
詳細を見ていくと minorTickIncrement (フォーム入力)の値は0.1と入力した値が 0.100000001490116 になっている。
この誤差と割り算の仕組みにより 3 になるようだ。
(ちなみに 5.000... / 1.0.... - 1)の計算は4になり上記と様相が異なる。
対応1 > FLT_EPSILON
FLT_EPSILON分の誤差がminorTickIncrement に含まれたのかと思い以下のようにしたらきちんと4になった。
ただし、このあたりは詳細に見ていかないといけないだろう。
#include <float.h>
...
float fval1 = axisPtr->majorTickIncrement;
float fval2 = axisPtr->minorTickIncrement;
fval2 = fval2 - FLT_EPSILON;
int minorTickCount = fval1 / fval2 - 1;
上記のコードでFLT_EPSILONを引かさない計算では3になる。
floatは7桁の精度だったと思うが、なぜ3になるかは未消化。
ideoneで確認
http://ideone.com/ftpjlB
で確認したところ 4 になる。
C++ Builderのコンパイラの問題なのだろうか。
対応2 > std::lround() / SimpleRoundTo()
@termoshtt さんに std::lround()があるという情報をいただいた。
XE4でinclude <cmath>
を追加してstd::lround()
を使おうとしたが、エラーのため使用できなかった。
lround()をキーとして検索するとXE4では SimpleRoundTo()
という関数が近い処理をしているようだ。
以下はきちんと4になった。
float fval1 = axisPtr->majorTickIncrement;
float fval2 = axisPtr->minorTickIncrement;
int cnt3 = SimpleRoundTo(fval1 / fval2 - 1.0);
int nop=1; // for breakpoint
こちらもでいいだろう。
int cnt3 = SimpleRoundTo(fval1 / fval2) - 1;