арифметические правила типа данных на языке c - PullRequest
3 голосов
/ 26 января 2011

в c-программировании, если я использую переменные k, X, Y, n в уравнении ниже (где exp () - математическая константа e, повышенная до (), pi = 3,14159 ... и j = sqrt (-1)) и все эти переменные объявлены как числа с плавающей запятой двойной точности 64b (где X - комплексное число), результатом для вывода будет также этот тип данных.

output = k * exp(2*pi*j*X*Y/n)

Теперь, если я хочу попытаться управлять памятью более разумно, я бы хотел сделать

k, Y и n равным 32-битному unsigned long int (от 0 до 4294967295)) и

pi, j и X должны быть 32-битными числами с плавающей запятой.

Мой вопрос: результатом вывода будет тип данных float (будем надеяться) или unsigned long int?То есть, есть ли в языке C некоторые правила по умолчанию, которые разумно заботятся о умножении числа с плавающей запятой и целого числа и возвращении результата в виде числа с плавающей запятой, или я должен управлять этим вручную, используя приведение типов и т. Д.?Просто интересно, есть ли что-то, о чем мне нужно беспокоиться в такой операции, или я могу оставить это на C, чтобы делать все разумно за кадром.

Ответы [ 3 ]

8 голосов
/ 26 января 2011

При выполнении арифметики с плавающими и целыми числами, он всегда будет приводить его к плавающему. То есть:

  • плавать * плавать = плавать
  • float * int = float
  • int * float = float
  • INT * INT = Int

Вы получите «целочисленную математику», только если все значения являются целыми числами.

5 голосов
/ 26 января 2011

Это может быть довольно уродливо. Компилятор просматривает типы операндов для операции single и переводит оба типа в «больший» тип (например, если один int, а другой double, он преобразует int до double, затем выполните операцию).

В вашем случае это может привести к довольно неожиданным результатам. Прямо сейчас у вас есть: 2*pi*j*X*Y/n. Операторы группируются слева направо, так что это эквивалентно ((((2*pi)*j)*X)*Y)/n. В этом случае это, вероятно, сработает достаточно хорошо - один из операндов в «первой» операции является плавающим, поэтому все остальные операнды будут преобразованы в плавающее число, как вы хотите. Однако, если вы переставите операнды (даже способом, который кажется эквивалентным в обычной математике), результат может быть совершенно другим. Например, если вы измените его на 2*Y/n*pi*j*X, часть 2*Y/n будет выполнена с использованием арифметики integer , потому что 2, Y и n - все целые числа. Это означает, что деление будет делаться на целые числа, давая целочисленный результат, и только после того целочисленного результата будет получено, если это целое число будет преобразовано в число с плавающей точкой для умножения на pi.

Итог: если вы не имеете дело с чем-то вроде большого массива, так что преобразование в меньшие типы может реально сэкономить немало памяти, вам, как правило, гораздо лучше оставить все операнды одного типа, если это возможно , Я также хотел бы отметить, что в этом случае ваша попытка «интеллектуального управления памятью», вероятно, в любом случае не принесет пользы - на типичном текущем компьютере long int и float являются 32-битными, поэтому они оба используют одинаковое количество памяти в любом случае. Также обратите внимание, что exp принимает double в качестве операнда, так что даже если вы сделаете float математику для остальных, он все равно будет повышен до double. Также обратите внимание, что преобразования из int в float (и обратно) могут быть довольно медленными.

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

2 голосов
/ 26 января 2011

«Обычные арифметические преобразования» в языке C работают так: float:

  • Если оба операнда имеют одинаковый тип, то все в порядке.
  • Если один является двойным, другой преобразуется в двойной.
  • Иначе, если один из них является плавающим, другой преобразуется в плавающий.
  • Иначе, если они оба являются целыми числами, применяются различные правила "целочисленных повышений".

Числовая константа "1" рассматривается как int. Числовая константа "1.0" считается двойной. Числовая константа "1.0f" рассматривается как число с плавающей запятой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...