Почему преобразование в режиме non-strictfp считается потерей информации?

Я понимаю, что преобразование в режиме strictfp используется для переносимости, а не для точности, как указано в этом вопросе. Однако в спецификации языка Java, Java SE 8 Edition говорится, что

Расширяющее примитивное преобразование из float в double, не являющееся strictfp, может привести к потере информации об общей величине преобразованного значения.

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

ИЗМЕНИТЬ:

Формулировка «... может потерять информацию о...» в спецификации дала мне ощущение, что преобразование в режиме без strictfp не имеет какой-то точности по сравнению с преобразованием в режиме strictfp. Для меня это не имело смысла, потому что преобразование в режиме non-strictfp, возможно, использует промежуточные значения с более высокой точностью. Этот вопрос был впервые написан на основе этого понимания и может показаться не таким желательным, как вы ожидали.


person b1sub    schedule 31.01.2016    source источник
comment
... что расширяющее примитивное преобразование, которое является strictfp, предназначено для точности ... ну, я полагаю. Практическая точка зрения состоит в том, что все представления с плавающей запятой являются приближениями к фактическим значениям, даже если подмножество значений может быть случайно представлено точно.   -  person scottb    schedule 31.01.2016
comment
@scottb Связанный ответ предполагает, что без ключевого слова strictfp значение, скорее всего, будет точным. Мне кажется, что выражение strictfp не всегда точное.   -  person b1sub    schedule 31.01.2016
comment
Не strictfp float может иметь показатель степени, который меньше, чем наименьший двойной показатель степени. Плавающий strictfp не может.   -  person Patricia Shanahan    schedule 31.01.2016
comment
@PatriciaShanahan Если это правда, то не является ли нестрогий fp более точным? Почему спецификация языка Java описывает его как потеря информации?   -  person b1sub    schedule 31.01.2016
comment
@Il-seobBae Non-strictfp может избежать потери памяти до нуля, что могло бы произойти в strictfp. В этом смысле он точнее.   -  person Patricia Shanahan    schedule 31.01.2016
comment
@PatriciaShanahan Вы хотите сказать, что недополнение необходимо для адекватного представления числового значения? Я понял твою мысль, но я ее почти не понимаю. Можете ли вы привести конкретный пример, который предполагает, что недополнение является разумным результатом?   -  person b1sub    schedule 31.01.2016
comment
Что вы имеете в виду под более точным? Если вы имеете в виду, что диапазон представляемых значений больше, это может быть или не быть правдой, и если это правда, это может быть или не быть правдой согласованным образом. Это не обязательно имеет какое-либо отношение к тому, будет ли код, написанный для использования таких типов, продолжать работать без strictfp. Иными словами, наличие более точных чисел с плавающей запятой может на самом деле привести к тому, что конечный результат вычисления будет более фиктивным. И не потому, что вычисления плохо спроектированы.   -  person tmyklebu    schedule 31.01.2016


Ответы (1)


Архитектура Intel IA64 использует фиксированный формат регистра с плавающей запятой, один бит знака, 17 бит экспоненты и 64 бита мантиссы. Когда число с плавающей запятой сохраняется из одного из этих регистров в 32- или 64-битную переменную, оно должно быть преобразовано.

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

Первоначально Java просто настаивала на том, чтобы все вычисления выполнялись так, как если бы все промежуточные результаты сохранялись. Оказалось, что это дает плохую производительность из-за сложности принудительного перевода показателя степени в правильный диапазон при каждом вычислении. Решение состояло в том, чтобы предоставить программисту выбор между полностью согласованным режимом strictfp и более расслабленным режимом, в котором показатель степени мог выйти за пределы диапазона для типа выражения без принудительного приведения значения к нулю или бесконечности.

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

Если бы тот же расчет был выполнен в режиме strictfp, у числа с плавающей запятой не было бы разрешено иметь показатель степени за пределами диапазона показателя степени с плавающей запятой. Какой бы расчет он ни производил, он привел бы значение к нулю или бесконечности. Каждое значение с плавающей запятой точно представлено в double, поэтому преобразование вообще не меняет значение, не говоря уже о потере общей величины.

person Patricia Shanahan    schedule 31.01.2016
comment
Я думаю, что двойное расширение использует 15 бит экспоненты. - person Pascal Cuoq; 01.02.2016
comment
Мне очень жаль, что я продолжаю спрашивать вас об этом до сих пор. Я искренне благодарю вас за то, что вы сообщили мне все детали спецификации. Это было действительно полезно. - person b1sub; 01.02.2016
comment
Могу ли я задать вам простой вопрос, основанный на вашем ответе? Когда вы сказали, что Non-strictfp может избежать потери памяти до нуля... в комментарии, предполагалось ли, что это означает, что операция с плавающей точкой non-strictfp может привести к в недостатке при преобразовании в плавающую/двойную память в памяти? Я имею в виду, что простое перемещение нестрогого fp в памяти с плавающей запятой в non-strictfp in-memory double не кажется проблемой. - person b1sub; 01.02.2016
comment
@Il-seobBae Единственным представлением числа double в памяти является, по сути, 64-битный двоичный код IEEE 754, и в нем нет места для более широкой экспоненты, которая может существовать в регистре. Одно и то же представление используется в памяти независимо от состояния strictfp. - person Patricia Shanahan; 01.02.2016
comment
@PatriciaShanahan Да. Я это знаю. Проблема здесь в том, что недостаточный поток, о котором вы говорите, является только продуктом операции (например, сложения или умножения). Другими словами, float a=something; double b=a; не должно подвергаться потере значимости, потому что нет возможности использовать операцию, для которой может потребоваться более широкий показатель степени. В заключение, мой вопрос заключался в том, что ваши комментарии до сих пор полностью говорят о преобразовании, которое включает операцию с двумя или более нестрогими числами с плавающей запятой, что не применимо к случаю, о котором я упоминал выше. - person b1sub; 01.02.2016
comment
@ Il-seobBae Все зависит от того, откуда исходит something. Если бы это было число с плавающей запятой в памяти, экспонента точно подошла бы, и не было бы потери значимости. Если something было вычислено в регистре, и присвоение происходит из регистра, он может иметь слишком широкий показатель степени. - person Patricia Shanahan; 01.02.2016
comment
@PatriciaShanahan Спасибо за ответ. Это мне очень помогло. - person b1sub; 02.02.2016