22

C++がceil関数を提供することを私は知っています。実際には、C++でceil関数をどのように実装できるのか疑問に思いました。メソッドのシグネチャはpublicstaticint ceil(float num)です。

いくつかの洞察を提供してください。

簡単な方法を考えました。numを文字列に変換し、小数点のインデックスを見つけ、小数部が0より大きいかどうかを確認します。はいの場合はnum + 1を返し、そうでない場合はnumを返します。しかし、文字列変換の使用は避けたい

4

10 に答える 10

32

IEEE754浮動小数点数の要素を分解して、ロジックを自分で実装できます。

#include <cstring>

float my_ceil(float f)
{
    unsigned input;
    memcpy(&input, &f, 4);
    int exponent = ((input >> 23) & 255) - 127;
    if (exponent < 0) return (f > 0);
    // small numbers get rounded to 0 or 1, depending on their sign

    int fractional_bits = 23 - exponent;
    if (fractional_bits <= 0) return f;
    // numbers without fractional bits are mapped to themselves

    unsigned integral_mask = 0xffffffff << fractional_bits;
    unsigned output = input & integral_mask;
    // round the number down by masking out the fractional bits

    memcpy(&f, &output, 4);
    if (f > 0 && output != input) ++f;
    // positive numbers need to be rounded up, not down

    return f;
}

(ここに通常の「ポータブルではない」免責事項を挿入します。)

于 2011-12-04T19:34:40.283 に答える
15

以下は、正の数に対する単純な実装です (これは、キャストが(int)ゼロに向かって切り捨てられるという事実を利用しています)。

int ceil(float num) {
    int inum = (int)num;
    if (num == (float)inum) {
        return inum;
    }
    return inum + 1;
}

これを負の数でも動作するように拡張するのは簡単です。

あなたの質問は を返す関数を求めましたintが、通常、ceil()関数は引数と同じ型を返すため、範囲 (つまりfloat ceil(float num)) に問題はありません。たとえば、上記の関数はnumが 1e20 の場合に失敗します。

于 2011-12-04T18:23:39.880 に答える
7

それは本質的にあなたがしなければならないことですが、に変換することはありませんstring

浮動小数点数は として表され(+/-) M * 2^Eます。指数 は、2 進小数点*Eからどれだけ離れているかを示します。が十分に大きい場合、小数部分がないため、何もする必要はありません。が十分に小さい場合、整数部分がないため、答えは 1 です (がゼロではなく、数値が正であると仮定します)。それ以外の場合は、2 進小数点が仮数内のどこに表示されるかを示します。これを使用してチェックを行い、丸めを実行できます。EEME


* 10 進法ではなく 2 進法であるため、小数点ではありません。

于 2011-12-04T18:08:18.350 に答える
5

私の5セント:

template <typename F>
inline auto ceil(F const f) noexcept
{
  auto const t(std::trunc(f));

  return t + (t < f);
}
于 2019-01-16T08:38:43.533 に答える
1

前のコードの推奨事項:

int ceil(float val) 
{
    int temp  = val * 10;
    if(val%10)
    return (temp+1);
    else
    return temp;
}

コンパイルされません: float またはダブル。参照: float 型および double 型のオペランドに演算子 % を使用できないのはなぜですか? また、精度が 1/10 を超えない 10 進数値に対しても機能しません。

一方、以前のコードの推奨事項:

int ma_ceil(float num)
{   int a = num;
    if ((float)a != num)
        return num+1;
    return num;
}

浮動小数点値の範囲を超えない限り、うまく機能します。数値 = 555555555; または num = -5.000000001 は、double を使用しない限り機能しません。

また、float と double は IEEE 浮動小数点形式で格納されるため、格納されるバイナリ表現が不正確になる可能性があります。例えば:

浮動小数点数 = 5; 場合によっては、5.0000000 という値が割り当てられず、5.9999998 または 5.00000001 が割り当てられることがあります。以前のコード バージョンを修正するには、次のように、浮動小数点値の精度に依存するのではなく、整数演算を使用するように戻り値を変更することをお勧めします。

int ma_ceil(float num)
{   int a = num;
    if ((float)a != num)
        return a+1;
    return a;
}
于 2018-11-09T18:38:59.830 に答える
0

このようなもの:

  double param, fractpart, intpart;

  param = 3.14159265;
  fractpart = modf (param , &intpart);

  int intv = static_cast<int>(intpart); // can overflow - so handle that.

  if (fractpart > some_epsilon)
    ++intv;

some_epsilon整数部分がインクリメントされる前よりも小数部分が大きくなるように値を定義するだけです。考慮すべき他のことは符号です(つまり、値が負の場合など)

于 2011-12-04T18:19:12.953 に答える
0

負の数で動作するものは次のとおりです。

int ceil(float num) {
    int inum = (int)num;
    if (num < 0 || num == (float)inum) {
        return inum;
    }
    return inum + 1;
}
于 2020-07-30T17:24:54.533 に答える
-5

これを試して...

int ceil(float val)
{
    int temp  = val * 10;
    if(val%10)
    return (temp+1);
    else
    return temp;
}
于 2011-12-04T18:11:18.770 に答える