TOML (Tom’s Obvious, Minimal Language) is a configuration language that’s designed to be simple and easy to understand, with a focus on usability. One of the primary data types in TOML is float
, which is used to represent decimal numbers with a fractional part. These float
values in TOML are implemented as IEEE 754 binary64 values. In this blog, we’ll dive into how Toml floats work in TOML, with particular emphasis on their syntax, representation, and the rules that define valid and invalid float values.
TOML Floats
In TOML, a float
is a numerical value that can represent real numbers, including fractional values and those expressed in scientific notation (with exponents).
A float
consists of three parts:
- Integer Part: The whole number part of the float.
- Fractional Part: The part after the decimal point.
- Exponent Part: The part that shows how the number should be scaled, based on the exponent.
The IEEE 754 binary64 standard (commonly known as double-precision floating point) is used for encoding these values. This standard defines how floating-point numbers are represented and how operations on them are performed.
Format of TOML Floats
A float in TOML follows a specific structure:
- Integer Part: The whole number before the decimal point.
- Fractional Part (optional): A decimal point followed by one or more digits.
- Exponent Part (optional): A scientific notation format represented by an “E” or “e” followed by a signed integer, indicating the power of 10 to which the number is raised.
Valid Floats
# Floats with a Fractional Part
flt1 = +1.0 # Positive float
flt2 = 3.1415 # Pi approximation
flt3 = -0.01 # Negative float
# Floats with an Exponent Part (scientific notation)
flt4 = 5e+22 # 5 × 10^22
flt5 = 1e06 # 1 × 10^6 (same as 1,000,000)
flt6 = -2E-2 # -2 × 10^(-2) (same as -0.02)
# Floats with Both Fractional and Exponent Parts
flt7 = 6.626e-34 # 6.626 × 10^-34 (Planck's constant)
Invalid floats
# INVALID examples
invalid_float_1 = .7 # Missing whole number (No digit before the decimal)
invalid_float_2 = 7. # Missing fractional part (No digit after the decimal)
invalid_float_3 = 3.e+20 # Missing fractional part before 'e' (No digit after the decimal)
Rule: A decimal point must have digits on both sides. This means a float must have digits on both sides of the decimal point.
Readability with Underscores
Similar to integers, underscores may be used to enhance readability. Each underscore must be surrounded by at least one digit.
# Readable Floats Using Underscores
flt8 = 224_617.445_991_228 # Underscores improve readability
Rule: Underscores must be between numbers, not at the start or end.
Zero in Toml Float
In TOML, the values -0.0
and +0.0
are valid and represent zero, but with a sign.
-0.0
: Negative zero+0.0
: Positive zero0.0
: Zero without any sign
According to the IEEE 754 standard for floating-point numbers:
-0.0
and+0.0
are treated as the same value (0.0
), but they have different internal representations, which can be important in certain calculations.- The sign of zero may affect certain edge cases in mathematical operations, but for most practical uses, they are treated the same as
0.0
.
This is mostly used in scientific computing or cases where the sign of zero can have meaning.
Special Float Values (IEEE 754)
TOML also supports special float values, which are always written in lowercase.
Infinity (inf
)
inf
: Represents positive infinity.+inf
: Same asinf
, positive infinity (optional + sign).-inf
: Represents negative infinity.
# infinity
sf1 = inf # positive infinity
sf2 = +inf # positive infinity (same as inf)
sf3 = -inf # negative infinity
Infinity is often used in mathematical operations to represent values that exceed any finite number.
Not-a-Number (nan
)
nan
: Represents “Not a Number,” which is used to signal invalid or undefined numbers (like dividing zero by zero).+nan
: Same asnan
, but with an optional plus sign.-nan
: Same asnan
, but with a minus sign.
# not a number, 0 / 0 results in nan because there's no defined answer to that division.
sf4 = nan # actual sNaN/qNaN encoding is implementation-specific
sf5 = +nan # same as `nan`
sf6 = -nan # valid, actual encoding is implementation-specific
NaN is used when a result doesn’t make sense (like dividing zero by zero). The way NaN (Not-a-Number) is encoded depends on the implementation, so how it’s stored can vary. This means how NaN is stored in memory (internally) depends on the system or language you’re using.
There are two common types of NaN:
- sNaN (Signaling NaN): Used to signal an error in a computation (usually a floating-point exception or to trigger a trap, depending on the system).
- qNaN (Quiet NaN): Used to propagate through calculations without signaling an error (i.e., it propagates “quietly” through calculations without raising exceptions).
However, for TOML, it doesn’t matter whether it’s sNaN or qNaN; it simply stores it as nan
, and how it’s handled is up to the implementation (such as in programming languages or hardware).
Conclusion
TOML provides a simple and intuitive way to represent float values, while still adhering to the powerful and widely adopted IEEE 754 binary64 standard. By understanding the basic rules of float formatting and the significance of fractional and exponent parts, you can effectively use and manage floating-point values in TOML configuration files. The ability to represent special values like infinity and NaN makes TOML even more flexible for a wide range of applications, particularly those that require precise and high-range numerical values.