Почему типы с плавающей запятой в c / c ++ так странно названы?

C ++ предлагает три типа с плавающей запятой: float, double и long double. Я нечасто использую в коде числа с плавающей запятой, но когда я это делаю, меня всегда ловят предупреждения в безобидных строках вроде

float PiForSquares = 4.0;

Проблема в том, что буквальный 4.0 - это двойник, а не поплавок, что раздражает.

Для целочисленных типов у нас есть short int, int и long int, что довольно просто. Почему в C нет только коротких чисел с плавающей запятой, плавающих и длинных с плавающей запятой? А откуда вообще взялся «двойник»?

РЕДАКТИРОВАТЬ: кажется, что отношения между плавающими типами аналогичны отношениям между целыми числами. double должен быть не меньше float, а long double должен быть не меньше double. Никаких других гарантий точности / дальности не дается.


person Community    schedule 29.12.2008    source источник
comment
4.0 не является строковым литералом; это двойной буквальный смысл!   -  person Jonathan Leffler    schedule 30.12.2008
comment
long float существовал до double, а double был синонимом long float; он был удален из стандарта C89.   -  person Jonathan Leffler    schedule 30.12.2008
comment
то, что мне хотелось бы, это двойной поплавок :)   -  person Johannes Schaub - litb    schedule 30.12.2008
comment
Существует множество гарантий, связанных с <float.h>, в частности с такими вещами, как FLT_DIG (я думаю, что он гарантированно может представлять 5 десятичных цифр, то есть целые числа от 0 до 99999).   -  person tc.    schedule 24.07.2012
comment
Этот вопрос SO также может быть интересен в отношении имен single и double.   -  person zardosht    schedule 11.04.2020


Ответы (12)


Термины «одинарная точность» и «двойная точность» возникли в FORTRAN и уже широко использовались, когда был изобретен C. На машинах начала 1970-х годов одинарная точность была значительно более эффективной и, как сегодня, использовала вдвое меньше памяти, чем двойная точность. Следовательно, это было разумное значение по умолчанию для чисел с плавающей запятой.

long double был добавлен намного позже, когда стандарт IEEE сделал поправку на чип Intel 80287 с плавающей запятой, который использовал 80-битные числа с плавающей запятой вместо классической 64-битной двойной точности.

Вопрос о гарантиях неверен; сегодня почти все языки гарантируют реализацию двоичных чисел с плавающей запятой IEEE 754 с одинарной точностью (32 бита) и двойной точностью (64 бита). Некоторые также предлагают повышенную точность (80 бит), которая отображается в C как long double. Стандарт IEEE с плавающей запятой, возглавляемый Уильямом Каханом, был триумфом хорошей инженерии над целесообразностью: на машинах того времени он выглядел непомерно дорогим, но на сегодняшних машинах он очень дешев, а переносимость и предсказуемость плавающих операций IEEE - номера точек должны ежегодно экономить миллиарды долларов.

person Norman Ramsey    schedule 30.12.2008
comment
OP говорит о C и C ++, ни один из которых не гарантирует IEEE 754. - person Robert Gamble; 30.12.2008
comment
В c ++ есть флаг, чтобы узнать, реализован ли ieee754: numeric_limits ‹double› :: is_iec559 - person Johannes Schaub - litb; 30.12.2008
comment
Точно так же в C99 есть макрос STDC_IEC_559, но они просто проверяют, имеет ли реализация намерение использовать IEEE. Я возражаю против того, что оператор Вопросника неверен в отношении гарантий, когда C / C ++ не гарантирует IEEE с плавающей запятой. - person Robert Gamble; 30.12.2008
comment
Я также сомневаюсь в утверждении, что почти все [современные] языки гарантируют реализацию двоичных чисел с плавающей запятой IEEE 754. Из всех языков, которые я использую, я могу вспомнить только один, который, как я знаю, гарантирует это. - person Robert Gamble; 30.12.2008
comment
одинарная точность на самом деле не является фортраном. Фортран имел настоящую и двойную точность. - person Roddy; 31.12.2008
comment
Я не думаю, что IEEE делал скидку на чип 80287 или даже на чип 8087. Многие 16-битные или 32-битные процессоры без FPU могут обрабатывать 80-битные значения с расширенной точностью более эффективно, чем 64-битные значения с двойной точностью. Добавление трех 64-битных значений потребует распаковки первых двух для разделения мантиссы и экспоненты, выравнивания значений, выполнения сложения, нормализации результата, упаковки результата, распаковки результата и третьего значения, выравнивания значений, выполнения сложения. , нормализуя результат и упаковывая результат. Использование 80-битного промежуточного типа ... - person supercat; 28.08.2015
comment
... позволит устранить шаги нормализации, упаковки и распаковки, а во многих случаях повысит точность. Для безопасного использования 80-битного промежуточного типа требуется наличие 80-битного типа переменной - требование, которое многие компиляторы C испортили из-за плохой обработки C89 длинного двойного числа с вариативными функциями, - но это был хороший дизайн с полезностью за пределами х87. - person supercat; 28.08.2015

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

 float f = 4.0f;
 long double f = 4.0l;

Двойное значение по умолчанию, потому что это то, что использует большинство людей. Длинные удвоения могут быть излишними, а поплавки имеют очень плохую точность. Double работает практически для всех приложений.

Почему именно именование? Однажды все, что у нас было, были 32-битные числа с плавающей запятой (ну, на самом деле все, что у нас было, это числа с фиксированной запятой, но я отвлекся). В любом случае, когда плавающая точка стала популярной функцией в современных архитектурах, C, вероятно, был языком dujour, и ему было дано название «float». Казалось, имеет смысл.

В то время можно было подумать о double, но на самом деле он не был реализован в процессорах cpu / fp того времени, которые были 16- или 32-битными. Когда двойник стал использоваться в большем количестве архитектур, C, вероятно, дошел до его добавления. C нужно было какое-то имя для чего-то вдвое большего размера, чем поплавок, поэтому мы получили двойное. Потом кому-то понадобилась еще большая точность, мы подумали, что он сумасшедший. Мы все равно добавили его. Имя четверка (?) Было излишним. Длинный дубль был достаточно хорош, и никто не наделал много шума.

Отчасти путаница заключается в том, что доброе "int", кажется, со временем меняется. Раньше «int» означало 16-битное целое число. Однако число с плавающей запятой привязано к стандарту IEEE как 32-битное число с плавающей запятой IEEE. По этой причине C сохранил значение с плавающей запятой, определяемое как 32-битное, и сделал double и long double для ссылки на более длинные стандарты.

person Doug T.    schedule 29.12.2008
comment
Спасибо. но если исходным типом был float, почему литералы двойные? И я думаю, что объяснение IEEE хорошее - но неверное: IEEE-754 был опубликован в 1985 году ... - person Roddy; 30.12.2008
comment
Что ж, до 1985 года поплавок был частью C std? Весьма вероятно, что люди использовали арифметику с фиксированной точкой в ​​течение долгого времени. - person Doug T.; 30.12.2008
comment
IIRC, термины float для 32-битных чисел с плавающей запятой и double для 64-битных double восходят к 60-м годам, до появления C. Вероятно, возникла с архитектурой IBM 360 - person Die in Sente; 30.12.2008
comment
Очень плохая четкость - скажите об этом производителю видеокарты. весь графический процессор и практически вся графика всегда выполняется с плавающей точкой. - person shoosh; 30.12.2008
comment
C89 float может быть IEE754, но не обязательно. - person MSalters; 02.01.2009
comment
Очень хорошее объяснение. Возможно, вы захотите добавить, что некоторые библиотеки / языки называют float синглом. - person Jonathan C Dickinson; 24.08.2009
comment
Если память не изменяет (я думаю, я читал это в копии K&R 90-х годов, но это могло быть совершенно неверно), конкретная подмодель PDP-11, используемая в исходной разработке C и Unix, имела модуль с плавающей запятой, который мог только удерживать значения двойной точности в его регистрах; значения одинарной точности автоматически расширяются при загрузке из памяти. Таким образом, было «естественным» заставить C повсеместно продвигать одинарную точность в двойную - буквальные количества, продвижение незапрототипированных аргументов и обычные арифметические преобразования - все это отражает эту причуду. - person zwol; 05.01.2013

Литералы

Проблема в том, что буквальный 4.0 - это двойник, а не поплавок, что раздражает.

С константами есть одно важное различие между целыми числами и числами с плавающей запятой. В то время как относительно легко решить, какой целочисленный тип использовать (вы выбираете достаточно маленький, чтобы удерживать значение, с некоторой дополнительной сложностью для подписанных / неподписанных), с float это не так просто. Многие значения (включая простые, такие как 0,1) не могут быть точно представлены числами с плавающей запятой, поэтому выбор типа влияет не только на производительность, но и на результат. Кажется, что в этом случае разработчики языка C предпочли надежность по сравнению с производительностью, и поэтому они решили, что представление по умолчанию должно быть более точным.

История

Почему в C нет только коротких чисел с плавающей запятой, плавающих и длинных с плавающей запятой? А откуда вообще взялся «двойник»?

Термины «одинарная точность» и «двойная точность» возникли в FORTRAN и уже широко использовались, когда был изобретен C.

person Suma    schedule 30.12.2008

Во-первых, эти имена не относятся к C ++, но являются довольно распространенной практикой для любого типа данных с плавающей запятой, который реализует IEEE 754.

Имя double относится к «двойной точности», в то время как float часто называют «одинарной точностью».

person jalf    schedule 29.12.2008
comment
en.wikipedia.org/wiki/IEEE_754-1985 Хорошая идея, но IEEE-754 постдаты C не менее чем на десять лет ... - person Roddy; 30.12.2008

В двух наиболее распространенных форматах с плавающей запятой используются 32-битные и 64-битные форматы, причем более длинный «удваивает» размер первого, поэтому он был назван «двойным».

person Robert Gamble    schedule 29.12.2008

Двойник назван так, потому что он вдвое превышает «точность» числа с плавающей запятой. На самом деле это означает, что он использует вдвое больше места, чем значение с плавающей запятой - если ваш float 32-битный, то ваш double будет 64-битным.

Имя двойной точности несколько неверно, поскольку точность с плавающей запятой двойной точности равна мантиссе 52 бита, тогда как точность мантиссы с плавающей запятой одинарной точности составляет 23 бита (удвоение, равное 56). Подробнее о плавающей запятой здесь: Floating Point - Wikipedia, включая ссылки внизу на статьи по одиночному и поплавки двойной точности.

Имя long double, вероятно, просто по той же традиции, что и длинное целое число против короткого целого числа для целочисленных типов, за исключением того, что в этом случае они поменяли его местами, поскольку 'int' эквивалентно 'long int'.

person Ed Carrel    schedule 30.12.2008

В представлении с фиксированной точкой после точки счисления ставится фиксированное количество цифр (обобщение десятичной точки в десятичных представлениях). В отличие от этого представления с плавающей запятой, где точка счисления может перемещаться или плавать в пределах цифр представляемого числа. Отсюда и название «представление с плавающей запятой». Это было сокращенно «плавать».

В K&R C float относится к представлениям с плавающей запятой с 32-битными двоичными представлениями, а double относится к представлениям с плавающей запятой с 64-битными двоичными представлениями или к удвоенному размеру и откуда происходит имя. Однако исходная спецификация K&R требовала, чтобы все вычисления с плавающей запятой выполнялись с двойной точностью.

В первоначальном стандарте IEEE 754 (IEEE 754-1985), золотом стандарте для представлений с плавающей запятой и арифметики, были предусмотрены определения для двоичных представлений чисел с плавающей запятой одинарной и двойной точности. Числа с двойной точностью были названы удачно, поскольку они были представлены вдвое большим количеством битов, чем числа с одинарной точностью.

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

person jason    schedule 30.12.2008

Их называют одинарной и двойной точностью, потому что они связаны с естественным размером (не уверен в этом термине) процессора. Таким образом, одинарная точность 32-битного процессора будет иметь длину 32 бита, а его двойная точность будет вдвое больше - 64 бита. Они просто решили назвать тип с одинарной точностью "float" в C.

person Ray Hidayat    schedule 01.02.2009
comment
Вы ищете термин «размер слова». - person Jyaan; 25.10.2010

double - это сокращение от «двойной точности». long double, я полагаю, происходит из-за нежелания добавлять другое ключевое слово, когда в процессорах начал появляться тип с плавающей запятой с еще более высокой точностью.

person erikkallen    schedule 29.12.2008

Ладно, исторически так было раньше:

В исходных машинах, используемых для C, 16-битные слова были разбиты на 2 байта, а char - один байт. Адреса были 16-битными, поэтому sizeof(foo*) было 2, sizeof(char) было 1. Целое число было 16 бит, поэтому sizeof(int) было также 2. Затем появились машины VAX (расширенная адресация), и адрес был 32-битным. Символ по-прежнему составлял 1 байт, но теперь sizeof(foo*) было 4.

Произошла некоторая путаница, которая утихла в компиляторах Беркли, так что short теперь составляет 2 байта, а int - 4 байта, поскольку они хорошо подходят для эффективного кода. Длинный превратился в 8 байтов, потому что существовал эффективный метод адресации для 8-байтовых блоков, которые назывались двойными словами. Блоки по 4 байта были словами и, конечно, достаточно, блоки по 2 байта были полусловами.

Реализация чисел с плавающей запятой была такова, что они умещались в отдельные слова или двойные слова. Чтобы оставаться последовательным, двойное слово с плавающей запятой было названо «двойным».

person Charlie Martin    schedule 30.12.2008
comment
Я не думаю, что это правильно. Все это история целых чисел ... все истории с плавающей запятой, которые я слышал, говорят, что double означает двойную точность. - person Qwertie; 30.12.2008
comment
Кроме того, конечно, неверен размер long, который, конечно, был 4 (такой же, как int) с использованием компилятора BSD vax ... [эквивалентность int и long является причиной множества ошибок при переносе старого программного обеспечения на 64-битные (или 16-битные) платформы] - person snogglethorpe; 12.12.2011

Следует отметить, что double НЕ должен иметь возможность удерживать значения, превышающие по величине значения float; это только должно быть более точным.

person aib    schedule 30.12.2008
comment
Я не думаю, что должен быть более точным: он должен быть не менее точным, а это совсем другое ... - person Roddy; 30.12.2008
comment
Стандарт дает ему меньший эпсилон. Думаю, 1E-5 против 1E-7. - person aib; 31.12.2008

отсюда% f для типа с плавающей запятой и% lf для длинного числа с плавающей запятой, что аналогично double.

person EvilTeach    schedule 01.02.2009
comment
В функции printf из C %f уже означает double, а %Lf означает long double. Что касается функции scanf, вы правы. - person Roland Illig; 05.07.2010