Всегда ли возврат к двойному плаванию возвращает значение?
Выполняет ли листинг double
до float
одинаковый результат или могут быть некоторые "округляющие различия"?
Например, x
в
float x = (float)0.123456789d;
всегда одно и то же значение?
А как насчет того, чтобы сбрасывать float в double, а затем отбрасывать его обратно на float, т.е. (float)(double)someFloat
?
В основном заинтересованы в том, что результаты на С#, но не стесняйтесь делиться, если у вас есть знания о том, как это работает на других языках.
Ответы
Ответ 1
Результаты не должны зависеть от языка, если язык не отличается от спецификации IEEE.
Все поплавки могут быть точно представлены как удвоенные, поэтому в оба конца от float до double to float должно быть такое же значение, с которого вы начали.
Аналогично, при любом добавлении значения double для float всегда должен быть одинаковый результат, но, конечно, существует много разных двойных значений, которые усекаются до одного и того же значения float.
Ответ 2
Если вы отбрасываете double
до float
, вы теряете точность и данные. Upcasting a float
до a double
является расширяющимся преобразованием; никакие данные не теряются, если они затем сработали с округлением... то есть, если вы не сделаете что-то по значению до того, как он сбрасывает его обратно в float.
Числа с плавающей запятой жертвуют точностью и точностью для диапазона. Одноточечные поплавки дают вам 32-битную точность; двойная точность дает вам 64 бит. Но они могут представлять значения за пределами границ, которые укажет базовая точность.
С# float
и double
- значения с плавающей запятой IEEE 754.
Эффективная точность мантиссы на 1 бит больше, чем ее кажущийся размер (магия с плавающей запятой).
Некоторые ресурсы с плавающей запятой CLR для вас:
Эта статья, вероятно, является канонической статьей об опасностях и ловушках арифметики с плавающей запятой. Если вы не являетесь членом ACM, нажмите ссылку на заголовок, чтобы найти общедоступную загрузку статьи:
- Дэвид Голдберг. 1991. Что каждый компьютерный ученый должен знать о арифметике с плавающей запятой. ACM Comput. Surv. 23, 1 (март 1991 года), 5-48. DOI = 10.1145/103162.103163 http://doi.acm.org/10.1145/103162.103163
Абстрактный
Арифметика с плавающей точкой рассматривается многими как эзотерический субъект. Это довольно удивительно, поскольку плавающая точка вездесуща в компьютерных системах: Почти каждый язык имеет тип данных с плавающей запятой; компьютеров с ПК до суперкомпьютеры имеют ускорители с плавающей запятой; большинство компиляторов будут время от времени компилировать алгоритмы с плавающей запятой; и практически каждый система должна реагировать на исключения с плавающей запятой, такие как переполнение. Эта бумага представляет учебное пособие по аспектам с плавающей точкой, которые оказывают непосредственное влияние на дизайнеров компьютерных систем. Он начинается с фона с плавающей точкой ошибки представления и округления, продолжается с обсуждением плавающего IEEE и заканчивается примерами того, как разработчики компьютерных систем могут лучше поддерживать плавающие точки.
Ответ 3
Двойной должен иметь возможность точно удерживать все возможные значения поплавка. Приведение float в double не должно изменять значение, а возврат к float должен возвращать исходное значение, если вы не выполняли никаких вычислений в double в то же время.
Ответ 4
Учитывая, что они имеют различную точность, даже я вы делаете от меньшей точности до более широкой (я полагаю, это на самом деле ваше сомнение), результат не всегда может быть одинаковым.
Операции с плавающей точкой, особенно литье, всегда являются предметом усечения/округления и любого другого приближения.
Ответ 5
В некоторых случаях самое близкое представление float
к числовой величине может отличаться от значения, полученного округлением ближайшего представления double
до float
. Две такие величины: 12 344 321,4999999991 и 12,345,678.50000000093. Целочисленные числа выше и ниже обеих этих величин точно представлены как float
, но ближайший double
к каждому из них имеет дробную часть ровно 0,5. Поскольку преобразование таких значений double
(между 2 ^ 23 и 2 ^ 24, с долей от 0,5) до float
будет округлено до ближайшего четного целого; компилятор в каждом случае заканчивает округление от значения, которое было бы ближе к исходному номеру.
Обратите внимание, что на практике компилятор, по-видимому, анализирует числа как double
, а затем преобразовывается в float
, поэтому хотя 12344321.4999999991f должен округлить до 12344321f, он округляется до 12344322f. Аналогично, 12345678.50000000093f должен округлить до 12345679f, но раундов до 12345678f, поэтому даже в случаях, когда конверсия в double
, а затем float
теряет точность, таких потерь при конверсиях нельзя избежать, указав числа непосредственно как float
.
Кстати, значения 12344321.4999999992f и 12345678.50000000094f округлены правильно.
Ответ 6
Числа с плавающей запятой в С# хранятся в формате IEEE 754 (http://en.wikipedia.org/wiki/IEEE_754). Этот формат состоит из двух частей: цифр и экспоненты. Удвоенные номера содержат 52 цифры, а поплавки - 23 цифры. База - 2, а не десять. Итак, для вашего примера выше (0.123456789) цифры будут 111010110111100110100010101 (двоичное представление 123456789). Это 27 цифр, которые удобно вписываются в двойной, но не в поплавок, так что да, точность будет потеряна при конвертации в оба конца.
С другой стороны, если ваш номер равен 0.123456, цифры будут 11110001001000000 (17 цифр), которые удобно помещаются как в поплавке, так и в десятичной системе, поэтому вы не теряете точности в обратном направлении.
Ответ 7
Это скомпилировано с gcc на mac.,,
#include <stdio.h>
int main()
{
double x = 0.123456789;
float y = x;
double z = y;
printf ("x=%9.9f\n",x);
printf ("y=%9.9f\n",y);
printf ("z=%9.9f\n",z);
}
Выплевывает это.,
./a.out
x=0.123456789
y=0.123456791
z=0.123456791