Reputation: 31173
Declaring ranges in Ada is always done inclusively.
If i want a type that has all the integers from 0
to 42
(or as a mathmatical interval: [0, 42]
) i declare it as follows:
type zero_to_42 is range 0 .. 42;
If i want to exclude the zero (the range (0, 42]
), this is not an issue for discrete types:
type not_zero_to_42 is range (zero_to_42'First + 1) .. zero_to_42'Last;
but i still have to do this manually, there is no zero_to_answer'NextAfterFirst
For floating point types i have no idea how to do this properly. It's simple for excluding the zero, but excluding anything else seems implementation defined to me.
type works is digits 6 range 0.0 .. 42.0
type also_works is new works range (0.0 + works'small) .. 42.0
type broken is new works range 0.0 .. (42.0 - works'small)
since float values near 42.0
have less precision than floating point values near 0.0
, 42.0 - works'small
is rounded to 42.0
i could of course find a value by hand that works (e.g. 41.9999
) but that seems ugly to me and might not work anymore when i change the number of digits that works
has.
Upvotes: 2
Views: 987
Reputation: 31689
The 'Succ
and 'Pred
attributes can be used on floating-point values to return the next or previous machine numbers. If T
is a floating-point type,
T'Succ(X)
is the smallest floating-point "machine number" > X
, and
T'Pred(X)
is the largest floating-point machine number < X
. Thus:
type Works is digits 6 range 0.0 .. 42.0;
subtype Exclusive is Works range 0.0 .. Works'Pred(42.0);
Or (since the range on the type
declaration might not be relevant):
type Digits_6 is digits 6;
subtype Exclusive is Digits_6 range 0.0 .. Digits_6'Pred(42.0);
Or
type Exclusive is digits 6 range 0.0 .. Float'Pred(42.0);
assuming you know Float
is a 32-bit IEEE float and Exclusive
will also be one.
Upvotes: 2
Reputation: 25491
You might be able to use the Ada 2012 dynamic predicate:
type Exclusive is new Float range 0.0 .. 42.0
with Dynamic_Predicate => Exclusive > 0.0 and then Exclusive < 42.0;
but GNAT seems to have troubles with this: GCC 4.8.1 is OK, GNAT GPL 2013 won’t even accept values of 1.0 or 41.0, and GCC 4.9.0-20140119 threw a bug box!
Upvotes: 1
Reputation: 31173
What is can be used here is 'Adjacent(near_value, towards_value)
type works is digits 6 range 0.0 .. 42.0
type also_works is new works range (0.0 + works'small) .. 42.0
type still_works is new works range 0.0 .. works'Adjacent(42.0, 0.0)
this looks for whichever value can be represented by the machine that is closest to near_value
in the direction of towards_value
when printing out still_works'last
and works'last
very likely the result will look/be the same, but comparing the two won't work
declare
type works is digits 6 range 0.0 .. 42.0
subtype still_works is works range 0.0 .. works'Adjacent(42.0, 0.0)
begin
Text_IO.Put_Line(works'Image(works'Last));
Text_IO.Put_Line(still_works'Image(still_works'Last));
Text_IO.Put_Line(Boolean'Image(works'Last = still_works'Last));
end;
yields when compiled with gnat:
4.20000E+01
4.20000E+01
FALSE
Upvotes: 2