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

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

float PiForSquares = 4.0;

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

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

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

4.0 не является строковым литералом; это двойной буквальный смысл!

Jonathan Leffler 30.12.2008 03:16

long float существовал до double, а double был синонимом long float; он был удален из стандарта C89.

Jonathan Leffler 30.12.2008 03:17

хотелось бы "двойного поплавка" :)

Johannes Schaub - litb 30.12.2008 12:11

Есть множество гарантий, окружающих <float.h>, в частности такие вещи, как FLT_DIG (я думаю, что он гарантированно сможет представлять 5 десятичных цифр, то есть целые числа от 0 до 99999).

tc. 24.07.2012 21:50

Этот ТАК вопрос также может быть интересен в отношении имен «одиночный» и «двойной».

zardosht 11.04.2020 20:29
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
16
5
8 737
12

Ответы 12

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

 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 году ...

Roddy 30.12.2008 03:04

Ну что, до 1985 года поплавок был частью C std? Весьма вероятно, что люди использовали арифметику с фиксированной точкой в ​​течение долгого времени.

Doug T. 30.12.2008 03:05

IIRC, термины «float» для 32-битных чисел с плавающей запятой и «double» для 64-битных double восходят к 60-м годам, до появления C. Вероятно, возникла с архитектурой IBM 360

Die in Sente 30.12.2008 03:59

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

shoosh 30.12.2008 07:25

C89 float может быть IEE754, но не обязательно.

MSalters 02.01.2009 18:05

Очень хорошее объяснение. Возможно, вы захотите добавить, что некоторые библиотеки / языки называют float синглом.

Jonathan C Dickinson 24.08.2009 16:03

Если память не изменяет (я думаю, что читал это в копии K&R 90-х годов, но это могло быть совершенно неверно), конкретная подмодель PDP-11, используемая в исходной разработке C и Unix, имела модуль с плавающей запятой, который мог только удерживать значения двойной точности в его регистрах; значения одинарной точности автоматически расширяются при загрузке из памяти. Таким образом, было «естественным» заставить C повсеместно продвигать одинарную точность в двойную - буквальные количества, продвижение незапрототипированных аргументов и обычные арифметические преобразования - все это отражает эту причуду.

zwol 05.01.2013 12:04

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

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

en.wikipedia.org/wiki/IEEE_754-1985 Хорошая идея, но IEEE-754 отодвигает C как минимум на десять лет ...
Roddy 30.12.2008 02:56

Два наиболее распространенных формата с плавающей запятой используют 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» означает «двойная точность».

Qwertie 30.12.2008 19:46

Кроме того, конечно, неверен размер long, который, конечно, был 4 (такой же, как int) с использованием компилятора BSD vax ... [«эквивалентность» int и long является причиной множества ошибок при портировании старое программное обеспечение для 64-битных (или 16-битных) платформ]

snogglethorpe 12.12.2011 10:48

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

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

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

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

Я не думаю, что это имеет, если быть более точным: он должен быть «не менее точным», а это совсем другое ...

Roddy 30.12.2008 21:28

Стандарт дает ему меньший эпсилон. Думаю, 1E-5 против 1E-7.

aib 31.12.2008 01:14

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

В 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.

Robert Gamble 30.12.2008 08:09

В C++ есть флаг, чтобы узнать, реализован ли ieee754: numeric_limits <double> :: is_iec559

Johannes Schaub - litb 30.12.2008 12:53

Точно так же в C99 есть макрос STDC_IEC_559, но он просто проверяет, имеет ли реализация намерение использовать IEEE. Я возражаю против утверждения «Опрашивающий неверен в отношении гарантий», когда C / C++ не гарантирует IEEE с плавающей запятой.

Robert Gamble 30.12.2008 16:27

Я также сомневаюсь в утверждении, что «почти все [современные] языки гарантируют реализацию двоичных чисел с плавающей запятой IEEE 754». Из всех языков, которые я использую, я могу вспомнить только один, который, как я знаю, гарантирует это.

Robert Gamble 30.12.2008 16:28

«одинарная точность» на самом деле не является широким термином. Фортран имел "настоящую" и "двойную точность".

Roddy 31.12.2008 01:04

Я не думаю, что IEEE «делал поправки на чип 80287» или даже на чип 8087. Многие 16-битные или 32-битные процессоры без FPU могут обрабатывать 80-битные значения с расширенной точностью более эффективно, чем 64-битные значения с двойной точностью. Добавление трех 64-битных значений потребует распаковки первых двух для разделения мантиссы и экспоненты, выравнивания значений, выполнения сложения, нормализации результата, упаковки результата, распаковки результата и третьего значения, выравнивания значений, выполнения сложения. , нормализуя результат и упаковывая результат. Использование 80-битного промежуточного типа ...

supercat 28.08.2015 00:12

... позволит исключить этапы нормализации, упаковки и распаковки, а во многих случаях повысит точность. Безопасное использование 80-битного промежуточного типа требует наличия 80-битного типа переменной - требование, которое многие компиляторы C испортили из-за плохой обработки C89 «длинного двойника» с вариативными функциями - но это был хороший дизайн с полезностью за пределами x87.

supercat 28.08.2015 00:14

Литералы

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.

Вы ищете термин «размер слова».

Jyaan 25.10.2010 21:40

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

В функции printf из C %f уже означает double, а %Lf означает long double. Что касается функции scanf, то вы правы.

Roland Illig 05.07.2010 11:14

Другие вопросы по теме