convertRationalToBinary static method

BsonBinary convertRationalToBinary(
  1. Rational? rational
)

Implementation

static BsonBinary convertRationalToBinary(Rational? rational) {
  if (rational == null) {
    // Rational does not manage NaN
    return BsonBinary.fromHexString('0000000000000000000000000000007c');
  } else if (rational == infinityValue) {
    // Rational does not manage infinity, this is a conventional value
    return BsonBinary.fromHexString('00000000000000000000000000000078');
  } else if (rational == -infinityValue) {
    // Rational does not manage -infinity, this is a conventional value
    return BsonBinary.fromHexString('000000000000000000000000000000f8');
  } else if (rational == Rational.zero) {
    return BsonBinary.fromHexString('00000000000000000000000000004030');
  } else if (rational.hasFinitePrecision &&
      // if bigger than one (i.e at least one integer digit)
      // we could have a lot of unnecessary trailing zeros calculated
      // in the precision.
      rational < _r1 &&
      rational.precision > 34) {
    // Return zero
    return BsonBinary.fromHexString('00000000000000000000000000004030');
  }

  String res;
  if (rational.hasFinitePrecision) {
    res = rational.toStringAsFixed(rational.scale);
  } else {
    res = rational.toStringAsPrecisionFast(34);
  }
  var exponent = extractExponent(res);
  var significand = extractSignificand(res);

  // Significand greater or equal to 10^34 - 1 must be considered as 0
  if (significand > maxSignificand) {
    significand = Rational.zero;
  }

  // The exponent calculated implies that the significand is of the form
  // i.ddddddd, but our significand must be an integer.
  // plus 6176 (exp 0, lower is negative)
  var biasedExponent = exponent + 6176;

  // encoding as case 1 number (first bit of the combination field not '11')
  // because the minimum value of the case 2 (2^114) is higher than
  // the max allowed value (10^34-1)
  var highSignificand = significand ~/ maxUInt64;
  var lowSignificand = significand - (highSignificand * maxUInt64);
  // Needed because we are using Int instead of UInt
  if (lowSignificand >= maxInt64) {
    lowSignificand -= maxUInt64;
  }

  var lowInt = Int64.parseRadix(lowSignificand.toString(), 10);
  var highInt = Int64.parseRadix(highSignificand.toString(), 10);
  highInt += (Int64(biasedExponent) << 49);
  if (rational.isNegative) {
    highInt |= signMask;
  }
  return BsonBinary(16)
    ..writeFixInt64(lowInt)
    ..writeFixInt64(highInt);
}