C ++ 03標準は、C90標準に基づいて標準Cライブラリと呼ばれ、C ++ 03標準のドラフト(C ++ 03に最も近い公に利用可能なドラフト標準はN1804です)で規定されてい1.2
ます。
ISO / IEC 9899:1990の7節およびISO / IEC 9899 / Amd.1:1995の7節に記述されているライブラリーを、以降、標準Cライブラリーと呼びます。1)
cppreferenceのround、lround、llroundのCドキュメントに移動すると、roundおよび関連する関数がC99の一部であり、C ++ 03以前では使用できないことがわかります。
C ++ 11では、C ++ 11がC標準ライブラリの C99ドラフト標準に依存しているため、std :: roundと、整数の戻り値型std :: lround、std :: llroundを提供するため、これは変更されます。
#include <iostream>
#include <cmath>
int main()
{
std::cout << std::round( 0.4 ) << " " << std::lround( 0.4 ) << " " << std::llround( 0.4 ) << std::endl ;
std::cout << std::round( 0.5 ) << " " << std::lround( 0.5 ) << " " << std::llround( 0.5 ) << std::endl ;
std::cout << std::round( 0.6 ) << " " << std::lround( 0.6 ) << " " << std::llround( 0.6 ) << std::endl ;
}
C99のもう1つのオプションはstd :: truncで、次のようになります。
argより大きくない最も近い整数を計算します。
#include <iostream>
#include <cmath>
int main()
{
std::cout << std::trunc( 0.4 ) << std::endl ;
std::cout << std::trunc( 0.9 ) << std::endl ;
std::cout << std::trunc( 1.1 ) << std::endl ;
}
C ++ 11以外のアプリケーションをサポートする必要がある場合、最善の策は、ブーストラウンド、iround、lround、llround、またはブーストトランケーションを使用することです。
自分のバージョンのラウンドをロールするのは難しい
自分でロールすることは、見た目よりも難しいため、おそらく努力する価値はありません。浮動小数点を最も近い整数に丸める、パート1、浮動小数点を最も近い整数に丸める、パート2およびフロートを最も近い整数に丸める、パート3で説明します。
たとえば、実装を使用std::floor
して追加する一般的なロールは、0.5
すべての入力に対して機能しません。
double myround(double d)
{
return std::floor(d + 0.5);
}
これが失敗する入力の1つは0.49999999999999994
、です(ライブで確認してください)。
別の一般的な実装には、浮動小数点型を整数型にキャストすることが含まれます。これは、整数型が宛先型で表現できない場合に未定義の動作を呼び出す可能性があります。これは、C ++標準のドラフトセクションである4.9
浮動積分変換からわかります(強調は私のものです)。
浮動小数点型のprvalueは、整数型のprvalueに変換できます。変換は切り捨てられます。つまり、小数部分は破棄されます。切り捨てられた値を宛先タイプで表すことができない場合の動作は未定義です。[...]
例えば:
float myround(float f)
{
return static_cast<float>( static_cast<unsigned int>( f ) ) ;
}
次に、次の呼び出しstd::numeric_limits<unsigned int>::max()
が与えられ4294967295
ます。
myround( 4294967296.5f )
オーバーフローが発生します(ライブで確認してください)。
Cでround()を実装する簡潔な方法に対するこの回答を見ると、これが実際にどれほど難しいかがわかりますか?単精度浮動小数点ラウンドのnewlibsバージョンを参照しています。シンプルに見えるものに対しては非常に長い機能です。浮動小数点の実装について詳しくない人がこの関数を正しく実装できるとは考えにくいでしょう。
float roundf(x)
{
int signbit;
__uint32_t w;
/* Most significant word, least significant word. */
int exponent_less_127;
GET_FLOAT_WORD(w, x);
/* Extract sign bit. */
signbit = w & 0x80000000;
/* Extract exponent field. */
exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
if (exponent_less_127 < 23)
{
if (exponent_less_127 < 0)
{
w &= 0x80000000;
if (exponent_less_127 == -1)
/* Result is +1.0 or -1.0. */
w |= ((__uint32_t)127 << 23);
}
else
{
unsigned int exponent_mask = 0x007fffff >> exponent_less_127;
if ((w & exponent_mask) == 0)
/* x has an integral value. */
return x;
w += 0x00400000 >> exponent_less_127;
w &= ~exponent_mask;
}
}
else
{
if (exponent_less_127 == 128)
/* x is NaN or infinite. */
return x + x;
else
return x;
}
SET_FLOAT_WORD(x, w);
return x;
}
一方、他のソリューションがどれも使用できない場合、newlibは十分にテストされた実装であるため、オプションになる可能性があります。
std::cout << std::fixed << std::setprecision(0) << -0.9
、たとえば、を実行するだけでよいようです。