ofDouble method

FpvType ofDouble(
  1. double inDouble, {
  2. FloatingPointRoundingMode roundingMode = FloatingPointRoundingMode.roundNearestEven,
})

Convert from double using its native binary representation

Implementation

FpvType ofDouble(double inDouble,
    {FloatingPointRoundingMode roundingMode =
        FloatingPointRoundingMode.roundNearestEven}) {
  if (explicitJBit) {
    return ofFloatingPointValue(FloatingPointValue.populator(
            exponentWidth: exponentWidth, mantissaWidth: mantissaWidth - 1)
        .ofDouble(inDouble, roundingMode: roundingMode)) as FpvType;
  }
  if (inDouble.isNaN) {
    return nan;
  }

  if (inDouble.isInfinite) {
    return ofConstant(
      inDouble < 0.0
          ? FloatingPointConstants.negativeInfinity
          : FloatingPointConstants.positiveInfinity,
    );
  }

  if (roundingMode != FloatingPointRoundingMode.roundNearestEven &&
      roundingMode != FloatingPointRoundingMode.truncate) {
    throw UnimplementedError(
        'Only roundNearestEven or truncate is supported for this width');
  }

  final fp64 = FloatingPoint64Value.populator().ofDouble(inDouble);
  final fp64Mw = fp64.mantissa.width;
  final exponent64 = fp64.exponent;

  var expVal = (exponent64.toInt() - fp64.bias) + bias;
  final mantissa64n = ((expVal <= 0)
      ? [LogicValue.one, fp64.mantissa].swizzle() >>>
          (-expVal +
              (!explicitJBit & (fp64.exponent.toInt() > 0)
                  ? 1
                  : explicitJBit
                      ? 1
                      : 0))
      : [LogicValue.one, fp64.mantissa].swizzle());

  var mantissa = mantissa64n.slice(fp64Mw - (explicitJBit ? 0 : 1),
      fp64Mw - mantissaWidth + (explicitJBit ? 1 : 0));

  // TODO(desmonddak): this should be in a separate function to use
  //  with a FloatingPointValue converter we need.
  if (roundingMode == FloatingPointRoundingMode.roundNearestEven) {
    final stickyPos = fp64Mw - (mantissaWidth + 3);
    final sticky =
        (stickyPos >= 0) ? mantissa64n.slice(stickyPos, 0).or() : 0;
    final roundPos = stickyPos + 1;
    final round = ((roundPos >= 0) & (roundPos > stickyPos))
        ? mantissa64n[roundPos]
        : 0;
    final guardPos = roundPos + 1;
    final guard = (guardPos >= 1) ? mantissa64n[roundPos + 1] : 0;

    // RNE Rounding
    if (guard == LogicValue.one) {
      if ((round == LogicValue.one) |
          (sticky == LogicValue.one) |
          (mantissa[0] == LogicValue.one)) {
        mantissa += 1;
        if (mantissa == LogicValue.zero.zeroExtend(mantissa.width)) {
          expVal += 1;
          if (explicitJBit) {
            mantissa = [
              LogicValue.one,
              LogicValue.zero.zeroExtend(mantissa.width - 1)
            ].swizzle();
          }
        }
      }
    }
  }

  if (_unpopulated.supportsInfinities && expVal > maxExponent + bias) {
    return ofConstant(
      fp64.sign.toBool()
          ? FloatingPointConstants.negativeInfinity
          : FloatingPointConstants.positiveInfinity,
    );
  }

  final exponent =
      LogicValue.ofBigInt(BigInt.from(max(expVal, 0)), exponentWidth);

  if (subNormalAsZero && expVal <= 0) {
    // If we are subnormal, we return zero
    mantissa = LogicValue.zero.zeroExtend(mantissaWidth);
  }

  final sign = fp64.sign;

  return populate(
    sign: sign,
    exponent: exponent,
    mantissa: mantissa,
  );
}