random method
- Random rv, {
- @Deprecated('use genNormal/genSubNormal instead') bool normal = false,
- @Deprecated('use genNormal/genSubNormal instead') bool subNormal = false,
- bool genNormal = true,
- bool genSubNormal = true,
- bool excludeInfinity = false,
- FpvType? gt,
- FpvType? lt,
- FpvType? gte,
- FpvType? lte,
Generate a random FloatingPointValue, using random seed rv
in a given
range, if provided. The distribution of values is uniform across the
combined bitfield of exponent and mantissa.
This generates a valid FloatingPointValue anywhere in the range it can
represent:a general FloatingPointValue has a mantissa in [0,2)
with 0 <= exponent <= maxExponent()
.
If normal
is true
, this method will only generate mantissas in the
range of [1,2)
and minExponent() <= exponent <= maxExponent()
,
otherwise if subNormal
is true
, it will only generate mantissas in the
range of [0,1)
and exponent == 0
. If both are false
, it will
generate mantissas in the range of [0,2)
and minExponent() <= exponent <= maxExponent()
.
The normal
and subNormal
parameters are deprecated, please use
genNormal
and genSubNormal
instead.
If genNormal
is true
, this method will generate normal numbers, and if
genSubNormal
is true
, it will generate subnormal numbers. If both
are false
, an exception will be thrown. Note that the range of numbers
to be generated is respected by these flags, so a range which does not
contain the requested type of number will result in a throw.
You can constrain the range of random numbers generated by using a lower
bound specified by gt
or gte
and an upper bound specified by lt
or
lte
. If either both lower or both upper bounds are specified, the
tightest bounds are used.
If excludeInfinity
is true
, then infinity values will not be
generated. NaN values are never generated.
The range is interpreted as follows:
gt
,lt
: generate a value in the range([gt], [lt])
gte
,lt
: generate a value in the range[[gte], [lt])
gt
,lte
: generate a value in the range([gt], [lte]]
gte
,lte
: generate a value in the range[[gte], [lte]]
gt
: generate a value in the range([gt], ∞)
gte
: generate a value in the range[[gte], ∞)
lt
: generate a value in the range(-∞, [lt])
lte
: generate a value in the range(-∞, [lte]]
- none: generate a value in the range
(-∞, ∞)
Implementation
FpvType random(Random rv,
{@Deprecated('use genNormal/genSubNormal instead')
bool normal = false, // if true, generate only normal numbers
@Deprecated('use genNormal/genSubNormal instead')
bool subNormal = false, // if true generate only subnormal numbers
// These are the new parameters to replace normal/subNormal.
bool genNormal = true,
bool genSubNormal = true,
bool excludeInfinity = false,
FpvType? gt,
FpvType? lt,
FpvType? gte,
FpvType? lte}) {
FpvType cloneConstant(FloatingPointConstants c) =>
_unpopulated.clonePopulator().ofConstant(c) as FpvType;
// DEPRECATION: these checks are for the deprecated parameters.
if (normal & subNormal) {
throw RohdHclException(
'FloatingPointValuePopulator.random: cannot have both normal and '
'subNormal be true');
}
if (normal & !genNormal) {
throw RohdHclException(
'FloatingPointValuePopulator.random: cannot have both normal and '
'genNormal be false -- normal will be deprecated, use genNormal');
}
if (subNormal & !genSubNormal) {
throw RohdHclException(
'FloatingPointValuePopulator.random: cannot have both subNormal and '
'genSubNormal be false -- subNormal will be deprecated, use '
'genSubNormal');
}
if (subNormal & subNormalAsZero) {
throw RohdHclException(
'FloatingPointValuePopulator.random: cannot have both subNormal and '
'subNormalAsZero be true');
}
// End DEPRECATION region.
_checkMatching('gt', gt);
_checkMatching('lt', lt);
_checkMatching('gte', gte);
_checkMatching('lte', lte);
if (gt != null) {
if (lt != null) {
if (gt.compareTo(lt) >= 0) {
throw RohdHclException(
'FloatingPointValuePopulator.random: cannot have $gt >= '
'$lt');
}
} else if (lte != null) {
if (gt.compareTo(lte) > 0) {
throw RohdHclException(
'FloatingPointValuePopulator.random: cannot have $gt > '
'$lte');
}
}
} else if (gte != null) {
if (lt != null) {
if (gte.compareTo(lt) >= 0) {
throw RohdHclException(
'FloatingPointValuePopulator.random: cannot have $gte >= '
'$lt');
}
} else if (lte != null) {
if (gte.compareTo(lte) > 0) {
throw RohdHclException(
'FloatingPointValuePopulator.random: cannot have $gte > '
'$lte');
}
}
}
// Manage the old parameters-- this will not be necessary after deprecation.
final bool doGenNormal;
final bool doGenSubNormal;
if (normal) {
doGenNormal = true;
doGenSubNormal = false;
} else if (subNormal) {
doGenNormal = false;
doGenSubNormal = true;
} else {
doGenNormal = genNormal;
doGenSubNormal = genSubNormal;
}
// End Manage the old parameters.
if (!doGenNormal & !doGenSubNormal) {
throw RohdHclException(
'FloatingPointValuePopulator.random: cannot have both genNormal and '
'genSubNormal be false');
}
if (doGenSubNormal & subNormalAsZero) {
throw RohdHclException(
'FloatingPointValuePopulator.random: cannot have doGenSubNormal be '
'true and subNormalAsZero be true');
}
if (explicitJBit) {
FloatingPointValuePopulator populator() => FloatingPointValue.populator(
exponentWidth: exponentWidth, mantissaWidth: mantissaWidth - 1);
return ofFloatingPointValue(populator().random(rv,
genNormal: genNormal,
genSubNormal: genSubNormal,
gt: (gt != null)
? populator().ofFloatingPointValue(gt, canonicalizeExplicit: true)
: null,
lt: (lt != null)
? populator().ofFloatingPointValue(lt, canonicalizeExplicit: true)
: null,
gte: (gte != null)
? populator()
.ofFloatingPointValue(gte, canonicalizeExplicit: true)
: null,
lte: (lte != null)
? populator()
.ofFloatingPointValue(lte, canonicalizeExplicit: true)
: null)) as FpvType;
}
if ((lt == null) & (lte == null)) {
lte = doGenSubNormal & !doGenNormal
? cloneConstant(FloatingPointConstants.largestPositiveSubnormal)
: !excludeInfinity
? cloneConstant(FloatingPointConstants.positiveInfinity)
: null;
lt = (lte == null) & excludeInfinity
? cloneConstant(FloatingPointConstants.positiveInfinity)
: null;
}
if ((gt == null) & (gte == null)) {
gte = doGenSubNormal & !doGenNormal
? cloneConstant(FloatingPointConstants.largestPositiveSubnormal)
.negate() as FpvType
: !excludeInfinity
? cloneConstant(FloatingPointConstants.negativeInfinity)
: null;
gt = (gte == null) & excludeInfinity
? cloneConstant(FloatingPointConstants.negativeInfinity)
: null;
}
// Take the tightest constraints and assign as local variables.
final FpvType? lgte;
final FpvType? lgt;
final FpvType? llte;
final FpvType? llt;
if ((gt != null) && (gte != null)) {
final gtTighter = (gt.compareTo(gte) != -1);
lgte = gtTighter ? null : gte;
lgt = gtTighter ? gt : null;
} else {
lgte = gte;
lgt = gt;
}
if ((lt != null) && (lte != null)) {
final ltTighter = (lt.compareTo(lte) != 1);
llte = ltTighter ? null : lte;
llt = ltTighter ? lt : null;
} else {
llte = lte;
llt = lt;
}
// Trim the limits to skip either normal or subnormal ranges as needed.
// - normal | - subnormal | 0 | + subnormal | + normal
final trimGt = (lgt == null)
? null
: ((lgt.isNormal() & (lgt.sign == LogicValue.one) & !doGenNormal)
? cloneConstant(FloatingPointConstants.smallestPositiveNormal)
.negate() as FpvType
: ((!lgt.isNormal() &
(lgt.sign == LogicValue.one) &
!doGenSubNormal)
? cloneConstant(
FloatingPointConstants.smallestPositiveSubnormal)
.negate() as FpvType
: (!lgt.isNormal() &
(lgt.sign == LogicValue.zero) &
!doGenSubNormal)
? cloneConstant(
FloatingPointConstants.largestPositiveSubnormal)
: lgt));
final trimGte = (lgte == null)
? null
: ((lgte.isNormal() & (lgte.sign == LogicValue.one) & !doGenNormal)
? cloneConstant(FloatingPointConstants.largestPositiveSubnormal)
.negate() as FpvType
: ((!lgte.isNormal() &
(lgte.sign == LogicValue.one) &
!doGenSubNormal)
? cloneConstant(FloatingPointConstants.positiveZero)
: (!lgte.isNormal() &
(lgte.sign == LogicValue.zero) &
!doGenSubNormal)
? cloneConstant(
FloatingPointConstants.smallestPositiveNormal)
: lgte));
final trimLt = (llt == null)
? null
: ((llt.isNormal() & (llt.sign == LogicValue.zero) & !doGenNormal)
? cloneConstant(FloatingPointConstants.smallestPositiveNormal)
: ((!llt.isNormal() & !doGenSubNormal)
? cloneConstant(FloatingPointConstants.largestPositiveSubnormal)
.negate() as FpvType
: llt));
final trimLte = (llte == null)
? null
: ((llte.isNormal() & (llte.sign == LogicValue.zero) & !doGenNormal)
? cloneConstant(FloatingPointConstants.largestPositiveSubnormal)
: ((!llte.isNormal() & !doGenSubNormal)
? cloneConstant(FloatingPointConstants.smallestPositiveNormal)
.negate()
: llte));
final negNormals = doGenNormal &
((trimGt ?? trimGte)!.sign == LogicValue.one) &
((trimGt ?? trimGte)!.isNormal()) &
(trimGt !=
cloneConstant(FloatingPointConstants.smallestPositiveNormal)
.negate());
final posNormals = doGenNormal &
((trimLt ?? trimLte)!.sign == LogicValue.zero) &
((trimLt ?? trimLte)?.isNormal() ?? true) &
(trimLt !=
cloneConstant(FloatingPointConstants.smallestPositiveNormal));
final negSubNormals = doGenSubNormal &
((trimGt ?? trimGte)!.sign == LogicValue.one) &
!(trimGt?.isAZero ?? false) &
!(trimGte?.isAZero ?? false) &
(trimGt !=
cloneConstant(FloatingPointConstants.smallestPositiveSubnormal)
.negate());
final posSubNormals = doGenSubNormal &
((trimLt ?? trimLte)!.sign == LogicValue.zero) &
!(trimLt?.isAZero ?? false) &
!(trimLte?.isAZero ?? false) &
(trimLt !=
cloneConstant(FloatingPointConstants.smallestPositiveSubnormal));
if ((!doGenSubNormal & !negNormals & !posNormals) ||
(!doGenNormal & !negSubNormals & !posSubNormals)) {
throw RohdHclException(
'FloatingPointValuePopulator.random: cannot generate value, '
'range excludes all normal and subnormal values');
}
// Note that we never have both gt/gte or lt/lte null because of Infinity.
var gtSign = (trimGt ?? trimGte)?.sign;
var gtMagnitude =
(trimGt != null) ? [trimGt.exponent, trimGt.mantissa].swizzle() : null;
var gteMagnitude = (trimGte != null)
? [trimGte.exponent, trimGte.mantissa].swizzle()
: null;
var ltSign = (trimLt ?? trimLte)?.sign;
var ltMagnitude =
(trimLt != null) ? [trimLt.exponent, trimLt.mantissa].swizzle() : null;
var lteMagnitude = (trimLte != null)
? [trimLte.exponent, trimLte.mantissa].swizzle()
: null;
if ((!doGenSubNormal) & negNormals & posNormals) {
// We need to pick a side to generate from.
final genSign = rv.nextLogicValue(width: 1);
if (genSign == LogicValue.zero) {
// Generate positive normals.
gtSign = LogicValue.zero;
gtMagnitude = null;
final rhGte =
cloneConstant(FloatingPointConstants.smallestPositiveNormal);
gteMagnitude = [rhGte.exponent, rhGte.mantissa].swizzle();
} else {
// Generate negative normals.
ltSign = LogicValue.one;
ltMagnitude = null;
final lhLte =
cloneConstant(FloatingPointConstants.smallestPositiveNormal)
.negate() as FpvType;
lteMagnitude = [lhLte.exponent, lhLte.mantissa].swizzle();
}
if ((!doGenNormal) & !negSubNormals & !posSubNormals) {
throw RohdHclException(
'FloatingPointValuePopulator.random: cannot generate value, '
'range excludes all normal and subnormal values');
}
} else if ((!doGenNormal) & negSubNormals & posSubNormals) {
// We need to pick a side to generate from.
final genSign = rv.nextLogicValue(width: 1);
if (genSign == LogicValue.zero) {
// Generate positive subnormals.
gtSign = LogicValue.zero;
gtMagnitude = null;
final rhGte = cloneConstant(FloatingPointConstants.positiveZero);
gteMagnitude = [rhGte.exponent, rhGte.mantissa].swizzle();
} else {
// Generate negative subnormals.
ltSign = LogicValue.one;
ltMagnitude = null;
final lhLte = cloneConstant(FloatingPointConstants.negativeZero);
lteMagnitude = [lhLte.exponent, lhLte.mantissa].swizzle();
}
}
final tgt = (gtMagnitude != null)
? SignMagnitudeValue(sign: gtSign!, magnitude: gtMagnitude)
: null;
final tgte = (gteMagnitude != null)
? SignMagnitudeValue(sign: gtSign!, magnitude: gteMagnitude)
: null;
final tlt = (ltMagnitude != null)
? SignMagnitudeValue(sign: ltSign!, magnitude: ltMagnitude)
: null;
final tlte = (lteMagnitude != null)
? SignMagnitudeValue(sign: ltSign!, magnitude: lteMagnitude)
: null;
final smv =
SignMagnitudeValue.populator(width: exponentWidth + mantissaWidth)
.random(rv, gt: tgt, gte: tgte, lt: tlt, lte: tlte);
return populate(
sign: smv.sign,
exponent: smv.magnitude
.slice(exponentWidth + mantissaWidth - 1, mantissaWidth),
mantissa: smv.magnitude.slice(mantissaWidth - 1, 0));
}