Floating-Point, Fixed-Point & Decimal Types
Declare floating-point types by required precision (digits), use Float and Long_Float, understand why 0.1 + 0.2 /= 0.3, and use Ada's ordinary fixed-point (delta) and decimal fixed-point (delta digits) types for exact, evenly spaced values such as sensor readings and money.
Ada has three kinds of real numbers. Floating-point types give relative precision over a huge range and map to the hardware FPU. Ordinary fixed-point types give absolute precision — values are evenly spaced multiples of a small step — which suits embedded sensor and control values on processors without floating-point hardware. Decimal fixed-point types give exact decimal arithmetic for financial calculations. You choose by stating the precision you need, not by picking a machine type.
Floating-Point Types
'type Sensor_Value is digits 6 range -1_000.0 .. 1_000.0;' requests at least 6 significant decimal digits; the compiler picks a hardware type that satisfies it. Predefined Float (6 digits on GNAT, IEEE single) and Long_Float (15 digits, IEEE double) are also available. Real literals must contain a decimal point (2.0, not 2), and mixing Integer and Float requires conversion: Float (N).
Floating-point values are binary approximations: 0.1 and 0.2 are not exactly representable, so 0.1 + 0.2 is very close to but not equal to 0.3. Never compare floating values with = for computed results; compare with a tolerance. Float'Image prints in scientific notation (3.00000E-01); Ada.Float_Text_IO gives control over Fore, Aft and Exp fields for fixed-format output.
• type T is digits N [range L .. H]; — precision-based declaration. • Float (≈6 digits), Long_Float (≈15 digits) on GNAT. • Real literals need a decimal point; convert integers explicitly. • Compare computed floats with a tolerance, never =. • Use Ada.Float_Text_IO for formatted output.
Ordinary Fixed-Point Types
'type Volts is delta 0.125 range 0.0 .. 10.0;' declares values that are exact multiples of a step (T'Small) no larger than 0.125; GNAT chooses a power of two, here exactly 0.125. Addition and subtraction are exact, and values are stored as scaled integers, making fixed point efficient on microcontrollers without an FPU and ideal for signal processing, where absolute resolution matters more than range. Multiplication of two fixed-point values produces a result that must be converted to a target fixed type.
• type T is delta D range L .. H; — absolute precision, evenly spaced values. • T'Small is the actual step (a power of 2 ≤ D unless specified with for T'Small use). • Stored as scaled integers: efficient without FPU hardware. • Good for sensors, DSP, control loops.
Decimal Fixed-Point Types
'type Money is delta 0.01 digits 12;' represents values with exactly two decimal places and up to 12 digits in total. The step is exactly 0.01 (a power of ten), so adding 19.99 three times gives exactly 59.97 — no binary rounding drift like with Float. Decimal types are the correct choice for currency, following the tradition of COBOL; the Ada.Text_IO.Editing package can format them as '$1,234.56'.
• type T is delta 0.01 digits N; — exact decimal arithmetic. • No binary rounding surprises: use for money and decimal quantities. • Ada.Text_IO.Editing provides picture-based formatting.
Code Examples
Float'Image prints 0.1 + 0.2 as 3.00000E-01 (rounded to 6 digits), yet X = 0.3 is FALSE because the underlying binary values differ; a tolerance comparison is TRUE. Output: Float'Digits = 6 Long_Float'Digits = 15 V = 1.23456E+02 0.1 + 0.2 = 3.00000E-01 X = 0.3 ? FALSE abs (X - 0.3) < 1.0E-6 ? TRUE 7.0 / 2.0 = 3.50000E+00 Float (7) / 2.0 = 3.50000E+00
Volts has a step of exactly 0.125, so 3.25 + 0.5 = 3.75 (printed as 3.8 because 'Image shows just enough digits for the delta). Money sums exactly to 59.97; multiplying by the qualified decimal 0.07 gives 4.19 (truncated to the cent). Output: V = 3.8 Volts'Small = 1.25000E-01 3 x 19.99 = 59.97 Total * 0.07 (tax) = 4.19 Half: Float:= 1 / 2;
Half : Float := 1.0 / 2.0;
1 / 2 is integer division (and an Integer, not a Float); use real literals.
if Total = 0.3 then ...
if abs (Total - 0.3) < 1.0E-6 then ...
Computed floating values are rarely exactly equal; compare within a tolerance.
Balance: Float:= 0.0; -- money type Money is delta 0.01 digits 14; Balance: Money:= 0.0;
Binary floating point cannot represent most decimal cents exactly; use a decimal fixed-point type.
Which declaration gives exact cents for currency? A. type M is digits 6; B. type M is delta 0.01 digits 12; C. type M is new Float; D. type M is mod 100;
B. A decimal fixed-point type with delta 0.01.
What does 'digits 6' specify for a floating-point type? A. Six decimal places B. At least six significant decimal digits of precision C. Six bytes D. Values up to 999999
B. At least six significant decimal digits (relative precision).
Why is 0.1 + 0.2 = 0.3 false for Float? A. Ada bug B. Binary floating point cannot represent these decimals exactly C. Float has only 1 digit D. = is not defined for Float
B. The values are binary approximations whose sum differs slightly from the approximation of 0.3.
When is an ordinary fixed-point type a good choice? A. Huge dynamic range B. Evenly spaced values with absolute resolution, e.g. sensor readings on a CPU without FPU C. Text processing D. Currency with cents
B. Fixed point provides absolute resolution and efficient integer-based arithmetic.
What does the fixed-point example print?
Real output: V = 3.8 Volts'Small = 1.25000E-01 3 x 19.99 = 59.97 Total * 0.07 (tax) = 4.19
with Ada.Text_IO; use Ada.Text_IO;
procedure L7_Float is
type Sensor_Value is digits 6 range -1_000.0 .. 1_000.0; -- at least 6 significant digits
V : constant Sensor_Value := 123.456;
X : constant Float := 0.1 + 0.2;
begin
Put_Line ("Float'Digits =" & Integer'Image (Float'Digits));
Put_Line ("Long_Float'Digits =" & Integer'Image (Long_Float'Digits));
Put_Line ("V =" & Sensor_Value'Image (V));
Put_Line ("0.1 + 0.2 =" & Float'Image (X));
Put_Line ("X = 0.3 ? " & Boolean'Image (X = 0.3));
Put_Line ("abs (X - 0.3) < 1.0E-6 ? " & Boolean'Image (abs (X - 0.3) < 1.0E-6));
Put_Line ("7.0 / 2.0 =" & Float'Image (7.0 / 2.0));
Put_Line ("Float (7) / 2.0 =" & Float'Image (Float (7) / 2.0));
end L7_Float;with Ada.Text_IO; use Ada.Text_IO;
procedure L7_Fixed is
type Volts is delta 0.125 range 0.0 .. 10.0; -- ordinary fixed point
type Money is delta 0.01 digits 12; -- decimal fixed point
V : Volts := 3.25;
Price : constant Money := 19.99;
Total : Money := 0.0;
begin
V := V + 0.5;
Put_Line ("V =" & Volts'Image (V));
Put_Line ("Volts'Small =" & Float'Image (Float (Volts'Small)));
for I in 1 .. 3 loop
Total := Total + Price; -- exact: no rounding drift
end loop;
Put_Line ("3 x 19.99 =" & Money'Image (Total));
Put_Line ("Total * 0.07 (tax) =" & Money'Image (Total * Money'(0.07)));
end L7_Fixed;