Как я должен получить дробную часть значения с плавающей запятой?

#c #floating-point #c99 #floor #libm

#c #значение с плавающей запятой #c99 #этаж #libm

Вопрос:

У меня есть переменная x типа float , и мне нужна ее дробная часть. Я знаю, что могу получить это с помощью

  • x - floorf(x) , или
  • fmodf(x, 1.0f)

Мои вопросы: всегда ли один из них предпочтительнее другого? Являются ли они фактически одинаковыми? Есть ли третья альтернатива, которую я мог бы рассмотреть?

Примечания:

  • Если ответ зависит от используемого мной процессора, давайте сделаем его x86_64, и если вы можете подробнее рассказать о других процессорах, это было бы неплохо.
  • Пожалуйста, убедитесь и обратитесь к поведению при отрицательных значениях x . Я не возражаю против того или иного поведения, но мне нужно знать, что это за поведение.

Комментарии:

1. По крайней мере, ответ не должен зависеть от процессора.

2. Я никогда не слышал о fmod(), поэтому мне пришлось поиграть с ним. Когда исходное число равно нулю или меньше, результаты будут другими. Имеет ли это значение?

Ответ №1:

Есть ли третья альтернатива, которую я мог бы рассмотреть?

Для этого есть специальная функция. modff существует для разложения числа на его целые и дробные части.

float modff( float arg, float* iptr );

Разлагает заданное значение с плавающей запятой arg на целые и дробные части, каждая из которых имеет тот же тип и знак, arg что и . Целая часть (в формате с плавающей запятой) хранится в объекте, на который указывает iptr .

Ответ №2:

Я бы сказал, что x - floorf(x) это довольно хорошо (точно), за исключением угловых случаев

  • он имеет неправильный знаковый бит для отрицательного нуля или любого другого отрицательного целого числа с плавающей запятой (мы могли бы ожидать, что дробная часть будет иметь тот же знаковый бит).
  • это не так хорошо работает с inf

modff учитывает знаковый бит -0,0 как для частей int, так и для частей frac и отвечает /-0,0 для дробной части /-inf — по крайней мере, если реализация поддерживает стандарт IEC 60559 (IEEE 754).
Обоснование для inf может быть следующим: поскольку каждое число с плавающей запятой с точностью более 2 ^ имеет нулевую дробную часть, тогда это должно быть верно и для бесконечного числа с плавающей запятой.

Это незначительно, но, тем не менее, отличается.

РЕДАКТИРОВАТЬ Ошибка, конечно, как указано @StoryTeller-UnslanderMonica наиболее очевидным недостатком x - floor(x) является случай отрицательной плавающей запятой с дробной частью, потому что, примененный к -2.25, он вернет, например, 0.75, что не то, что мы ожидаем…

Поскольку используется метка c99, x - truncf(x) было бы более правильным, но все еще страдают от незначительных проблем, на которых я изначально сосредоточился.

Комментарии:

1.Для negative x floorf будет ближайшим целым числом меньше x . Итак, скажем -3.2 , мы получим -4.0 , что, в свою очередь, приведет -3.2 - (-4.0) = 0.8 к — что является не просто неправильным знаком.

2. @StoryTeller-UnslanderMonica Аргхх, спасибо, что указали на это, я был так сосредоточен на части со знаком нулевой дроби, что пропустил самую очевидную проблему!