Floating-Point Value

Floating-point values represent numbers that can include fractional parts and an optional exponent.

float               ::= PLUS_MINUS? ( float_special | float_number )

float_special       ::= "inf" | "nan"   /* case insensitive */

float_number        ::= ( integer_dec float_exponent ) |
                        ( integer_dec PERIOD integer_dec? float_exponent? ) |
                        ( integer_dec? PERIOD integer_dec float_exponent? )

float_exponent      ::= LETTER_E PLUS_MINUS? DIGIT+   /* maximum of 6 digits */

In the example below, you can see various valid floating-point values:

[main]
value a: .0
value b: NaN
value c: INF
value d: 2937.28301
value e: 12e+10
value f: -12.9
value g: -8'283.9e-5

Important

This specification does not require a specific floating-point storage format for programming language or parser implementations. The reference to ISO/IEC 60559:2020 (or IEEE 754) is only meant to clarify the definition of floating-point numbers. What matters most is that parsers follow the floating-point syntax and rules described in the grammar.

Since different programming languages and platforms may use slightly varied internal representations for floating-point values, small differences between implementations are expected. Handling these differences is the responsibility of the application using the configuration.

Remember that ELCL is a configuration format, not a storage format. As such, minor rounding errors in floating-point values should not cause issues in your application.

Rules

  1. Expected Precision: A parser should support floating-point numbers of the size described as binary64 in the ISO/IEC 60559:2020 or IEEE 754 standard. This format uses 64 bits in total, with 11 bits for the exponent and 52 bits for the mantissa.

    ┌────────────────────────────────────────────────────────┐
    │ 64 bits                                                │
    ├───┬─────────────────┬──────────────────────────────────┤
    │ 1 │ 11 bits         │ 52 bits                          │
    ├───┼─────────────────┼──────────────────────────────────┤
    │ S │ Exponent        │ Mantissa                         │
    └───┴─────────────────┴──────────────────────────────────┘
    
  2. Alternative Precision: A parser can support a different storage format, such as fixed-point, provided it supports a minimum precision of 17 decimal places across both the integral and fractional parts.

    ┌────────────────────────────────────────────────────────┐
    │ 128 bits                                               │
    ├───┬────────────────────────┬───────────────────────────┤
    │ 1 │ 63 bits                │ 64 bits                   │
    ├───┼────────────────────────┼───────────────────────────┤
    │ S │ Integral               │ Fraction                  │
    └───┴────────────────────────┴───────────────────────────┘
    

    Note

    A parser using an alternative internal storage format must still correctly parse and interpret the full floating-point syntax, including exponents and the special literals nan and inf.

  3. Minimum Structure: A floating-point value must include either an integral part, a fractional part, or both.

    [main]
    value a: 1293.
    value b: .029
    value c: 1192.0067
    
  4. Decimal Point: The integral part is separated from the fractional part by a decimal point (.).

    [main]
    value a: 1293.
    value b: .029
    value c: 11.0067
    
  5. Exponent: A floating-point value with a decimal point can have an exponent. A floating-point value without a decimal point must include an exponent to be considered a valid floating-point number..

    [main]
    value a: 1293.e6
    value b: .029e-4
    value c: 1192e5
    
  6. Special Values: The special literals inf (infinity) and nan (not-a-number) are valid floating-point numbers. These literals are case-insensitive.

    [main]
    value a: nan
    value b: inf
    value c: -nan   # Though logically unnecessary, this syntax is supported for completeness.
    value d: -inf
    
  7. Integral Part: The integral part of a floating-point number consists of a sequence of digits 09.

    [main]
    value: 1207256.
    
  8. No Zero Padding: The integral part of a floating-point number must not be padded with leading zeros.

    [main]
    value: 005.293    # ERROR! Leading zeros are not allowed.
    
  9. Fractional Part: The fractional part of a floating-point number consists of a sequence of digits 09. The fractional part may have trailing zeroes.

    [main]
    value: .00201982
    
  10. Digit Limit: The total number of digits in both the integral and fractional parts must not exceed 20 digits. Trailing zeroes in the fractional part add to the total digit count.

    [main]
    value a: 10000000000.00000000001     # ERROR! Exceeds 20 digits.
    value b: 1.000000000000000000000     # ERROR! Exceeds 20 digits.
    
  11. Exponent Part: An exponent must start with the letter e (case-insensitive), followed by an optional plus (+) or minus (-) sign, and then one to six digits.

    [main]
    value a: 103216.0e-12
    value b: 0.0235e+9
    
  12. Exponent Padding: The exponent can be padded with leading zeros.

    [main]
    value: 103216.0e-000012
    
  13. Zero: All possible variants of zero, 0.0, .0 and 0. with plus or minus sign are valid floating-point numbers.

    [main]
    value a: 0.0
    value b: 0.
    value c: .0
    value d: -0.0
    value e: -.0
    value f: +0.
    
  14. Digit Separators: Apostrophes (') can be used as optional digit separators in the integral and fractional parts, but not in the exponent, to improve readability.

    [main]
    value: 100'000.000'001
    
  15. No Separator at Start or End: A number must not begin or end with a digit separator.

    [main]
    value a: '100'000.    # ERROR! Must not start with a separator.
    value b: 100'000'.    # ERROR! Must not end with a separator.
    
  16. No Consecutive Separators: Consecutive digit separators are not allowed.

    [main]
    value: 100''000    # ERROR! Consecutive separators are not allowed.
    
  17. No Hexadecimal and Binary Forms: Hexadecimal or octal formats of floating-point numbers are not allowed

    [main]
    value: 0x1.921fb54442d18p+1  # ERROR! Hexadecimal or binary formats are not allowed.
    
  18. Conversion Method: Floating-point conversions should follow the guidelines outlined in the ISO/IEC 60559:2020 standard (section 5.12) or IEEE 754.

    Important

    ELCL is a configuration format, not a storage format. Therefore, small rounding errors, especially after 15 significant digits, are perfectly acceptable.

  19. Behavior When Limits Are Exceeded: If a floating-point value exceeds the internal storage range (crossing the minimum or maximum value), the stored value should be rounded down to zero or rounded up to represent infinity, as appropriate.

    Important

    ELCL is a configuration format, not a storage format. Therefore, small rounding errors, particularly after 15 significant digits, are expected and acceptable.

Features

Feature

Coverage

float

Floating-point numbers are a standard feature.

Errors

Error Code

Causes

Syntax

Raised if value separators are placed incorrectly.
Raised if there are multiple decimal points.
Raised if the integral part is padded with zeros.
Raised if the value exceeds the allowed number of digits.