mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-19 02:22:10 -05:00
551 lines
22 KiB
Plaintext
551 lines
22 KiB
Plaintext
[/
|
|
Boost.Optional
|
|
|
|
Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal
|
|
|
|
Distributed under the Boost Software License, Version 1.0.
|
|
(See accompanying file LICENSE_1_0.txt or copy at
|
|
http://www.boost.org/LICENSE_1_0.txt)
|
|
]
|
|
|
|
|
|
[section Definitions]
|
|
|
|
[section Introduction]
|
|
|
|
This section provides definitions of terms used in the Numeric Conversion library.
|
|
|
|
[blurb [*Notation]
|
|
[_underlined text] denotes terms defined in the C++ standard.
|
|
|
|
[*bold face] denotes terms defined here but not in the standard.
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section Types and Values]
|
|
|
|
As defined by the [_C++ Object Model] (§1.7) the [_storage] or memory on which a
|
|
C++ program runs is a contiguous sequence of [_bytes] where each byte is a
|
|
contiguous sequence of bits.
|
|
|
|
An [_object] is a region of storage (§1.8) and has a type (§3.9).
|
|
|
|
A [_type] is a discrete set of values.
|
|
|
|
An object of type `T` has an [_object representation] which is the sequence of
|
|
bytes stored in the object (§3.9/4)
|
|
|
|
An object of type `T` has a [_value representation] which is the set of
|
|
bits that determine the ['value] of an object of that type (§3.9/4).
|
|
For [_POD] types (§3.9/10), this bitset is given by the object representation,
|
|
but not all the bits in the storage need to participate in the value
|
|
representation (except for character types): for example, some bits might
|
|
be used for padding or there may be trap-bits.
|
|
|
|
__SPACE__
|
|
|
|
The [*typed value] that is held by an object is the value which is determined
|
|
by its value representation.
|
|
|
|
An [*abstract value] (untyped) is the conceptual information that is
|
|
represented in a type (i.e. the number π).
|
|
|
|
The [*intrinsic value] of an object is the binary value of the sequence of
|
|
unsigned characters which form its object representation.
|
|
|
|
__SPACE__
|
|
|
|
['Abstract] values can be [*represented] in a given type.
|
|
|
|
To [*represent] an abstract value `V` in a type `T` is to obtain a typed value
|
|
`v` which corresponds to the abstract value `V`.
|
|
|
|
The operation is denoted using the `rep()` operator, as in: `v=rep(V)`.
|
|
`v` is the [*representation] of `V` in the type `T`.
|
|
|
|
For example, the abstract value π can be represented in the type
|
|
`double` as the `double value M_PI` and in the type `int` as the
|
|
`int value 3`
|
|
|
|
__SPACE__
|
|
|
|
Conversely, ['typed values] can be [*abstracted].
|
|
|
|
To [*abstract] a typed value `v` of type `T` is to obtain the abstract value `V`
|
|
whose representation in `T` is `v`.
|
|
|
|
The operation is denoted using the `abt()` operator, as in: `V=abt(v)`.
|
|
|
|
`V` is the [*abstraction] of `v` of type `T`.
|
|
|
|
Abstraction is just an abstract operation (you can't do it); but it is
|
|
defined nevertheless because it will be used to give the definitions in the
|
|
rest of this document.
|
|
|
|
[endsect]
|
|
|
|
[section C++ Arithmetic Types]
|
|
|
|
The C++ language defines [_fundamental types] (§3.9.1). The following subsets of
|
|
the fundamental types are intended to represent ['numbers]:
|
|
|
|
[variablelist
|
|
[[[_signed integer types] (§3.9.1/2):][
|
|
`{signed char, signed short int, signed int, signed long int}`
|
|
Can be used to represent general integer numbers (both negative and positive).
|
|
]]
|
|
[[[_unsigned integer types] (§3.9.1/3):][
|
|
`{unsigned char, unsigned short int, unsigned int, unsigned long int}`
|
|
Can be used to represent positive integer numbers with modulo-arithmetic.
|
|
]]
|
|
[[[_floating-point types] (§3.9.1/8):][
|
|
`{float,double,long double}`
|
|
Can be used to represent real numbers.
|
|
]]
|
|
[[[_integral or integer types] (§3.9.1/7):][
|
|
`{{signed integers},{unsigned integers}, bool, char and wchar_t}`
|
|
]]
|
|
[[[_arithmetic types] (§3.9.1/8):][
|
|
`{{integer types},{floating types}}`
|
|
]]
|
|
]
|
|
|
|
The integer types are required to have a ['binary] value representation.
|
|
|
|
Additionally, the signed/unsigned integer types of the same base type
|
|
(`short`, `int` or `long`) are required to have the same value representation,
|
|
that is:
|
|
|
|
int i = -3 ; // suppose value representation is: 10011 (sign bit + 4 magnitude bits)
|
|
unsigned int u = i ; // u is required to have the same 10011 as its value representation.
|
|
|
|
In other words, the integer types signed/unsigned X use the same value
|
|
representation but a different ['interpretation] of it; that is, their
|
|
['typed values] might differ.
|
|
|
|
Another consequence of this is that the range for signed X is always a smaller
|
|
subset of the range of unsigned X, as required by §3.9.1/3.
|
|
|
|
[note
|
|
Always remember that unsigned types, unlike signed types, have modulo-arithmetic;
|
|
that is, they do not overflow.
|
|
This means that:
|
|
|
|
[*-] Always be extra careful when mixing signed/unsigned types
|
|
|
|
[*-] Use unsigned types only when you need modulo arithmetic or very very large
|
|
numbers. Don't use unsigned types just because you intend to deal with
|
|
positive values only (you can do this with signed types as well).
|
|
]
|
|
|
|
|
|
[endsect]
|
|
|
|
[section Numeric Types]
|
|
|
|
This section introduces the following definitions intended to integrate
|
|
arithmetic types with user-defined types which behave like numbers.
|
|
Some definitions are purposely broad in order to include a vast variety of
|
|
user-defined number types.
|
|
|
|
Within this library, the term ['number] refers to an abstract numeric value.
|
|
|
|
A type is [*numeric] if:
|
|
|
|
* It is an arithmetic type, or,
|
|
* It is a user-defined type which
|
|
* Represents numeric abstract values (i.e. numbers).
|
|
* Can be converted (either implicitly or explicitly) to/from at least one arithmetic type.
|
|
* Has [link boost_numericconversion.definitions.range_and_precision range] (possibly unbounded)
|
|
and [link boost_numericconversion.definitions.range_and_precision precision] (possibly dynamic or
|
|
unlimited).
|
|
* Provides an specialization of `std::numeric_limits`.
|
|
|
|
A numeric type is [*signed] if the abstract values it represent include negative numbers.
|
|
|
|
A numeric type is [*unsigned] if the abstract values it represent exclude negative numbers.
|
|
|
|
A numeric type is [*modulo] if it has modulo-arithmetic (does not overflow).
|
|
|
|
A numeric type is [*integer] if the abstract values it represent are whole numbers.
|
|
|
|
A numeric type is [*floating] if the abstract values it represent are real numbers.
|
|
|
|
An [*arithmetic value] is the typed value of an arithmetic type
|
|
|
|
A [*numeric value] is the typed value of a numeric type
|
|
|
|
These definitions simply generalize the standard notions of arithmetic types and
|
|
values by introducing a superset called [_numeric]. All arithmetic types and values are
|
|
numeric types and values, but not vice versa, since user-defined numeric types are not
|
|
arithmetic types.
|
|
|
|
The following examples clarify the differences between arithmetic and numeric
|
|
types (and values):
|
|
|
|
|
|
// A numeric type which is not an arithmetic type (is user-defined)
|
|
// and which is intended to represent integer numbers (i.e., an 'integer' numeric type)
|
|
class MyInt
|
|
{
|
|
MyInt ( long long v ) ;
|
|
long long to_builtin();
|
|
} ;
|
|
namespace std {
|
|
template<> numeric_limits<MyInt> { ... } ;
|
|
}
|
|
|
|
// A 'floating' numeric type (double) which is also an arithmetic type (built-in),
|
|
// with a float numeric value.
|
|
double pi = M_PI ;
|
|
|
|
// A 'floating' numeric type with a whole numeric value.
|
|
// NOTE: numeric values are typed valued, hence, they are, for instance,
|
|
// integer or floating, despite the value itself being whole or including
|
|
// a fractional part.
|
|
double two = 2.0 ;
|
|
|
|
// An integer numeric type with an integer numeric value.
|
|
MyInt i(1234);
|
|
|
|
|
|
[endsect]
|
|
|
|
[section Range and Precision]
|
|
|
|
Given a number set `N`, some of its elements are representable in a numeric type `T`.
|
|
|
|
The set of representable values of type `T`, or numeric set of `T`, is a set of numeric
|
|
values whose elements are the representation of some subset of `N`.
|
|
|
|
For example, the interval of `int` values `[INT_MIN,INT_MAX]` is the set of representable
|
|
values of type `int`, i.e. the `int` numeric set, and corresponds to the representation
|
|
of the elements of the interval of abstract values `[abt(INT_MIN),abt(INT_MAX)]` from
|
|
the integer numbers.
|
|
|
|
Similarly, the interval of `double` values `[-DBL_MAX,DBL_MAX]` is the `double`
|
|
numeric set, which corresponds to the subset of the real numbers from `abt(-DBL_MAX)` to
|
|
`abt(DBL_MAX)`.
|
|
|
|
__SPACE__
|
|
|
|
Let [*`next(x)`] denote the lowest numeric value greater than x.
|
|
|
|
Let [*`prev(x)`] denote the highest numeric value lower then x.
|
|
|
|
Let [*`v=prev(next(V))`] and [*`v=next(prev(V))`] be identities that relate a numeric
|
|
typed value `v` with a number `V`.
|
|
|
|
An ordered pair of numeric values `x`,`y` s.t. `x<y` are [*consecutive] iff `next(x)==y`.
|
|
|
|
The abstract distance between consecutive numeric values is usually referred to as a
|
|
[_Unit in the Last Place], or [*ulp] for short. A ulp is a quantity whose abstract
|
|
magnitude is relative to the numeric values it corresponds to: If the numeric set
|
|
is not evenly distributed, that is, if the abstract distance between consecutive
|
|
numeric values varies along the set -as is the case with the floating-point types-,
|
|
the magnitude of 1ulp after the numeric value `x` might be (usually is) different
|
|
from the magnitude of a 1ulp after the numeric value y for `x!=y`.
|
|
|
|
Since numbers are inherently ordered, a [*numeric set] of type `T` is an ordered sequence
|
|
of numeric values (of type `T`) of the form:
|
|
|
|
REP(T)={l,next(l),next(next(l)),...,prev(prev(h)),prev(h),h}
|
|
|
|
where `l` and `h` are respectively the lowest and highest values of type `T`, called
|
|
the boundary values of type `T`.
|
|
|
|
__SPACE__
|
|
|
|
A numeric set is discrete. It has a [*size] which is the number of numeric values in the set,
|
|
a [*width] which is the abstract difference between the highest and lowest boundary values:
|
|
`[abt(h)-abt(l)]`, and a [*density] which is the relation between its size and width:
|
|
`density=size/width`.
|
|
|
|
The integer types have density 1, which means that there are no unrepresentable integer
|
|
numbers between `abt(l)` and `abt(h)` (i.e. there are no gaps). On the other hand,
|
|
floating types have density much smaller than 1, which means that there are real numbers
|
|
unrepresented between consecutive floating values (i.e. there are gaps).
|
|
|
|
__SPACE__
|
|
|
|
The interval of [_abstract values] `[abt(l),abt(h)]` is the range of the type `T`,
|
|
denoted `R(T)`.
|
|
|
|
A range is a set of abstract values and not a set of numeric values. In other
|
|
documents, such as the C++ standard, the word `range` is ['sometimes] used as synonym
|
|
for `numeric set`, that is, as the ordered sequence of numeric values from `l` to `h`.
|
|
In this document, however, a range is an abstract interval which subtends the
|
|
numeric set.
|
|
|
|
For example, the sequence `[-DBL_MAX,DBL_MAX]` is the numeric set of the type
|
|
`double`, and the real interval `[abt(-DBL_MAX),abt(DBL_MAX)]` is its range.
|
|
|
|
Notice, for instance, that the range of a floating-point type is ['continuous]
|
|
unlike its numeric set.
|
|
|
|
This definition was chosen because:
|
|
|
|
* [*(a)] The discrete set of numeric values is already given by the numeric set.
|
|
* [*(b)] Abstract intervals are easier to compare and overlap since only boundary
|
|
values need to be considered.
|
|
|
|
This definition allows for a concise definition of `subranged` as given in the last section.
|
|
|
|
The width of a numeric set, as defined, is exactly equivalent to the width of a range.
|
|
|
|
__SPACE__
|
|
|
|
The [*precision] of a type is given by the width or density of the numeric set.
|
|
|
|
For integer types, which have density 1, the precision is conceptually equivalent
|
|
to the range and is determined by the number of bits used in the value representation:
|
|
The higher the number of bits the bigger the size of the numeric set, the wider the
|
|
range, and the higher the precision.
|
|
|
|
For floating types, which have density <<1, the precision is given not by the width
|
|
of the range but by the density. In a typical implementation, the range is determined
|
|
by the number of bits used in the exponent, and the precision by the number of bits
|
|
used in the mantissa (giving the maximum number of significant digits that can be
|
|
exactly represented). The higher the number of exponent bits the wider the range,
|
|
while the higher the number of mantissa bits, the higher the precision.
|
|
|
|
[endsect]
|
|
|
|
[section Exact, Correctly Rounded and Out-Of-Range Representations]
|
|
|
|
Given an abstract value `V` and a type `T` with its corresponding range `[abt(l),abt(h)]`:
|
|
|
|
If `V < abt(l)` or `V > abt(h)`, `V` is [*not representable] (cannot be represented) in
|
|
the type `T`, or, equivalently, it's representation in the type `T` is [*out of range],
|
|
or [*overflows].
|
|
|
|
* If `V < abt(l)`, the [*overflow is negative].
|
|
* If `V > abt(h)`, the [*overflow is positive].
|
|
|
|
If `V >= abt(l)` and `V <= abt(h)`, `V` is [*representable] (can be represented) in the
|
|
type `T`, or, equivalently, its representation in the type `T` is [*in range], or
|
|
[*does not overflow].
|
|
|
|
Notice that a numeric type, such as a C++ unsigned type, can define that any `V` does
|
|
not overflow by always representing not `V` itself but the abstract value
|
|
`U = [ V % (abt(h)+1) ]`, which is always in range.
|
|
|
|
Given an abstract value `V` represented in the type `T` as `v`, the [*roundoff] error
|
|
of the representation is the abstract difference: `(abt(v)-V)`.
|
|
|
|
Notice that a representation is an ['operation], hence, the roundoff error corresponds
|
|
to the representation operation and not to the numeric value itself
|
|
(i.e. numeric values do not have any error themselves)
|
|
|
|
* If the roundoff is 0, the representation is [*exact], and `V` is exactly representable
|
|
in the type `T`.
|
|
* If the roundoff is not 0, the representation is [*inexact], and `V` is inexactly
|
|
representable in the type `T`.
|
|
|
|
If a representation `v` in a type `T` -either exact or inexact-, is any of the adjacents
|
|
of `V` in that type, that is, if `v==prev` or `v==next`, the representation is
|
|
faithfully rounded. If the choice between `prev` and `next` matches a given
|
|
[*rounding direction], it is [*correctly rounded].
|
|
|
|
All exact representations are correctly rounded, but not all inexact representations are.
|
|
In particular, C++ requires numeric conversions (described below) and the result of
|
|
arithmetic operations (not covered by this document) to be correctly rounded, but
|
|
batch operations propagate roundoff, thus final results are usually incorrectly
|
|
rounded, that is, the numeric value `r` which is the computed result is neither of
|
|
the adjacents of the abstract value `R` which is the theoretical result.
|
|
|
|
Because a correctly rounded representation is always one of adjacents of the abstract
|
|
value being represented, the roundoff is guaranteed to be at most 1ulp.
|
|
|
|
The following examples summarize the given definitions. Consider:
|
|
|
|
* A numeric type `Int` representing integer numbers with a
|
|
['numeric set]: `{-2,-1,0,1,2}` and
|
|
['range]: `[-2,2]`
|
|
* A numeric type `Cardinal` representing integer numbers with a
|
|
['numeric set]: `{0,1,2,3,4,5,6,7,8,9}` and
|
|
['range]: `[0,9]` (no modulo-arithmetic here)
|
|
* A numeric type `Real` representing real numbers with a
|
|
['numeric set]: `{-2.0,-1.5,-1.0,-0.5,-0.0,+0.0,+0.5,+1.0,+1.5,+2.0}` and
|
|
['range]: `[-2.0,+2.0]`
|
|
* A numeric type `Whole` representing real numbers with a
|
|
['numeric set]: `{-2.0,-1.0,0.0,+1.0,+2.0}` and
|
|
['range]: `[-2.0,+2.0]`
|
|
|
|
First, notice that the types `Real` and `Whole` both represent real numbers,
|
|
have the same range, but different precision.
|
|
|
|
* The integer number `1` (an abstract value) can be exactly represented
|
|
in any of these types.
|
|
* The integer number `-1` can be exactly represented in `Int`, `Real` and `Whole`,
|
|
but cannot be represented in `Cardinal`, yielding negative overflow.
|
|
* The real number `1.5` can be exactly represented in `Real`, and inexactly
|
|
represented in the other types.
|
|
* If `1.5` is represented as either `1` or `2` in any of the types (except `Real`),
|
|
the representation is correctly rounded.
|
|
* If `0.5` is represented as `+1.5` in the type `Real`, it is incorrectly rounded.
|
|
* `(-2.0,-1.5)` are the `Real` adjacents of any real number in the interval
|
|
`[-2.0,-1.5]`, yet there are no `Real` adjacents for `x < -2.0`, nor for `x > +2.0`.
|
|
|
|
[endsect]
|
|
|
|
[section Standard (numeric) Conversions]
|
|
|
|
The C++ language defines [_Standard Conversions] (§4) some of which are conversions
|
|
between arithmetic types.
|
|
|
|
These are [_Integral promotions] (§4.5), [_Integral conversions] (§4.7),
|
|
[_Floating point promotions] (§4.6), [_Floating point conversions] (§4.8) and
|
|
[_Floating-integral conversions] (§4.9).
|
|
|
|
In the sequel, integral and floating point promotions are called [*arithmetic promotions],
|
|
and these plus integral, floating-point and floating-integral conversions are called
|
|
[*arithmetic conversions] (i.e, promotions are conversions).
|
|
|
|
Promotions, both Integral and Floating point, are ['value-preserving], which means that
|
|
the typed value is not changed with the conversion.
|
|
|
|
In the sequel, consider a source typed value `s` of type `S`, the source abstract
|
|
value `N=abt(s)`, a destination type `T`; and whenever possible, a result typed value
|
|
`t` of type `T`.
|
|
|
|
|
|
Integer to integer conversions are always defined:
|
|
|
|
* If `T` is unsigned, the abstract value which is effectively represented is not
|
|
`N` but `M=[ N % ( abt(h) + 1 ) ]`, where `h` is the highest unsigned typed
|
|
value of type `T`.
|
|
* If `T` is signed and `N` is not directly representable, the result `t` is
|
|
[_implementation-defined], which means that the C++ implementation is required to
|
|
produce a value `t` even if it is totally unrelated to `s`.
|
|
|
|
|
|
Floating to Floating conversions are defined only if `N` is representable;
|
|
if it is not, the conversion has [_undefined behavior].
|
|
|
|
* If `N` is exactly representable, `t` is required to be the exact representation.
|
|
* If `N` is inexactly representable, `t` is required to be one of the two
|
|
adjacents, with an implementation-defined choice of rounding direction;
|
|
that is, the conversion is required to be correctly rounded.
|
|
|
|
|
|
Floating to Integer conversions represent not `N` but `M=trunc(N)`, were
|
|
`trunc()` is to truncate: i.e. to remove the fractional part, if any.
|
|
|
|
* If `M` is not representable in `T`, the conversion has [_undefined behavior]
|
|
(unless `T` is `bool`, see §4.12).
|
|
|
|
|
|
Integer to Floating conversions are always defined.
|
|
|
|
* If `N` is exactly representable, `t` is required to be the exact representation.
|
|
* If `N` is inexactly representable, `t` is required to be one of the
|
|
two adjacents, with an implementation-defined choice of rounding direction;
|
|
that is, the conversion is required to be correctly rounded.
|
|
|
|
[endsect]
|
|
|
|
[section Subranged Conversion Direction, Subtype and Supertype]
|
|
|
|
Given a source type `S` and a destination type `T`, there is a
|
|
[*conversion direction] denoted: `S->T`.
|
|
|
|
For any two ranges the following ['range relation] can be defined:
|
|
A range `X` can be ['entirely contained] in a range `Y`, in which case
|
|
it is said that `X` is enclosed by `Y`.
|
|
|
|
[: [*Formally:] `R(S)` is enclosed by `R(T)` iif `(R(S) intersection R(T)) == R(S)`.]
|
|
|
|
If the source type range, `R(S)`, is not enclosed in the target type range,
|
|
`R(T)`; that is, if `(R(S) & R(T)) != R(S)`, the conversion direction is said
|
|
to be [*subranged], which means that `R(S)` is not entirely contained in `R(T)`
|
|
and therefore there is some portion of the source range which falls outside
|
|
the target range. In other words, if a conversion direction `S->T` is subranged,
|
|
there are values in `S` which cannot be represented in `T` because they are
|
|
out of range.
|
|
Notice that for `S->T`, the adjective subranged applies to `T`.
|
|
|
|
Examples:
|
|
|
|
Given the following numeric types all representing real numbers:
|
|
|
|
* `X` with numeric set `{-2.0,-1.0,0.0,+1.0,+2.0}` and range `[-2.0,+2.0]`
|
|
* `Y` with numeric set `{-2.0,-1.5,-1.0,-0.5,0.0,+0.5,+1.0,+1.5,+2.0}` and range `[-2.0,+2.0]`
|
|
* `Z` with numeric set `{-1.0,0.0,+1.0}` and range `[-1.0,+1.0]`
|
|
|
|
For:
|
|
|
|
[variablelist
|
|
[[(a) X->Y:][
|
|
`R(X) & R(Y) == R(X)`, then `X->Y` is not subranged.
|
|
Thus, all values of type `X` are representable in the type `Y`.
|
|
]]
|
|
[[(b) Y->X:][
|
|
`R(Y) & R(X) == R(Y)`, then `Y->X` is not subranged.
|
|
Thus, all values of type `Y` are representable in the type `X`, but in this case,
|
|
some values are ['inexactly] representable (all the halves).
|
|
(note: it is to permit this case that a range is an interval of abstract values and
|
|
not an interval of typed values)
|
|
]]
|
|
[[(b) X->Z:][
|
|
`R(X) & R(Z) != R(X)`, then `X->Z` is subranged.
|
|
Thus, some values of type `X` are not representable in the type `Z`, they fall
|
|
out of range `(-2.0 and +2.0)`.
|
|
]]
|
|
]
|
|
|
|
It is possible that `R(S)` is not enclosed by `R(T)`, while neither is `R(T)` enclosed
|
|
by `R(S)`; for example, `UNSIG=[0,255]` is not enclosed by `SIG=[-128,127]`;
|
|
neither is `SIG` enclosed by `UNSIG`.
|
|
This implies that is possible that a conversion direction is subranged both ways.
|
|
This occurs when a mixture of signed/unsigned types are involved and indicates that
|
|
in both directions there are values which can fall out of range.
|
|
|
|
Given the range relation (subranged or not) of a conversion direction `S->T`, it
|
|
is possible to classify `S` and `T` as [*supertype] and [*subtype]:
|
|
If the conversion is subranged, which means that `T` cannot represent all possible
|
|
values of type `S`, `S` is the supertype and `T` the subtype; otherwise, `T` is the
|
|
supertype and `S` the subtype.
|
|
|
|
For example:
|
|
|
|
[: `R(float)=[-FLT_MAX,FLT_MAX]` and `R(double)=[-DBL_MAX,DBL_MAX]` ]
|
|
|
|
If `FLT_MAX < DBL_MAX`:
|
|
|
|
* `double->float` is subranged and `supertype=double`, `subtype=float`.
|
|
* `float->double` is not subranged and `supertype=double`, `subtype=float`.
|
|
|
|
Notice that while `double->float` is subranged, `float->double` is not,
|
|
which yields the same supertype,subtype for both directions.
|
|
|
|
Now consider:
|
|
|
|
[: `R(int)=[INT_MIN,INT_MAX]` and `R(unsigned int)=[0,UINT_MAX]` ]
|
|
|
|
A C++ implementation is required to have `UINT_MAX > INT_MAX` (§3.9/3), so:
|
|
|
|
* 'int->unsigned' is subranged (negative values fall out of range)
|
|
and `supertype=int`, `subtype=unsigned`.
|
|
* 'unsigned->int' is ['also] subranged (high positive values fall out of range)
|
|
and `supertype=unsigned`, `subtype=int`.
|
|
|
|
In this case, the conversion is subranged in both directions and the
|
|
supertype,subtype pairs are not invariant (under inversion of direction).
|
|
This indicates that none of the types can represent all the values of the other.
|
|
|
|
When the supertype is the same for both `S->T` and `T->S`, it is effectively
|
|
indicating a type which can represent all the values of the subtype.
|
|
Consequently, if a conversion `X->Y` is not subranged, but the opposite `(Y->X)` is,
|
|
so that the supertype is always `Y`, it is said that the direction `X->Y` is [*correctly
|
|
rounded value preserving], meaning that all such conversions are guaranteed to
|
|
produce results in range and correctly rounded (even if inexact).
|
|
For example, all integer to floating conversions are correctly rounded value preserving.
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
|