JLS 3.10.2 -- Exposition of hexadecimal f.p. literals

Alex Buckley alex.buckley at oracle.com
Mon Oct 28 23:15:29 UTC 2019


Thanks Joe. I am unable to spend more time on this issue, so I have 
filed JDK-8233092 to record it for the future.

Alex

On 10/25/2019 5:29 PM, Joe Darcy wrote:
> To provide some additional background on this thread if not the JLS 
> section in question, hexadecimal floating-point literals are a very 
> useful language feature for a narrow range of situations. Those 
> situations include having a straightforward way to set the exact bits of 
> a floating-point value using a roughly human readable format. I commonly 
> use hexadecimal floating-point literals in numerical tests and have 
> added them to the narrative specs for sentinel values such as 
> Double.MAX_VALUE.
> 
> A finite IEEE floating-point value is conceptually a tuple of three 
> values, sign, significand, and exponent, where the significand and 
> exponent have ranges that are a function of the format in question, 
> float or double, etc. Depending on how one wants to formulate the 
> values, the ranges of each of these values can be given in terms of a 
> set of contiguous integers.
> 
> In a hex floating-point literal, the significand value is written in hex 
> but the exponent value is written in *decimal*. However, the decimal 
> value is used as an exponent for base 2 and in that sense is a "binary" 
> exponent. This seemingly conflicting design works for the intended use 
> cases.
> 
> For example, the smallest nonzero double value is numerically equal to 
> 2^-1074. As a hex literal this can be written in a number of ways including
> 
>      0x1.0p-1074
> 
> in decimal, 1 * 2 ^ -1074. The way to write the value corresponding to 
> the representation of the floating-point value, using some underscores 
> to help grouping, is
> 
>      0x0.0000_0000_0000_1p-1022
> 
> Decoding, this is a subnormal value (leading digit 0 with the lowest 
> exponent value) and only the least significant bit of the significand is 
> set. The double format uses 52-bits for its significand field, 13 hex 
> digits.
> 
> Other examples would include how to write "3.0" in a way corresponding 
> to the representation:
> 
>      0x1.8p1
> 
> that is 1.8 as a hex value (namely 1.5 in decimal) multiplied by 2^1 = 2.
> 
> On 10/24/2019 5:04 PM, Alex Buckley wrote:
>> On 10/24/2019 1:38 PM, Joe Darcy wrote:
>>> To make an explicit statement about the value of a floating-point 
>>> literal, I suggest after the sentence
>>>
>>> "A floating-point literal may be expressed in decimal (base 10) or 
>>> hexadecimal (base 16). "
>>>
>>> adding something like
>>>
>>> "The exact numerical value of a decimal floating-point literals is
>>>
>>>      decimal_sequence * 10 ^ exponent
>>>
>>> The exact numerical value of a hexadecimal floating-point literal is
>>>
>>>      hex_sequence * 2 ^ exponent
>>>
>>> The conversion of the exact numerical value to a particular 
>>> floating-point value is handled as if by Float.valueOf or 
>>> Double.valueOf for literals of type float and double, respectively."
>>
>> This is a good start, but needs tightening up. Please consider this 
>> text as if you're seeing it for the first t
> 
> To be more explicit, "decimal_sequence * 10 ^ exponent " is an informal 
> short-hand for "in each of the possible decimal floating-point literal 
> forms below, collect together the leading digits as a digit sequence, 
> treat it as a normal rational numerical value and multiply it by 10 
> raised to the exponent where the exponent if implicitly 1 if not 
> syntactically present in the literal."
> 
>       Digits . [Digits] [ExponentPart] [FloatTypeSuffix]
>      . Digits [ExponentPart] [FloatTypeSuffix]
>      Digits ExponentPart [FloatTypeSuffix]
>      Digits [ExponentPart] FloatTypeSuffix
> 
> 
>> ime, bearing in mind that it's defining terms which map to productions 
>> in the grammar immediately after.
>>
>> -----
>> A floating-point literal may be expressed in decimal (base 10) or 
>> hexadecimal (base 16).
>>
>> For decimal floating-point literals, at least one digit (in either the 
>> whole number or the fraction part) and either a decimal point, an 
>> exponent, or a float type suffix are required. All other parts are 
>> optional. The exponent, if present, is indicated by the ASCII letter e 
>> or E followed by an optionally signed integer.
>>
>> The exact numerical value of a decimal floating-point literal is:
>>   decimal_sequence * 10 ^ exponent
>>
>> For hexadecimal floating-point literals, at least one digit is 
>> required (in either the whole number or the fraction part), and the 
>> exponent is mandatory, and the float type suffix is optional. The 
>> exponent is indicated by the ASCII letter p or P followed by an 
>> optionally signed integer.
>>
>> The exact numerical value of a hexadecimal floating-point literal is:
>>   hex_sequence * 2 ^ exponent
>>
>> Underscores are allowed as separators between digits that denote the 
>> whole-number part, and between digits that denote the fraction part, 
>> and between digits that denote the exponent.
>> -----
>>
>> - What is "decimal_sequence"? The answer must be in terms of the 
>> artifacts mentioned in the immediately preceding paragraph -- or 
>> modify the grammar to introduce new artifacts that can be described in 
>> the narrative.
>>
>> - Similarly for "hex_sequence".
>>
>> - A decimal f-p literal need not include the exponent part, so the 
>> definition can't just assume "exponent" is known.
>>
>> - For a hexadecimal f-p literal, the questioner mentioned that the 
>> (mandatory) exponent is "in base 2", but there is no requirement to 
>> write the exponent in binary. There's lots of potential for confusion 
>> here. What are some examples of hexadecimal f-p literals?
>>
>> In the JLS, it is often the most fundamental descriptions and 
>> operations that are the hardest to phrase. We're not there yet for f-p 
>> literal values.
> 
> There could be value in having a highly condensed floating-point primer 
> in the JLS, but it would be fine to continue to omit such information as 
> well. For example, the statement in the JLS
> 
>      "The smallest positive finite non-zero literal of type double is 
> 4.9e-324."
> 
> is considerably more subtle than it appears at first. All finite binary 
> floating-point values are exactly representable as double values since 
> 10 = 2 * 5. There is a range of the number line which converts to 
> Double.MIN_VALUE and many decimal strings in that range which get 
> converted to Double.MIN_VALUE. The string "4.9e-324" is not the 
> numerically smallest such string nor is it the numerically largest. The 
> exact string has several hundred decimal digits. This string used is the 
> shortest such string, which is regarded as the canonical one.
> 
> Such subtleties could be alluded to in the JLS; if there is interest, I 
> could work on a few paragraphs describing the situation.
> 
> Cheers,
> 
> -Joe
> 


More information about the jls-jvms-spec-comments mailing list