4

私はいくつかのフロート操作を行っており、最終的に次の数字になります。

-0.5
-0.4
-0.3000000000000000004
-0.2000000000000000004
-0.1000000000000000003
1.10E-16
0.1
0.2
0.30000000000000000004
0.4
0.5

アルゴリズムは次のとおりです。

var inc:Number = nextMultiple(min, stepSize);
trace(String(inc));

private function nextMultiple(x:Number, y:Number) {
    return Math.ceil(x/y)*y;
}

フロートが常にバイトで正確に表現できるとは限らないという事実を理解しています。例: 1/3。ステップサイズが 0.1 であることも知っています。ステップサイズがある場合、どうすれば適切な出力を得ることができますか?

奇妙なことに、この種の問題に遭遇したのは初めてです。多分私はフロートで十分に遊んでいません。

4

10 に答える 10

8

言語にとらわれない解決策は、浮動小数点数ではなく、ステップ サイズがわかっている場合、数値を整数のステップ数として格納することです。

言語にとらわれない解決策は、言語のprintfの実装が何であるかを調べることです。

printf ("float: %.1f\n", number);
于 2008-12-08T17:33:01.093 に答える
3

ご存じのとおり、2 進数の浮動小数点精度の制限が問題です。これを回避する 1 つの方法は、浮動小数点演算を行わないことです。問題を整数に変換してから、出力に戻します。

于 2008-12-08T17:30:33.547 に答える
1

ラウンド関数を持つ言語を使用している場合は、それを使用できます。

編集

丸めに関するコメントに応えて、C# のサンプルを次に示します。

float value = 1.0F;

for (int i = 0; i < 20; i++)
{
    value -= 0.1F;
    Console.WriteLine(Math.Round(value, 1).ToString() + " : " + value.ToString());
}

結果は次のとおりです。

0.9 : 0.9

0.8 : 0.8

0.7 : 0.6999999

0.6 : 0.5999999

(等)

丸めは精度の問題を解決します。整数演算を行ってから 10 で割るよりも優れていると主張しているわけではなく、それが機能するというだけです。

于 2008-12-08T17:32:34.540 に答える
1

浮動小数点型の代わりに整数を使用するか、「ポイント」が小数点である浮動小数点型を使用します (.NET のSystem.Decimalなど)。

于 2008-12-08T17:33:14.383 に答える
0

数値をスケーリングして整数を取得し、数学を実行して、表示用に浮動小数点数にスケールバックするだけです。

//これは小数点以下3桁に丸められます
var NUM_SCALE = 1000;

関数scaleUpNumber(n){
    return(Math.floor(n * NUM_SCALE));
}
関数scaleDnNumber(n){
    return(n / NUM_SCALE);
}


var answ = scaleUpNumber(2.1) - scaleUpNumber(3.001);
alert(scaleDnNumber(answ)); // displays: -0.901

Change NUM_SCALE to increase/decrease decimap places

|/|ax

于 2008-12-21T11:46:58.753 に答える
0

printfがない場合、またはステップが10の累乗ではない場合(たとえば、0.2に最も近い値に丸めたい場合)、量子化器が必要なように聞こえます。

q(x、u)= u * floor(x / u + 0.5);

「u」はステップサイズ(この場合は0.1)であり、floor()は入力以下の最大の整数を検出し、「+0.5」は最も近い整数に丸めます。

したがって、基本的には、ステップサイズで除算し、最も近い整数に丸めて、ステップサイズを乗算します。

編集:ああ、気にしないでください、とにかく基本的にそれをやっていて、それがuで乗算されるステップは丸め誤差を導入しています。

于 2008-12-11T19:52:00.903 に答える
0

特定の問題では、実際に値を何かに使用する前に、-5 から 5 まで数えて 10 で割ります。

于 2008-12-08T17:32:46.617 に答える
0

これは少し直感に反しますが、テストしたところ動作します (AS3 の例):

var inc:Number = nextMultiple(min, stepSize);
trace(String(inc));

private function nextMultiple(x:Number, y:Number) {
    return Math.ceil(x/y)*(y*10)/10;
}

したがって、私が追加した唯一のことは、10 を掛けてyから 10 で割ることです。普遍的な解決策ではありませんが、stepSize で機能します。

[編集:] ここでのロジックは、最後の 10 進数が「目盛りから外れる」ように十分大きな数を掛けてから、再度除算して丸められた数を取得するようです。そうは言っても、上記のMath.round()を使用する例は、コードが渡された数値に何が起こるかを明示的に示しているという意味で、より読みやすく、より優れています。

于 2008-12-31T15:54:14.660 に答える
0

言語がサポートしている場合は、Decimal データ型を使用することをお勧めします。この正確な問題に対処するために、多くの言語に 10 進数が追加されました。

于 2008-12-31T15:57:51.363 に答える
0

私は次のことをしました、

var digitsNbr:Number = Math.abs(Math.ceil(((Math.log(stepSize) / Math.log(10))) + 1));      
tickTxt.text = String(inc.toPrecision(digitsNbr));

効率的ではありませんが、多くの手順はありません。

====== ステップの nbr を int として取得し、ステップで乗算する必要があります ...

于 2008-12-08T21:32:40.360 に答える