random method

FpvType random(
  1. Random rv, {
  2. @Deprecated('use genNormal/genSubNormal instead') bool normal = false,
  3. @Deprecated('use genNormal/genSubNormal instead') bool subNormal = false,
  4. bool genNormal = true,
  5. bool genSubNormal = true,
  6. bool excludeInfinity = false,
  7. FpvType? gt,
  8. FpvType? lt,
  9. FpvType? gte,
  10. 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));
}