web-dev-qa-db-ja.com

size_tをdoubleまたはint C ++にキャストする方法

私の質問は

Size_tデータがありますが、今度はそれをdoubleまたはintに変換します。

私が何かをするなら

 size_t data = 99999999;
 int convertdata = data;

コンパイラーは警告を報告します。多分オーバーフローするからです.

ブーストなどの方法や変換を行う他の方法はありますか?

35
user2701639

キャスト、 Blaz Bratanicが提案したように

size_t data = 99999999;
int convertdata = static_cast<int>(data);

は、警告を黙らせる可能性があります(ただし、キャストがあったとしても、原則としてコンパイラは好きなものについて警告できます)。

しかし、警告があなたに伝えていた問題、つまりsize_tからintへの変換が実際にオーバーフローする可能性があるという問題は解決しません。

可能な場合は、size_t値をintに変換する必要がないようにしないようにプログラムを設計してください。それをsize_t変数に格納し(既に行ったように)、それを使用します。

doubleに変換してもオーバーフローは発生しませんが、非常に大きなsize_t値に対して精度が失われる可能性があります。繰り返しますが、size_tdoubleに変換することはあまり意味がありません。 size_t変数に値を保持することをお勧めします。

R Sahuの答え キャストを回避できない場合、オーバーフロー時に例外をスローするなど、いくつかの提案があります。)

51
Keith Thompson

静的キャスト:

static_cast<int>(data);
15
Blaz Bratanic

コードがオーバーフローエラーを処理する準備ができている場合、dataが大きすぎる場合は例外をスローできます。

size_t data = 99999999;
if ( data > INT_MAX )
{
   throw std::overflow_error("data is larger than INT_MAX);
}
int convertData = static_cast<int>(data);
13
R Sahu

Boost numeric_cast を使用できます。

これは、ソース値が宛先タイプの範囲外の場合に例外をスローしますが、doubleへの変換時に精度の低下を検出しません。

ただし、使用する関数が何であれ、size_tの値がINT_MAXよりも大きい場合にどうするかを決定する必要があります。検出する場合は、numeric_castを使用するか、チェックする独自のコードを記述します。何らかの理由で発生しない可能性があることがわかっている場合は、static_castを使用して、ランタイムチェックのコストなしで警告を抑制できますが、ほとんどの場合、コストは問題になりません。

9
Steve Jessop

キャストを回避するためにプログラムを再設計できないと仮定します(参照 Keith Thomson's answer ):

Size_tからintにキャストするには、size_tがintの最大値を超えないようにする必要があります。これは std :: numeric_limits を使用して実行できます。

int SizeTToInt(size_t data)
{
    if (data > std::numeric_limits<int>::max())
        throw std::exception("Invalid cast.");
    return std::static_cast<int>(data);
}

Size_tからdoubleにキャストする必要があり、精度を失わないようにする必要がある場合は、ナローキャストを使用できると思います(Stroustrup:The C++ Programming Language、Fourth Edition):

template<class Target, class Source>
Target NarrowCast(Source v)
{
    auto r = static_cast<Target>(v);
    if (static_cast<Source>(r) != v)
        throw RuntimeError("Narrow cast failed.");
    return r;
}

Size_tからdoubleへの変換にナローキャストを使用して、浮動小数点で表現可能な整数の最大値の制限を調べてテストしました(コードはgoogletestを使用しています)。

EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() - 2 })), size_t{ IntegerRepresentableBoundary() - 2 });
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() - 1 })), size_t{ IntegerRepresentableBoundary() - 1 });
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() })), size_t{ IntegerRepresentableBoundary() });
EXPECT_THROW(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 1 }), std::exception);
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 2 })), size_t{ IntegerRepresentableBoundary() + 2 });
EXPECT_THROW(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 3 }), std::exception);
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 4 })), size_t{ IntegerRepresentableBoundary() + 4 });
EXPECT_THROW(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 5 }), std::exception);

どこ

constexpr size_t IntegerRepresentableBoundary()
{
    static_assert(std::numeric_limits<double>::radix == 2, "Method only valid for binary floating point format.");
    return size_t{2} << (std::numeric_limits<double>::digits - 1);
}

つまり、Nが仮数部の桁数である場合、2 ^ N以下のdoubleの場合、整数を正確に表すことができます。 2 ^ Nと2 ^(N + 1)の間のdoubleの場合、他のすべての整数を正確に表すことができます。 2 ^(N + 1)と2 ^(N + 2)の間のdoubleの場合、4番目の整数ごとに正確に表すことができます。

1
Ida