преобразование float в int: округление в сложных случаях (ceil () и floor () не могут использоваться) - PullRequest
1 голос
/ 20 октября 2010

Я хочу преобразовать значение с плавающей запятой в его целочисленное представление.Поскольку это будет использоваться в сравнениях, режим округления по умолчанию (round_to_nearest) мне не подходит.Насколько я знаю, я не могу указать режим округления для FPU в соответствии со стандартом C ++ (даже в C ++ 0x).Каковы другие способы достижения этого и какой из них является наиболее переносимым?Я программирую на Linux, GCC, i386 + x86-64.

Спасибо!

РЕДАКТИРОВАТЬ

Меня интересуют round_toward_infinity и round_toward_neg_infinityрежимы округления, и я хочу иметь возможность выбрать один из них каждый раз.

Ответы [ 7 ]

2 голосов
/ 20 октября 2010

Начиная с C99 есть llrint(), которое округляет до следующего (длинного длинного) целого числа, используя текущий режим округления (который может быть установлен с помощью fesetround()).

2 голосов
/ 20 октября 2010

Если оба значения 12.3 и 14.7 являются числами с плавающей точкой, то в IEEE 754 значения 13.0 и 14.0 являются числами с плавающей точкой (в более общем смысле: если даны два нецелых числа с плавающей точкой, все целые числа между ними также являются числами с плавающей точкой). Следовательно, в соответствии с IEEE 754 floor и ceil всегда работают правильно (обратите внимание, что x86 использует представления IEEE 754).

Если вы не подпадаете под IEEE 754, учтите, что определение floor гласит (C99: 7.12.9.2/3, у меня нет под рукой C90)

Функции пола возвращают наибольшее целочисленное значение, не превышающее x, выраженное в виде числа с плавающей запятой.

Я не знаю, как интерпретировать это, если наибольшее целочисленное значение, не превышающее x, не может быть точно представлено.

2 голосов
/ 20 октября 2010

Вы должны использовать floor и ceil .Прототипом является , а не int floor или int ceil, но они возвращают целочисленное значение.

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

int main()
{
        float x = 6.04;
        printf("floor = %f ceil = %f\n", floor(x), ceil(x));
        return 0;
}

Производит:

$ ./test 
floor = 6.000000 ceil = 7.000000

Так что вам сейчас нужнобрось ответ.

1 голос
/ 20 октября 2010

Вы должны указать, какой тип округления вы делаете хотите.

Подумайте об этом в следующих терминах:

  1. принять переменную с плавающей запятой

  2. округлить соответственно

  3. приведение к целому числу получит целую часть значения с плавающей запятой - оно усекает значение

Вы можете посмотреть floor() и ceil() для округления и округления соответственно.

Вы должны обратить особое внимание на то, что вы хотите, чтобы происходило около 0 и отрицательных чисел.

GLIBC имеет множество функций округления доступно.

Вот функция округления до бесконечности:

int round_towards_infinity(double value) {
  if(value > 0)
     return ceil(value);
  return floor(value);
}
0 голосов
/ 20 октября 2010

Звучит так, как будто вам придётся немного повозиться, чтобы получить правильный ответ. Извлеките экспоненту с плавающей точкой и используйте ее, чтобы сместить битовую комбинацию мантиссы на нужную величину. Возможно, вам придется сделать некоторые дополнительные хитрости для обработки +/- бесконечности, переполнения и денормализованных значений ... но это звучит как болезненный путь ... Я бы не пошел по нему, если бы вам действительно не пришлось это делать

0 голосов
/ 20 октября 2010

Преобразование, которое меня всегда учили использовать (хотя я уверен, что за него стреляют правильные математики с плавающей запятой), было:

float x = ....;
int   y = int(x + 0.5f);

Быстрый просмотр моей справки говорит о том, что в C99 есть семейство функций «lrint», которые принимают значения с плавающей запятой и возвращают длинные целые числа. Это может быть то, что вы ищете.

0 голосов
/ 20 октября 2010

Может быть так:

#include <cmath>

int Round( const double a )
{
  return static_cast< int >( std::floor( a + 0.5 ) );
}
...