#2902·LiteDB

Mixed numeric comparison is non-transitive across double and decimal

Author: JKamskerCreated Sep 16, 2026Updated Sep 16, 2026
Labelsbugbreaking-changeseverity: highpriority: P2

Summary

Mixed double/decimal comparison converts doubles through Convert.ToDecimal, which rounds to approximately 15 significant digits. Distinct adjacent doubles can therefore both compare equal to one decimal while remaining unequal to each other, violating equality transitivity.

This predates #2755 and should not be fixed in that PR.

Minimal reproduction

csharp
var first = new BsonValue(0.1d);
var nextDouble = BitConverter.Int64BitsToDouble(
    BitConverter.DoubleToInt64Bits(0.1d) + 1);
var second = new BsonValue(nextDouble);
var decimalValue = new BsonValue(0.1m);

Assert.True(first.Equals(decimalValue));
Assert.True(second.Equals(decimalValue));
Assert.False(first.Equals(second));

Assert.True(new BsonValue(double.Epsilon).Equals(new BsonValue(0m)));

Impact

Equality is not transitive across numeric BSON types. This can make equality and ordering behavior depend on the comparison path and can violate assumptions used by sets, dictionaries, sorting, and indexes.

Correcting the conversion/comparison rule may change the ordering of existing mixed-type numeric index keys on disk, so the compatibility implications need to be documented and handled as a breaking change.

Related: #2892 describes a separate document-ordering violation in the same general class of comparison-contract problems.