Как преобразовать float в int
Перейти к содержимому

Как преобразовать float в int

1.3.18. Преобразование типов

При выполнении операций происходят неявные преобразования типов в следующих случаях:

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

Кроме того, в Си есть возможность явного приведения значения одного типа к другому.

В операциях присваивания тип значения, которое присваивается, преобразуется к типу переменной, получающей это значение. Допускается преобразования целых и плавающих типов, даже если такое преобразование ведет к потере информации.

Преобразование целых типов со знаком. Целое со знаком преобразуется к более короткому целому со знаком, посредством усечения старших битов. Целая со знаком преобразуется к более длинному целому со знаком, путем размножения знака. При преобразовании целого со знаком к целому без знака, целое со знаком преобразуется к размеру целого без знака и результат рассматривается как значение без знака.

Преобразование целого со знаком к плавающему типу происходит без потери] информации, за исключением случая преобразования значения типа long int или unsigned long int к типу float, когда точность часто может быть потеряна.

Преобразование целых типов без знака. Целое без знака преобразуется к более короткому целому без знака или со знаком путем усечения старших битов. Целое без знака преобразуется к более длинному целому без знака или со знаком путем дополнения нулей слева.

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

Целые значения без знака преобразуются к плавающему типу, путем преобразования целого без знака к значению типа signed long, а затем значение signed long преобразуется в плавающий тип. Преобразования из unsigned long к типу float, double или long double производятся с потерей информации, если преобразуемое значение больше, чем максимальное положительное значение, которое может быть представлено для типа long.

Преобразования плавающих типов. Величины типа float преобразуются к типу double без изменения значения. Величины double и long double преобразуются к float c некоторой потерей точности. Если значение слишком велико для float, то происходит потеря значимости, о чем сообщается во время выполнения.

При преобразовании величины с плавающей точкой к целым типам она сначала преобразуется к типу long (дробная часть плавающей величины при этом отбрасывается), а затем величина типа long преобразуется к требуемому целому типу. Если значение слишком велико для long, то результат преобразования не определен.

Преобразования из float, double или long double к типу unsigned long производится с потерей точности, если преобразуемое значение больше, чем максимально возможное положительное значение, представленное типом long.

Преобразование типов указателя. Указатель на величину одного типа может быть преобразован к указателю на величину другого типа. Однако результат может быть не определен из-за отличий в требованиях к выравниванию и размерах для различных типов.

Указатель на тип void может быть преобразован к указателю на любой тип, и указатель на любой тип может быть преобразован к указателю на тип void без ограничений. Значение указателя может быть преобразовано к целой величине.

Метод преобразования зависит от размера указателя и размера целого типа следующим образом:

  • если размер указателя меньше размера целого типа или равен ему, то указатель преобразуется точно так же, как целое без знака;
  • если указатель больше, чем размер целого типа, то указатель сначала преобразуется к указателю с тем же размером, что и целый тип, и затем преобразуется к целому типу.

Целый тип может быть преобразован к адресному типу по следующим правилам:

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

Преобразования при вызове функции. Преобразования, выполняемые над аргументами при вызове функции, зависят от того, был ли задан прототип функции (объявление «вперед») со списком объявлений типов аргументов.

Если задан прототип функции и он включает объявление типов аргументов, то над аргументами в вызове функции выполняются только обычные арифметические преобразования.

Эти преобразования выполняются независимо для каждого аргумента. Величины типа float преобразуются к double, величины типа char и short преобразуются к int, величины типов unsigned char и unsigned short преобразуются к unsigned int. Могут быть также выполнены неявные преобразования переменных типа указатель. Задавая прототипы функций, можно переопределить эти неявные преобразования и позволить компилятору выполнить контроль типов.

Преобразования при приведении типов. Явное преобразование типов может быть осуществлено посредством операции приведения типов, которая имеет формат:

( имя-типа ) операнд .

В приведенной записи имя-типа задает тип, к которому должен быть преобразован операнд.

int i=2; long l=2; double d; float f; d=(double)i * (double)l; f=(float)d;

В данном примере величины i,l,d будут явно преобразовываться к указанным в круглых скобках типам.

Добавить комментарий Отменить ответ

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.

Arduino.ru

Можно ли как то целое число без дроби из float записать в int. мне просто ненужна дробь а только градусы в чистом виде без хвоста.

  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
  • Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии

kisoft аватар

Преобразование может быть разным, можно просто отбрасывать дробную часть, в этом случае если дробная часть меньше 0.5, то получаем нормальный результат, а если 0.9, то будет погрешность в 1 градус. Другой вариант, это преобразование с округлением до целого, тогда 0.9 будет преобразовано в 1 градус, что ближе к реальному значению. Какое именно преобразование нужно Вам, мы не знаем. Поскольку это зависит от задачи.

Как правильно преобразовать тип float в int и наоборот?

Приведенный ниже код выполняет быструю операцию обратного извлечения квадратного корня с помощью некоторых битовых хаков. Вероятно, алгоритм был разработан Silicon Graphics в начале 1990-х годов, а также появился в Quake 3. дополнительная информация

Однако я получаю следующее предупреждение от компилятора GCC C ++ : разыменование указателя с перетеканием типа нарушит правила строгого псевдонима

Должен ли я использовать static_cast , reinterpret_cast или dynamic_cast вместо этого в таких ситуациях?

8 ответов

Забудьте о слепках. Используйте memcpy .

Исходный код пытается инициализировать int32_t , сначала обращаясь к объекту float через указатель int32_t , в котором правила нарушаются. Приведение в стиле C эквивалентно reinterpret_cast , поэтому его изменение на reinterpret_cast не будет иметь большого значения.

Важное различие при использовании memcpy заключается в том, что байты копируются из float в int32_t , но к объекту float никогда не удается получить доступ через lvalue int32_t , потому что memcpy принимает указатели на void, а его внутренности «волшебны» и не нарушают правила сглаживания.

Единственное приведение, которое здесь будет работать, — это reinterpret_cast . (И даже тогда, по крайней мере, один компилятор будет стараться изо всех сил убедитесь, что это не сработает.)

Но что вы на самом деле пытаетесь сделать? Конечно есть лучшее решение, которое не требует каламбура. Есть очень и очень мало случаев, когда уместно использовать каламбур, и они все они находятся в очень, очень низкоуровневом коде, например, сериализация, или реализация стандартной библиотеки C (например, таких функций, как modf ). В противном случае (и, возможно, даже при сериализации) функции такие как ldexp и modf , вероятно, будут работать лучше, и, конечно, быть более читабельным.

Основываясь на ответах здесь, я создал современную функцию «псевдоприведения» для простоты применения.

Версия C99 (хотя большинство компиляторов поддерживают это, теоретически в некоторых может быть неопределенное поведение)

Универсальные версии (на основе принятого ответа)

Типы отливок одинакового размера:

Типы отливок любых размеров:

Используйте это как:

Обновление для C ++ 20

C ++ 20 представляет constexpr std::bit_cast в заголовок <bit> , который функционально эквивалентен для типов того же размера . Тем не менее, указанные выше версии по-прежнему полезны, если вы хотите реализовать эту функцию самостоятельно (предполагается, что constexpr не требуется) или если вы хотите поддерживать типы с разными размерами.

Приведение вызывает неопределенное поведение. Независимо от того, какую форму приведения вы используете, это все равно будет неопределенным поведением. Он не определен независимо от того, какой тип приведения вы используете.

Большинство компиляторов будут делать то, что вы ожидаете, но gcc любит быть злым и, вероятно, будет предполагать, что вы не назначили указатели, несмотря на все ваши указания, и изменит порядок операции, чтобы они давали какой-то странный результат.

Приведение указателя на несовместимый тип и разыменование его — неопределенное поведение. Единственное исключение — приведение его к или от char, поэтому единственным обходным путем является использование std::memcpy (согласно ответу Р. Мартиньо Фернандеса). (Я не уверен, насколько это определено с помощью объединений; хотя у него больше шансов на работу).

Тем не менее, вы не должны использовать приведение в стиле C в C ++. В этом случае ни static_cast не будет компилироваться, ни dynamic_cast , вынуждая вас использовать reinterpret_cast и reinterpret_cast , это серьезное предположение, что вы, возможно, нарушаете строгие правила псевдонима.

Единственное безопасное преобразование типа в массив — это массив char . Если вы хотите, чтобы один адрес данных можно было переключать на разные типы, вам понадобится union

Если у вас есть доступ к C ++ 20 или более поздней версии, вы можете использовать std::bit_cast

В ожидании реализации, если вы используете Clang, вы можете попробовать __builtin_bit_cast . Просто поменяйте броски вот так

Обновить

Я больше не считаю этот ответ правильным из-за обратной связи, которую я получил от комитета. Но я хочу оставить это в информационных целях. И я целенаправленно надеюсь, что этот ответ может быть исправлен комитетом (если он захочет это сделать). Т.е. В базовом оборудовании нет ничего, что могло бы сделать этот ответ неверным, это просто мнение комитета, которое делает это или нет.

Я добавляю ответ не для опровержения принятого ответа, а для его дополнения. Я считаю, что принятый ответ правильный и эффективный (и я только что проголосовал за него). Однако я хотел продемонстрировать другую технику, столь же правильную и эффективную:

Используя clang ++ с оптимизацией на -O3, я скомпилировал код Plasmacel, код Р. Мартиньо Фернандеса и этот код и сравнил сборочную линию за строкой. Все трое были идентичны. Это связано с тем, что компилятор решил скомпилировать его вот так. В равной степени компилятор мог создавать другой, неработающий код.

Здесь есть несколько хороших ответов, которые касаются проблемы набора текста.

Я хочу обратиться к части «быстрого вычисления обратного квадратного корня». Не используйте этот «трюк» на современных процессорах. Каждый основной вектор ISA имеет специальную аппаратную инструкцию для быстрого вычисления обратного квадратного корня. Каждый из них и быстрее, и точнее, чем этот часто копируемый небольшой взлом.

Все эти инструкции доступны через встроенные функции, поэтому их относительно легко использовать. В SSE вы хотите использовать rsqrtss (внутреннее: _mm_rsqrt_ss( ) ); в NEON вы хотите использовать vrsqrte (внутреннее: vrsqrte_f32( ) ); а в AltiVec вы хотите использовать frsqrte . Большинство ISA для графических процессоров имеют аналогичные инструкции. Эти оценки могут быть уточнены с использованием той же итерации Ньютона, и NEON даже имеет инструкцию vrsqrts для выполнения части уточнения в одной инструкции без необходимости загрузки констант.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *