245

したがって、単純な浮動小数点丸め関数が必要です。

double round(double);

round(0.1) = 0
round(-0.1) = 0
round(-0.9) = -1

math.h でceil()とを見つけることができますが、 ではありません。floor()round()

別の名前で標準 C++ ライブラリに存在しますか、それとも欠落していますか??

4

23 に答える 23

145

編集者注:次の回答は、いくつかの実装上の欠陥を含む単純なソリューションを提供します (完全な説明については、 Shafik Yaghmour の回答を参照してください)。C++11 にはstd::roundstd::lround、 、およびstd::llroundがビルトインとして既に含まれていることに注意してください。

C++98 標準ライブラリには round() はありません。ただし、自分で書くこともできます。以下はround-half-upの実装です。

double round(double d)
{
  return floor(d + 0.5);
}

C++98 標準ライブラリにラウンド関数がない理由として考えられるのは、実際にはさまざまな方法で実装できるためです。上記は一般的な方法の 1 つですが、round-to-evenなどの他の方法もあります。これは偏りが少なく、多くの丸めを行う場合に一般的に優れています。ただし、実装はもう少し複雑です。

于 2009-01-27T22:10:28.577 に答える
96

Boost は、単純な丸め関数のセットを提供します。

#include <boost/math/special_functions/round.hpp>

double a = boost::math::round(1.5); // Yields 2.0
int b = boost::math::iround(1.5); // Yields 2 as an integer

詳細については、Boost のドキュメントを参照してください。

編集:C++11以降、、、およびがstd::roundありstd::lroundますstd::llround

于 2011-05-01T16:19:30.537 に答える
94

C++03 標準は、標準が C++03 標準の草案 (C++03に最も近い公開されている草案標準は N1804 です)セクションでカバーされている標準 C ライブラリと呼ぶものについて、C90 標準に依存しています。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 からの別のオプションは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 以外のアプリケーションをサポートする必要がある場合は、boost round、iround、lround、llround、またはboost truncを使用することをお勧めします。

独自のバージョンのラウンドを展開するのは難しい

見た目より難しい: 浮動小数点数を最も近い整数に丸める (パート 1 ) 、浮動小数点数を最も近い整数に丸める(パート 2) 、浮動小数点数を最も近い整数に丸める (パート 3)説明:

たとえば、実装を使用std::floorおよび追加する一般的なロール0.5は、すべての入力に対して機能しません。

double myround(double d)
{
  return std::floor(d + 0.5);
}

これが失敗する 1 つの入力は0.49999999999999994, です (ライブで参照してください)。

別の一般的な実装には、浮動小数点型を整数型にキャストすることが含まれます。これは、整数部分を宛先の型で表現できない場合に未定義の動作を引き起こす可能性があります。これは、ドラフト C++ 標準セクション4.9 Floating-integral conversionsから見ることができます(私の強調):

浮動小数点型の 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 ) 

オーバーフローが発生します(ライブでご覧ください)。

Concise way to implement round() in C?に対するこの回答を見ると、これが実際にどれほど難しいかがわかります。単精度浮動小数点ラウンドの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がオプションになる可能性があります。

于 2014-06-22T04:07:51.643 に答える
71

丸めから整数の結果が必要な場合は、ceil または floor を介して渡す必要がないことに注意してください。すなわち、

int round_int( double r ) {
    return (r > 0.0) ? (r + 0.5) : (r - 0.5); 
}
于 2011-01-11T16:45:51.687 に答える
50

cmath の C++11 以降で利用可能です ( http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdfによると) 。

#include <cmath>
#include <iostream>

int main(int argc, char** argv) {
  std::cout << "round(0.5):\t" << round(0.5) << std::endl;
  std::cout << "round(-0.5):\t" << round(-0.5) << std::endl;
  std::cout << "round(1.4):\t" << round(1.4) << std::endl;
  std::cout << "round(-1.4):\t" << round(-1.4) << std::endl;
  std::cout << "round(1.6):\t" << round(1.6) << std::endl;
  std::cout << "round(-1.6):\t" << round(-1.6) << std::endl;
  return 0;
}

出力:

round(0.5):  1
round(-0.5): -1
round(1.4):  1
round(-1.4): -1
round(1.6):  2
round(-1.6): -2
于 2012-06-19T13:23:09.353 に答える
28

通常は として実装されfloor(value + 0.5)ます。

編集: そして、私が知っている少なくとも 3 つの丸めアルゴリズムがあるため、おそらく round とは呼ばれません: ゼロへの丸め、最も近い整数への丸め、およびバンカーの丸め。最も近い整数への丸めを求めています。

于 2009-01-27T22:08:38.097 に答える
14

私たちが見ている2つの問題があります:

  1. 丸め変換
  2. 型変換。

丸め変換とは、± float/double を最も近い floor/ceil float/double に丸めることを意味します。あなたの問題はここで終わるかもしれません。ただし、Int/Long を返すことが期待される場合は、型変換を実行する必要があるため、「オーバーフロー」の問題が解決策に影響を与える可能性があります。SO、関数のエラーをチェックしてください

long round(double x) {
   assert(x >= LONG_MIN-0.5);
   assert(x <= LONG_MAX+0.5);
   if (x >= 0)
      return (long) (x+0.5);
   return (long) (x-0.5);
}

#define round(x) ((x) < LONG_MIN-0.5 || (x) > LONG_MAX+0.5 ?\
      error() : ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))

から: http://www.cs.tut.fi/~jkorpela/round.html

于 2010-05-29T08:49:02.577 に答える
11

Boost では、特定の種類の丸めも実装されています。

#include <iostream>

#include <boost/numeric/conversion/converter.hpp>

template<typename T, typename S> T round2(const S& x) {
  typedef boost::numeric::conversion_traits<T, S> Traits;
  typedef boost::numeric::def_overflow_handler OverflowHandler;
  typedef boost::numeric::RoundEven<typename Traits::source_type> Rounder;
  typedef boost::numeric::converter<T, S, Traits, OverflowHandler, Rounder> Converter;
  return Converter::convert(x);
}

int main() {
  std::cout << round2<int, double>(0.1) << ' ' << round2<int, double>(-0.1) << ' ' << round2<int, double>(-0.9) << std::endl;
}

これは、整数への変換を行う場合にのみ機能することに注意してください。

于 2010-06-29T13:02:15.750 に答える
7

最近では、C99/C++11 数学ライブラリを含む C++11 コンパイラを使用しても問題ありません。しかし、問題は次のようになります。どの丸め関数を選択しますか?

C99/C++11round()は、実際には必要な丸め関数ではないことがよくあります。中途半端な場合のタイブレークとして、0 から離れて丸めるファンキーな丸めモードを使用します ( +-xxx.5000)。その丸めモードが特に必要な場合、またはround()より高速なC++ 実装をターゲットにしている場合はrint()、それを使用します (または、この質問に対する他の回答の 1 つを使用してその動作をエミュレートします。丸め動作。)

round()の丸めは、IEEE754 のデフォルトの丸めとは異なり、タイブレークとしても使用されます。Nearest-even は、数値の平均の大きさにおける統計的偏りを回避しますが、偶数に向かって偏ります。

現在のデフォルトの丸めモードを使用する 2 つの数学ライブラリの丸め関数がstd::nearbyint()ありstd::rint()ますstd::round()。唯一の違いは、nearbyintFE_INEXACT が発生しないことです。

rint()パフォーマンス上の理由から優先: gcc と clang はどちらもインライン化が容易ですが、gcc はインライン化されませんnearbyint()( を使用しても-ffast-math) 。


x86-64 および AArch64 の gcc/clang

Matt Godbolt の Compiler Explorerにいくつかのテスト関数を配置しました。ここでは、source + asm 出力 (複数のコンパイラの場合) を確認できます。コンパイラ出力の読み取りの詳細については、この Q&Aと Matt の CppCon2017 トークを参照してください。コンパイラのふたを外す」</a>,

FP コードでは、通常、小さな関数をインライン化することは大きなメリットです。特に Windows 以外では、標準の呼び出し規約に呼び出し保存レジスタがないため、コンパイラはcall. したがって、asm をよく知らなくても、それがライブラリ関数の末尾呼び出しに過ぎないのか、それとも 1 つまたは 2 つの数学命令にインライン化されているのかを簡単に確認できます。1 つまたは 2 つの命令にインライン化するものは、関数呼び出しよりも優れています (x86 または ARM でのこの特定のタスクの場合)。

x86 では、SSE4.1 にインライン化されたものroundsdroundpdはすべて SSE4.1 (または AVX )で自動ベクトル化できvroundpdます。(FP->整数変換は、AVX512 を必要とする FP->64 ビット整数を除いて、パックされた SIMD 形式でも利用できます。)

  • std::nearbyint():

    • x86 clang: を使用して単一の insn にインライン化し-msse4.1ます。
    • x86 gcc: でのみ単一の insn にインライン展開し、-msse4.1 -ffast-mathgcc 5.4以前でのみ。後のgccはそれをインライン化することはありません(おそらく、即値ビットの1つが不正確な例外を抑制できることに気付いていなかったのでしょうか?それはclangが使用するものですが、古いgccrintはインライン化するときと同じ即値を使用します)
    • AArch64 gcc6.3: デフォルトで単一の insn にインライン化します。
  • std::rint:

    • x86 clang: 単一の insn にインライン化-msse4.1
    • x86 gcc7: を使用して単一の insn にインライン化し-msse4.1ます。(SSE4.1 を使用しない場合、複数の命令にインライン化されます)
    • x86 gcc6.x 以前: -ffast-math -msse4.1.
    • AArch64 gcc: デフォルトで単一の insn にインライン化
  • std::round:

    • x86 clang: インライン化しません
    • x86 gcc: を使用して複数の命令にインライン化します-ffast-math -msse4.1。2 つのベクトル定数が必要です。
    • AArch64 gcc: 単一の命令にインライン化します (この丸めモード、IEEE デフォルトおよびその他のほとんどのハードウェア サポート)。
  • std::floor/ std::ceil/std::trunc

    • x86 clang: 単一の insn にインライン化-msse4.1
    • x86 gcc7.x: 単一の insn にインライン展開-msse4.1
    • x86 gcc6.x 以前: 単一の insn にインライン展開-ffast-math -msse4.1
    • AArch64 gcc: デフォルトで単一の命令にインライン化

int/ long/への丸めlong long:

ここには 2 つのオプションがあります: 使用するlrint(rintただし、 return long、またはlong longfor のようにllrint)、または FP->FP 丸め関数を使用してから、通常の方法で (切り捨てを使用して) 整数型に変換します。一部のコンパイラは、ある方法を他の方法よりも最適化します。

long l = lrint(x);

int  i = (int)rint(x);

or ->を最初にint i = lrint(x)変換してから、整数を に切り捨てることに注意してください。これは、範囲外の整数に違いをもたらします: C++ では未定義の動作ですが、x86 FP -> int 命令については明確に定義されています (定数の伝播を実行しているときにコンパイル時に UB が検出されない限り、コンパイラは発行します。実行された場合に壊れるコードを作成することが許可されています)。floatdoublelongint

x86 では、整数をオーバーフローする FP->integer 変換により、INT_MINor (符号ビットが設定された 64 ビット相当のビットLLONG_MINパターン) が生成されます。0x8000000Intel では、これを「整数不定」値と呼んでいます。(マニュアル エントリを参照してcvttsd2siください。これは、スカラー double を符号付き整数に変換する SSE2 命令です (切り捨てあり)。32 ビットまたは 64 ビット整数の変換先で使用できます (64 ビット モードのみ)。cvtsd2si(convert with current rounding ) もあります。これはコンパイラに出力させたいものですが、残念ながら gcc と clang は-ffast-math.

またunsigned、x86 (AVX512 なし) では int / long との間の FP の効率が悪いことに注意してください。64 ビット マシンでの 32 ビット符号なしへの変換はかなり安価です。64 ビットの符号付きに変換して切り捨てるだけです。しかし、それ以外の場合は大幅に遅くなります。

  • x86 clang with/without -ffast-math -msse4.1: (int/long)rintinlines to roundsd/ cvttsd2si. ( への最適化を逃したcvtsd2si)。 lrintまったくインライン化されません。

  • x86 gcc6.x 以前なし-ffast-math: どちらの方法もインライン化されていません

  • x86 gcc7 without -ffast-math:丸め、個別に変換します (SSE4.1 の合計 2 つの命令が有効になっている場合、そうでない場合はwithout(int/long)rintのインライン化された一連のコードがあります)。 インライン化されません。rintroundsdlrint
  • x86 gcc with -ffast-math : (optimal)にすべてインラインcvtsd2si化、SSE4.1 は不要。

  • なしの AArch64 gcc6.3 -ffast-math: (int/long)rint2 つの命令にインライン化します。 lrintインライン化しない

  • AArch64 gcc6.3 with -ffast-math:(int/long)rintへの呼び出しにコンパイルされlrintます。 lrintインライン化されません。これは、得られない 2 つの命令-ffast-mathが非常に遅い場合を除き、最適化の失敗である可能性があります。
于 2017-11-17T09:27:33.497 に答える
6

次のようにして、n桁の精度に丸めることができます。

double round( double x )
{
const double sd = 1000; //for accuracy to 3 decimal places
return int(x*sd + (x<0? -0.5 : 0.5))/sd;
}
于 2010-02-12T03:02:23.563 に答える
5

最終的に関数のdouble出力をに変換したい場合、この質問の受け入れられる解決策は次のようになります。round()int

int roundint(double r) {
  return (int)((r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5));
}

これは、一様にランダムな値が渡されると、私のマシンでは約8.88 nsで記録されます。

私が知る限り、以下は機能的に同等ですが、私のマシンでは2.48 nsで動作し、パフォーマンスが大幅に向上します。

int roundint (double r) {
  int tmp = static_cast<int> (r);
  tmp += (r-tmp>=.5) - (r-tmp<=-.5);
  return tmp;
}

パフォーマンスが向上する理由の 1 つに、分岐のスキップがあります。

于 2013-04-25T21:02:09.957 に答える
4

注意してくださいfloor(x+0.5)。[2 ^ 52,2^53]の範囲の奇数で発生する可能性があるのは次のとおりです。

-bash-3.2$ cat >test-round.c <<END

#include <math.h>
#include <stdio.h>

int main() {
    double x=5000000000000001.0;
    double y=round(x);
    double z=floor(x+0.5);
    printf("      x     =%f\n",x);
    printf("round(x)    =%f\n",y);
    printf("floor(x+0.5)=%f\n",z);
    return 0;
}
END

-bash-3.2$ gcc test-round.c
-bash-3.2$ ./a.out
      x     =5000000000000001.000000
round(x)    =5000000000000001.000000
floor(x+0.5)=5000000000000002.000000

これはhttp://bugs.squeak.org/view.php?id=7134です。@konikのようなソリューションを使用してください。

私自身の堅牢なバージョンは次のようになります。

double round(double x)
{
    double truncated,roundedFraction;
    double fraction = modf(x, &truncated);
    modf(2.0*fraction, &roundedFraction);
    return truncated + roundedFraction;
}

floor(x + 0.5)を避けるもう1つの理由は、ここに示されています。

于 2012-06-17T20:50:40.727 に答える
2

関数double round(double)を使用したmodf関数:

double round(double x)
{
    using namespace std;

    if ((numeric_limits<double>::max() - 0.5) <= x)
        return numeric_limits<double>::max();

    if ((-1*std::numeric_limits<double>::max() + 0.5) > x)
        return (-1*std::numeric_limits<double>::max());

    double intpart;
    double fractpart = modf(x, &intpart);

    if (fractpart >= 0.5)
        return (intpart + 1);
    else if (fractpart >= -0.5)
        return intpart;
    else
        return (intpart - 1);
    }

クリーンにコンパイルするには、"math.h" と "limits" を含める必要があります。この関数は、次の丸めスキーマに従って機能します。

  • ラウンド オブ 5.0 は 5.0
  • 3.8 のラウンドは 4.0 です
  • 2.3 のラウンドは 2.0 です
  • 1.5 のラウンドは 2.0 です
  • 0.501 のラウンドは 1.0
  • 0.5 のラウンドは 1.0
  • 0.499 のラウンドは 0.0
  • 0.01 のラウンドは 0.0
  • 0.0 の丸めは 0.0
  • -0.01 の丸めは -0.0
  • -0.499 の丸めは -0.0
  • -0.5 の丸めは -0.0
  • -0.501 のラウンドは -1.0
  • -1.5 の丸めは -1.0
  • -2.3 のラウンドは -2.0
  • -3.8 のラウンドは -4.0
  • -5.0 のラウンドは -5.0
于 2011-02-09T11:35:25.343 に答える
1

Kalaxy の応答に基づいて、自然な丸めに基づいて任意の浮動小数点数を最も近い整数型に丸めるテンプレート化されたソリューションを次に示します。また、値が整数型の範囲外の場合、デバッグ モードでエラーをスローするため、ほぼ実行可能なライブラリ関数として機能します。

    // round a floating point number to the nearest integer
    template <typename Arg>
    int Round(Arg arg)
    {
#ifndef NDEBUG
        // check that the argument can be rounded given the return type:
        if (
            (Arg)std::numeric_limits<int>::max() < arg + (Arg) 0.5) ||
            (Arg)std::numeric_limits<int>::lowest() > arg - (Arg) 0.5)
            )
        {
            throw std::overflow_error("out of bounds");
        }
#endif

        return (arg > (Arg) 0.0) ? (int)(r + (Arg) 0.5) : (int)(r - (Arg) 0.5);
    }
于 2013-10-24T00:03:47.680 に答える
1

コメントやその他の回答で指摘されているように、ISO C++ 標準ライブラリはround()、この関数が ISO C99 標準数学ライブラリへの参照によって取り込まれた ISO C++11 まで追加されませんでした。

[½, ub ]の正のオペランドのround(x) == floor (x + 0.5)場合、ここで、ubは、IEEE-754 (2008) にマップされる場合は 2 23であり、IEEE-754 (2008) にマップされる場合は 2 52です。数値 23 と 52 は、これら 2 つの浮動小数点形式で格納された仮数ビットの数に対応します。[+0, ½)の正のオペランド、および ( ub , +∞]の正のオペランドの場合. 関数は x 軸に対して対称であるため、負の引数は に従って処理できます。floatbinary32doublebinary64round(x) == 0round(x) == xxround(-x) == -round(x)

これにより、以下のコンパクトなコードが得られます。さまざまなプラットフォームで妥当な数の機械語命令にコンパイルされます。私は GPU で最もコンパクトなコードを観察しました。ここでmy_roundf()は、約 12 個の命令が必要です。プロセッサのアーキテクチャとツールチェーンに応じて、この浮動小数点ベースのアプローチは、別の回答で参照されている newlib の整数ベースの実装よりも高速または低速になる可能性があります。

インテル® コンパイラーのバージョン 13 を使用my_roundf()して、newlib の実装を徹底的にテストしました。また、newlib のバージョンが Intel コンパイラのライブラリと一致することも確認しました。倍精度の完全なテストはできませんが、コードは構造的に単精度の実装と同じです。roundf()/fp:strict/fp:fastroundf()mathimfround()

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>

float my_roundf (float x)
{
    const float half = 0.5f;
    const float one = 2 * half;
    const float lbound = half;
    const float ubound = 1L << 23;
    float a, f, r, s, t;
    s = (x < 0) ? (-one) : one;
    a = x * s;
    t = (a < lbound) ? x : s;
    f = (a < lbound) ? 0 : floorf (a + half);
    r = (a > ubound) ? x : (t * f);
    return r;
}

double my_round (double x)
{
    const double half = 0.5;
    const double one = 2 * half;
    const double lbound = half;
    const double ubound = 1ULL << 52;
    double a, f, r, s, t;
    s = (x < 0) ? (-one) : one;
    a = x * s;
    t = (a < lbound) ? x : s;
    f = (a < lbound) ? 0 : floor (a + half);
    r = (a > ubound) ? x : (t * f);
    return r;
}

uint32_t float_as_uint (float a)
{
    uint32_t r;
    memcpy (&r, &a, sizeof(r));
    return r;
}

float uint_as_float (uint32_t a)
{
    float r;
    memcpy (&r, &a, sizeof(r));
    return r;
}

float newlib_roundf (float x)
{
    uint32_t w;
    int exponent_less_127;

    w = float_as_uint(x);
    /* Extract exponent field. */
    exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
    if (exponent_less_127 < 23) {
        if (exponent_less_127 < 0) {
            /* Extract sign bit. */
            w &= 0x80000000;
            if (exponent_less_127 == -1) {
                /* Result is +1.0 or -1.0. */
                w |= ((uint32_t)127 << 23);
            }
        } else {
            uint32_t 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 so raise FE_INVALID by adding */
            return x + x;
        } else {
            return x;
        }
    }
    x = uint_as_float (w);
    return x;
}

int main (void)
{
    uint32_t argi, resi, refi;
    float arg, res, ref;

    argi = 0;
    do {
        arg = uint_as_float (argi);
        ref = newlib_roundf (arg);
        res = my_roundf (arg);
        resi = float_as_uint (res);
        refi = float_as_uint (ref);
        if (resi != refi) { // check for identical bit pattern
            printf ("!!!! arg=%08x  res=%08x  ref=%08x\n", argi, resi, refi);
            return EXIT_FAILURE;
        }
        argi++;
    } while (argi);
    return EXIT_SUCCESS;
}
于 2017-11-16T11:57:30.687 に答える
0

x86 アーキテクチャおよび MS VS 固有の C++ の asm で、次の round の実装を使用します。

__forceinline int Round(const double v)
{
    int r;
    __asm
    {
        FLD     v
        FISTP   r
        FWAIT
    };
    return r;
}

UPD: double 値を返す

__forceinline double dround(const double v)
{
    double r;
    __asm
    {
        FLD     v
        FRNDINT
        FSTP    r
        FWAIT
    };
    return r;
}

出力:

dround(0.1): 0.000000000000000
dround(-0.1): -0.000000000000000
dround(0.9): 1.000000000000000
dround(-0.9): -1.000000000000000
dround(1.1): 1.000000000000000
dround(-1.1): -1.000000000000000
dround(0.49999999999999994): 0.000000000000000
dround(-0.49999999999999994): -0.000000000000000
dround(0.5): 0.000000000000000
dround(-0.5): -0.000000000000000
于 2014-10-28T10:32:50.327 に答える
0

数学を使用する ARM の round_f

static inline float round_f(float value)
{
    float rep;
    asm volatile ("vrinta.f32 %0,%1" : "=t"(rep) : "t"(value));
    return rep;
}

数学なしの ARM の round_f

union f__raw {
    struct {
        uint32_t massa  :23;
        uint32_t order  :8;
        uint32_t sign   :1;
    };
    int32_t     i_raw;
    float       f_raw;
};

float round_f(float value)
{
    union f__raw raw;
    int32_t exx;
    uint32_t ex_mask;
    raw.f_raw = value;
    exx = raw.order - 126;
    if (exx < 0) {
        raw.i_raw &= 0x80000000;
    } else if (exx < 24) {
        ex_mask = 0x00ffffff >> exx;
        raw.i_raw += 0x00800000 >> exx;
        if (exx == 0) ex_mask >>= 1;
        raw.i_raw &= ~ex_mask;
    };
    return  raw.f_raw;
};
于 2022-01-13T00:21:14.173 に答える
-4
// Convert the float to a string
// We might use stringstream, but it looks like it truncates the float to only
//5 decimal points (maybe that's what you want anyway =P)

float MyFloat = 5.11133333311111333;
float NewConvertedFloat = 0.0;
string FirstString = " ";
string SecondString = " ";
stringstream ss (stringstream::in | stringstream::out);
ss << MyFloat;
FirstString = ss.str();

// Take out how ever many decimal places you want
// (this is a string it includes the point)
SecondString = FirstString.substr(0,5);
//whatever precision decimal place you want

// Convert it back to a float
stringstream(SecondString) >> NewConvertedFloat;
cout << NewConvertedFloat;
system("pause");

それは変換の非効率的な汚い方法かもしれませんが、まあ、うまくいきます笑。実際のフロートに適用されるので、それは良いことです。視覚的に出力に影響を与えるだけではありません。

于 2010-06-29T12:31:34.290 に答える
-6

これは私がしました:

#include <cmath.h>

using namespace std;

double roundh(double number, int place){

    /* place = decimal point. Putting in 0 will make it round to whole
                              number. putting in 1 will round to the
                              tenths digit.
    */

    number *= 10^place;
    int istack = (int)floor(number);
    int out = number-istack;
    if (out < 0.5){
        floor(number);
        number /= 10^place;
        return number;
    }
    if (out > 0.4) {
        ceil(number);
        number /= 10^place;
        return number;
    }
}
于 2009-05-09T16:47:36.557 に答える