C++ предлагает три типа с плавающей запятой: float, double и long double. Я нечасто использую числа с плавающей точкой в своем коде, но когда я это делаю, меня всегда ловят предупреждения в безобидных строках вроде
float PiForSquares = 4.0;
Проблема в том, что буквальное 4.0 - это двойник, а не поплавок, что раздражает.
Для целочисленных типов у нас есть short int, int и long int, что довольно просто. Почему в C нет только коротких чисел с плавающей запятой, плавающих и длинных с плавающей запятой? А откуда вообще взялся «двойник»?
Обновлено: кажется, что отношения между плавающими типами аналогичны отношениям между целыми числами. double должен быть как минимум такой же большой, как float, а long double как минимум такой же большой, как double. Никаких других гарантий точности / дальности не дается.
long float существовал до double, а double был синонимом long float; он был удален из стандарта C89.
хотелось бы "двойного поплавка" :)
Есть множество гарантий, окружающих <float.h>, в частности такие вещи, как FLT_DIG (я думаю, что он гарантированно сможет представлять 5 десятичных цифр, то есть целые числа от 0 до 99999).
Этот ТАК вопрос также может быть интересен в отношении имен «одиночный» и «двойной».





Вы, наверное, знали это, но вы может делаете буквальные числа с плавающей запятой / длинные удвоения
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 std как 32-битное число с плавающей запятой IEEE. По этой причине C сохранил значение float, определенное как 32-битное, и сделал double и long double для ссылки на более длинные стандарты.
Спасибо. но если исходным типом было "float", почему литералы двойные? И я думаю, что объяснение IEEE хорошее - но неверное: IEEE-754 был опубликован в 1985 году ...
Ну что, до 1985 года поплавок был частью C std? Весьма вероятно, что люди использовали арифметику с фиксированной точкой в течение долгого времени.
IIRC, термины «float» для 32-битных чисел с плавающей запятой и «double» для 64-битных double восходят к 60-м годам, до появления C. Вероятно, возникла с архитектурой IBM 360
«Очень плохая точность» - скажите производителю видеокарты. все графические процессоры и практически вся графика всегда выполняются с поплавками.
C89 float может быть IEE754, но не обязательно.
Очень хорошее объяснение. Возможно, вы захотите добавить, что некоторые библиотеки / языки называют float синглом.
Если память не изменяет (я думаю, что читал это в копии K&R 90-х годов, но это могло быть совершенно неверно), конкретная подмодель PDP-11, используемая в исходной разработке C и Unix, имела модуль с плавающей запятой, который мог только удерживать значения двойной точности в его регистрах; значения одинарной точности автоматически расширяются при загрузке из памяти. Таким образом, было «естественным» заставить C повсеместно продвигать одинарную точность в двойную - буквальные количества, продвижение незапрототипированных аргументов и обычные арифметические преобразования - все это отражает эту причуду.
Во-первых, эти имена не относятся к C++, но являются довольно распространенной практикой для любого типа данных с плавающей запятой, который реализует IEEE 754.
Имя double относится к «двойной точности», в то время как float часто называют «одинарной точностью».
Два наиболее распространенных формата с плавающей запятой используют 32-битный и 64-битный формат, более длинный - «удваивает» размер первого, поэтому он был назван «двойным».
double - это сокращение от «двойной точности». long double, я полагаю, происходит из-за нежелания добавлять другое ключевое слово, когда в процессорах начал появляться тип с плавающей запятой с еще более высокой точностью.
Ладно, исторически так было раньше:
В исходных машинах, используемых для 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-байтовые блоки были полуслова.
Реализация чисел с плавающей запятой была такова, что они умещались в отдельные слова или двойные слова. Чтобы оставаться последовательным, двойное слово с плавающей запятой было названо «двойным».
Я не думаю, что это правильно. Все это история целых чисел ... каждая история с плавающей запятой, которую я слышал, говорит, что «double» означает «двойная точность».
Кроме того, конечно, неверен размер long, который, конечно, был 4 (такой же, как int) с использованием компилятора BSD vax ... [«эквивалентность» int и long является причиной множества ошибок при портировании старое программное обеспечение для 64-битных (или 16-битных) платформ]
Двойник назван так, потому что он вдвое превышает «точность» числа с плавающей запятой. На самом деле это означает, что он использует вдвое больше места, чем значение с плавающей запятой - если ваш float 32-битный, то ваш double будет 64-битным.
Имя двойной точности немного неверно, поскольку точность с плавающей запятой двойной точности равна мантиссе 52 бита, а точность с плавающей точкой одинарной точности составляет 23 бита (удвоение - 56). Подробнее о плавающей запятой здесь: Плавающая точка - Википедия, включая ссылки внизу на статьи о поплавках одинарной и двойной точности.
Имя long double, вероятно, просто по той же традиции, что и длинное целое число против короткого целого числа для целочисленных типов, за исключением того, что в этом случае они поменяли его местами, поскольку 'int' эквивалентно 'long int'.
Следует отметить, что double НЕ должен быть способен удерживать значения, превышающие по величине значения float; только должно быть больше точный.
Я не думаю, что это имеет, если быть более точным: он должен быть «не менее точным», а это совсем другое ...
Стандарт дает ему меньший эпсилон. Думаю, 1E-5 против 1E-7.
В представлении с фиксированной точкой после точки счисления ставится фиксированное количество цифр (обобщение десятичной точки в десятичных представлениях). В отличие от этого представления с плавающей запятой, где точка счисления может перемещаться или плавать в пределах цифр представляемого числа. Отсюда и название «представление с плавающей запятой». Это было сокращенно «плавать».
В K&R C float относится к представлениям с плавающей запятой с 32-битными двоичными представлениями, а double относится к представлениям с плавающей запятой с 64-битными двоичными представлениями или двойным размером и откуда происходит имя. Однако исходная спецификация K&R требовала, чтобы все вычисления с плавающей запятой выполнялись с двойной точностью.
В первоначальном стандарте IEEE 754 (IEEE 754-1985), золотом стандарте для представлений с плавающей запятой и арифметики, были предусмотрены определения для двоичных представлений чисел с плавающей запятой одинарной и двойной точности. Числа с двойной точностью были названы удачно, поскольку они были представлены вдвое большим количеством битов, чем числа с одинарной точностью.
Для получения подробной информации о представлениях с плавающей запятой прочтите Дэвида Голдберга статья, Что должен знать каждый компьютерный ученый об арифметике с плавающей запятой.
Термины «одинарная точность» и «двойная точность» возник в FORTRAN уже широко использовались, когда был изобретен C. На машинах начала 1970-х годов одинарная точность была значительно эффективнее и сегодня использовали вдвое меньше памяти, чем двойная точность. Следовательно, для чисел с плавающей запятой это было разумный дефолт.
long double был добавлен намного позже, когда стандарт IEEE допускал использование микросхемы с плавающей запятой Intel 80287, которая использовала 80-битные числа с плавающей запятой вместо классической 64-битной двойной точности.
Вопрос о гарантиях неверен; сегодня почти все языки гарантируют реализацию двоичных чисел с плавающей запятой IEEE 754 с одинарной точностью (32 бита) и двойной точностью (64 бита). Некоторые также предлагают повышенная точность (80 бит), который отображается в C как long double. Стандарт IEEE с плавающей запятой, возглавляемый Уильямом Каханом, был триумфом хорошей инженерии над целесообразностью: на машинах того времени он выглядел непомерно дорогим, но на сегодняшних машинах он очень дешев, а переносимость и предсказуемость плавающих операций IEEE - номера точек должны ежегодно экономить миллиарды долларов.
OP говорит о C и C++, ни один из которых не гарантирует IEEE 754.
В C++ есть флаг, чтобы узнать, реализован ли ieee754: numeric_limits <double> :: is_iec559
Точно так же в C99 есть макрос STDC_IEC_559, но он просто проверяет, имеет ли реализация намерение использовать IEEE. Я возражаю против утверждения «Опрашивающий неверен в отношении гарантий», когда C / C++ не гарантирует IEEE с плавающей запятой.
Я также сомневаюсь в утверждении, что «почти все [современные] языки гарантируют реализацию двоичных чисел с плавающей запятой IEEE 754». Из всех языков, которые я использую, я могу вспомнить только один, который, как я знаю, гарантирует это.
«одинарная точность» на самом деле не является широким термином. Фортран имел "настоящую" и "двойную точность".
Я не думаю, что IEEE «делал поправки на чип 80287» или даже на чип 8087. Многие 16-битные или 32-битные процессоры без FPU могут обрабатывать 80-битные значения с расширенной точностью более эффективно, чем 64-битные значения с двойной точностью. Добавление трех 64-битных значений потребует распаковки первых двух для разделения мантиссы и экспоненты, выравнивания значений, выполнения сложения, нормализации результата, упаковки результата, распаковки результата и третьего значения, выравнивания значений, выполнения сложения. , нормализуя результат и упаковывая результат. Использование 80-битного промежуточного типа ...
... позволит исключить этапы нормализации, упаковки и распаковки, а во многих случаях повысит точность. Безопасное использование 80-битного промежуточного типа требует наличия 80-битного типа переменной - требование, которое многие компиляторы C испортили из-за плохой обработки C89 «длинного двойника» с вариативными функциями - но это был хороший дизайн с полезностью за пределами x87.
The problem is that the literal 4.0 is a double, not a float - Which is irritating.
С константами есть одно важное различие между целыми числами и числами с плавающей запятой. В то время как относительно легко решить, какой целочисленный тип использовать (вы выбираете достаточно маленький, чтобы удерживать значение, с некоторой дополнительной сложностью для подписанных / неподписанных), с float это не так просто. Многие значения (включая простые, такие как 0,1) не могут быть точно представлены числами с плавающей запятой, поэтому выбор типа влияет не только на производительность, но и на результат. Кажется, что в этом случае разработчики языка C предпочли надежность по сравнению с производительностью, и поэтому они решили, что представление по умолчанию должно быть более точным.
Why doesn't C just have short float, float and long float? And where on earth did "double" come from?
Термины «одинарная точность» и «двойная точность» возникли в FORTRAN и уже широко использовались, когда был изобретен C.
Их называют одинарной и двойной точностью, потому что они связаны с естественным размером (не уверен в этом термине) процессора. Таким образом, одинарная точность 32-битного процессора будет иметь длину 32 бита, а его двойная точность будет вдвое больше - 64 бита. Они просто решили назвать тип с одинарной точностью "float" в C.
Вы ищете термин «размер слова».
отсюда% f для типа с плавающей запятой и% lf для длинного числа с плавающей запятой, что аналогично double.
В функции printf из C %f уже означает double, а %Lf означает long double. Что касается функции scanf, то вы правы.
4.0 не является строковым литералом; это двойной буквальный смысл!