2

あらゆる浮動小数点型で動作するように設計されたテンプレートクラスを作成しています。いくつかの方法では、数値をその整数部分と小数部分に分割する必要があります。プリミティブ浮動小数点型では、整数にキャストして小数部分を切り捨てることができますが、これは大きな数のクラスでは機能しません。理想的には、私のクラスは、計算に4つの基本的な算術演算(加算、減算、乗算、除算)のみを使用します。

以下の方法は私が思いついた解決策です。元の数が1未満になるまで、10の累乗を引くだけです。これはうまく機能しますが、ブルートフォースアプローチのように見えます。これを行うためのより効率的な方法はありますか?

template< typename T >
class Math
{
    public:

    static T modf( T const & x, T & intpart )
    {
        T sub = 1;
        T ret = x;

        while( x >= sub )
        {
            sub *= 10;
        }

        sub /= 10;

        while( sub >= 1 )
        {
            while( ret >= sub )
            {
                ret -= sub;
            }

            sub /= 10;

        }//while [sub] > 0

        intpart = x - ret;

        return ret;
    }
}

簡潔にするために、サイン管理コードを削除したことに注意してください。

4

3 に答える 3

2

おそらく、減算ループを二分探索に置き換えることができますが、それは複雑さのクラスの改善ではありません。

あなたが持っているものは、 の10進数の合計にほぼ等しい数の減算を必要としますがx、バイナリ検索では、数値の3ビット倍にほぼ等しい数の加算と2で除算の操作が必要です。の 10 進数字のx.

あなたがしていることと二分探索では、上限を探すときに 10 の累乗を使用する特別な理由はありません。任意の数を使用できます。おそらくタイプにもよりますが、他の数値は平均して少し速いかもしれませんT

ところで、クラス テンプレートではなく、関数テンプレート (または名前空間modf内の無料のテンプレート関数) を作成することもできます。こうすることで、全体を特殊化することなく、特定の型 (特に組み込み型) に対して一度に 1 つの関数を特殊化またはオーバーロードできます。MathMathMath

例:

namespace Math
{
    template <typename T>
    T modf( T const & x, T & intpart )
    { ... }
}

次のように呼び出します。

float f = 1.5, fint;
std::cout << Math::modf(f, fint) << '\n';

double d = 2.5, dint;
std::cout << Math::modf(d, dint) << '\n';

mpf_class ff(3.5), ffint(0);  // GNU multi-precision
std::cout << Math::modf(ff, ffint) << '\n';

次のようにオーバーロードします。

namespace Math {
    double modf(double x, double &intpart) {
        return std::modf(x, &intpart);
    }

    mpf_class modf(const mpf_class &x, mpf_class &intpart) {
        intpart = floor(x);
        return x - intpart;
    }
}
于 2012-07-04T09:24:08.953 に答える
0

mb use std :: modfの方がいいですか?カスタムタイプの場合、Mathクラスの特殊化をリリースできます。

#include <cmath>
#include <iostream>

template<typename T>
class Math
{
public:
    static T modf(const T& x, T& integral_part)
    {
        return std::modf(x, &integral_part);
    }
};

int main()
{
    double d_part = 0.;
    double res = Math<double>::modf(5.2123, d_part);
    std::cout << d_part << " " << res << std::endl;
}
于 2012-07-04T09:19:19.733 に答える
0

「理想的には数学演算のみを使用する」という制限がどれほど厳しいかはわかりませんが、それでも小数部分については、文字列に抽出して浮動小数点数に戻すことができますか?

于 2012-07-04T09:23:54.053 に答える