3

私は以下を最適化しようとしています。以下のコードはこれを行います:

a = 0.775 で精度 2 dp が必要な場合、a => 0.78

基本的に、最後の桁が 5 の場合は次の桁を切り上げますが、そうでない場合は切り上げません。

私の問題は、値が 0.44999999343.... として保存され、setprecision が 0.4 に丸められるため、0.45 が小数点 1 で 0.5 に丸められないことでした。

そのため、setprecision をより高くする必要がsetprecision(p+10)あり、実際に 5 で終わる場合は、正しく切り上げるために少量を追加します。

完了すると、a と文字列 b を比較し、結果を返します。問題は、この関数が数十億回呼び出され、プログラムがクロールすることです。これを書き換え/最適化する方法と、コード内のどの機能がマシンに非常に重いかについて、より良いアイデアはありますか?

bool match(double a,string b,int p) { //p = precision no greater than 7dp

    double t[] = {0.2, 0.02, 0.002, 0.0002, 0.00002, 0.000002, 0.0000002, 0.00000002};

    stringstream buff;
    string temp;

    buff << setprecision(p+10) << setiosflags(ios_base::fixed) << a; // 10 decimal precision
    buff >> temp;

    if(temp[temp.size()-10] == '5')  a += t[p]; // help to round upwards

    ostringstream test;
    test << setprecision(p) << setiosflags(ios_base::fixed) << a;
    temp = test.str();

    if(b.compare(temp) == 0) return true;

    return false;
}
4

9 に答える 9

2

100 分の 1 の精度には 0.005、1000 分の 1 には 0.0005 を追加するだけでよいと思います。結果を "%1.2f" (100 分の 1、1.3f の 1000 分の 1 など) のように snprintf し、文字列を比較します。このロジックをテーブル化またはパラメータ化できるはずです。

于 2009-07-16T18:51:39.520 に答える
2

数値の目的によっては、浮動小数点数の代わりに固定小数点数を使用したい場合があります。クイック検索でこれが見つかります

于 2009-07-16T18:37:31.810 に答える
2

私は数十行の ASM だけで整数の平方根サブルーチンを書き、API 呼び出しはまったくありませんでしたが、それでも 1 秒あたり約 5,000 万 SqRoots しか実行できませんでした (これは約 5 年前のことです...)。

私が言いたいのは、何十億もの通話を行おうとすると、今日のテクノロジーでさえ窒息するということです.

しかし、本当に高速化する努力をしたい場合は、可能な限り多くの API の使用を削除してください。これにより、API タスクをライブラリに任せるのではなく、手動で実行することが必要になる場合があります。具体的には、あらゆる種類のストリーム操作を削除します。このコンテキストでは、それらはダートよりも遅いです。あなたは本当にそこで即興しなければならないかもしれません。

あとは、できる限り多くの C++ 行をカスタム ASM に置き換えるだけですが、それについては完璧主義者になる必要があります。すべての CPU サイクルとレジスタ、および CPU キャッシュとスタック空間のすべてのバイトを最大限に活用していることを確認してください。

浮動小数点の代わりに整数値を使用することを検討してください。整数値の方がはるかに ASM にやさしく、はるかに効率的です。小数を右端まで移動するには、数値に 10^7 (ロジックの作成方法によっては 10^p) を掛ける必要があります。次に、浮動小数点を基本整数に安全に変換できます。

残りの作業は、コンピュータ ハードウェアに依存する必要があります。

<--Microsoft Specific-->
また、C++ 識別子 (Donnie DeBoer が言及した静的識別子を含む) は、C++ コードにネストされた ASM ブロックから直接アクセスできることも付け加えます。これにより、インライン ASM が簡単になります。
<--End Microsoft Specific-->

于 2009-07-16T18:44:03.700 に答える
2

二重の t[] を静的にするだけで、投稿されたコードのいくつかの主要なサイクルを節約できるため、何度も割り当てられることはありません。

于 2009-07-16T19:06:01.800 に答える
1

代わりにこれを試してください:

#include <cmath>

double setprecision(double x, int prec) {
    return 
        ceil( x * pow(10,(double)prec) - .4999999999999)
        / pow(10,(double)prec);
}

それはおそらく速いです。インライン化も試してみてください。

仕組みの例:

2.345* 100 (10 to the 2nd power) = 234.5
234.5 - .4999999999999 = 234.0000000000001
ceil( 234.0000000000001 ) = 235
235 / 100 (10 to the 2nd power) = 2.35

.4999999999999 が選択されたのは、32 ビット システムでの c++ double の精度のためです。64 ビット プラットフォームを使用している場合は、おそらくさらに 9 が必要になります。32 ビット システムでさらに 9 を増やすと、オーバーフローして、切り上げではなく切り捨てられます。

于 2009-07-16T19:58:46.013 に答える
1

浮動小数点 (不正確な表現) を使用すると、真の数に関する情報の一部が失われます。ファッジ値を追加して、double に格納されている値を単純に「修正」することはできません。これにより、特定のケース (.45 など) が修正される可能性がありますが、他のケースは壊れます。切り捨てられるべき数値を切り上げることになります。

関連記事はこちら: http://www.theregister.co.uk/2006/08/12/floating_point_approximation/

于 2009-07-16T19:40:51.853 に答える
0

昔の開発者は、古い国のポンド、シリング、ペンスの暗黒時代から騙しています。

秘訣は、半ペニーの整数として値を格納することでした。(またはあなたの最小単位が何であれ)。その後のすべての算術は単純な整数算術であり、丸めなどは自動的に処理されます。

したがって、あなたのケースでは、数えているものの200分の1の単位でデータを保存し、これらの値に対して単純な整数計算を行い、結果を表示したいときはいつでも200で割ってfloat変数にします。

Boostは最近「BigDecimal」ライブラリを実行すると信じていますが、実行時の速度に対する要件により、おそらくこの優れたソリューションが除外されるでしょう。

于 2009-07-20T01:36:03.037 に答える
0

私はあなたが本当に何をしようとしているのか推測しています。文字列に倍精度の 10 進数表現が含まれているかどうかを確認しようとしていると思われます。おそらくそれは算術クイズ プログラムであり、ユーザーの応答が実際の答えに「十分に近い」かどうかを確認しようとしています。その場合は、文字列を double に変換し、2 つの double の差の絶対値が許容範囲内にあるかどうかを確認する方が簡単な場合があります。

double string_to_double(const std::string &s)
{
    std::stringstream buffer(s);
    double d = 0.0;
    buffer >> d;
    return d;
}

bool match(const std::string &guess, double answer, int precision)
{
    const static double thresh[] = { 0.5, 0.05, 0.005, 0.0005, /* etc. */ };
    const double g = string_to_double(guess);
    const double delta = g - answer;
    return -thresh[precision] < delta && delta <= thresh[precision];
}

もう 1 つの可能性は、文字列に変換する前に、最初に (まだ数値である間に) 答えを丸めることです。

bool match2(const std::string &guess, double answer, int precision)
{
    const static double thresh[] = {0.5, 0.05, 0.005, 0.0005, /* etc. */ };
    const double rounded = answer + thresh[precision];
    std::stringstream buffer;
    buffer << std::setprecision(precision) << rounded;
    return guess == buffer.str();
}

これらのソリューションはどちらも、サンプル コードよりも高速であるはずですが、本当に必要なことを実行できるかどうかはわかりません。

于 2009-07-16T22:42:34.857 に答える
0

私が見る限り、pポイントで丸められたaがbに等しいかどうかを確認しています。

aを文字列に変更する代わりに、別の方法で文字列をdoubleに変更します-(乗算と加算のみ、または小さなテーブルを使用した加算のみ)-次に、両方の数値を減算し、減算が適切な範囲内にあるかどうかを確認します(p == 1 => absの場合) (pa) < 0.05)

于 2009-07-20T01:16:26.993 に答える