Функция Ceil: как мы можем реализовать ее сами?

Я знаю, что C++ предоставляет нам функцию ceil. Для практики мне было интересно, как мы можем реализовать функцию ceil в C++. Подпись метода public static int ceil (float num)

пожалуйста, дайте некоторое представление.

Я подумал о простом способе: преобразовать num в строку, Найти индекс десятичной точки, проверить, если десятичная часть больше 0. Если да, верните num+1 еще верните num. Но я хочу избежать использования преобразования строки

6 ответов


вот наивная реализация для положительных чисел (это использует тот факт, что приведение к (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 is 1e20.


вы можете разобрать ингредиенты числа с плавающей запятой 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;
}

(вставьте здесь обычную оговорку" не переносится".)


это именно то, что вам нужно сделать, но без преобразования в string.

число с плавающей точкой представляется как (+/-) M * 2^E. Экспонента,E, говорит вам, как далеко вы находитесь от двоичной точки*. Если E достаточно большой, дробной части нет, поэтому делать нечего. Если E достаточно мал, целочисленной части нет, поэтому ответ 1 (при условии M является ненулевым, и число является положительным). В противном случае, E указывает, где двоичная точка появляется в пределах вашей мантиссы, которую можно использовать для проверки, а затем выполнить округление.


* не десятичная точка, потому что мы находимся в базе-2, а не в базе-10.

что-то вроде этого:

  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 значение для того, что вы хотите, чтобы дробная часть была больше, чем до увеличения целочисленной части. Другие вещи, чтобы рассмотреть знак (т. е. если значение отрицательное и т. д.)


он работает с отрицательным значением тоже

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

    return num;
}

попробуйте это...

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