Skip to content

Return decimal for decimal-based quantities #1074

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6c72c34
Test by hand (need to do all these changes in generator)
pgrawehr Mar 19, 2022
5af2990
IQuantity.Value is QuantityValue
pgrawehr Apr 3, 2022
397ec62
Improved support for QuantityValue
pgrawehr Apr 9, 2022
5f459d9
Add QuantityValue operators
pgrawehr Apr 17, 2022
e2a1952
Generator creates the expected Information.g.cs
pgrawehr Apr 17, 2022
1a6adde
Except for the tests, it compiles again
pgrawehr Apr 17, 2022
206b7b8
Rebase to correct v5 branch
pgrawehr Apr 17, 2022
ef457d7
Review findings
pgrawehr May 8, 2022
9e10c89
Add missing documentation comment
pgrawehr May 8, 2022
8e4b6af
Unit tests compile again
pgrawehr May 8, 2022
fadd229
Some small findings addressed
pgrawehr May 8, 2022
8c3f453
Fix minor accuracy issue
pgrawehr May 8, 2022
4137b4b
Simplify As() overloads by reusing and casting to double
angularsen May 22, 2022
fd5ab04
Fix unit test accuracy
pgrawehr May 29, 2022
6feb260
Move ToQuantityValue to extension methods
pgrawehr May 29, 2022
008b038
Ensure correct json is written
pgrawehr May 29, 2022
0662691
Merge remote-tracking branch 'remotes/angularsen/release/v5' into dec…
pgrawehr Jun 5, 2022
7cb874a
Fix merge problems
pgrawehr Jun 5, 2022
fc9358b
Test code
pgrawehr Jun 6, 2022
0193b06
Merge branch 'release/v5' into decimalConversion2
angularsen Sep 2, 2022
686d187
Remove implicit multiplication of QuantityValue
pgrawehr Oct 2, 2022
1daf064
Remove ExplicitInterfaceTest
angularsen Nov 29, 2022
a3a3771
Revert back to lowercase scientific notation
angularsen Nov 29, 2022
3ba016a
revert whitespace
angularsen Nov 29, 2022
822d81e
Minor refactor
angularsen Nov 29, 2022
aa5e6ec
QuantityValue: Fix missing assignment in new ctor
angularsen Nov 29, 2022
f2d31da
QuantityValue: Add IComparable<>, IComparable
angularsen Nov 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 45 additions & 19 deletions CodeGen/Generators/UnitsNetGen/QuantityGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,11 +262,11 @@ private void GenerateProperties()
public {_valueType} Value => _value;
");

// Need to provide explicit interface implementation for decimal quantities like Information
if (_quantity.ValueType != "double")
Writer.WL(@"
double IQuantity.Value => (double) _value;
Writer.WL(@"
/// <inheritdoc />
QuantityValue IQuantity.Value => _value;
");
// Need to provide explicit interface implementation for decimal quantities like Information
if (_quantity.ValueType == "decimal")
Writer.WL(@"
/// <inheritdoc cref=""IDecimalQuantity.Value""/>
Expand Down Expand Up @@ -306,11 +306,11 @@ private void GenerateConversionProperties()

Writer.WL($@"
/// <summary>
/// Gets a <see cref=""double""/> value of this quantity converted into <see cref=""{_unitEnumName}.{unit.SingularName}""/>
/// Gets a <see cref=""{_quantity.ValueType}""/> value of this quantity converted into <see cref=""{_unitEnumName}.{unit.SingularName}""/>
/// </summary>");
Writer.WLIfText(2, GetObsoleteAttributeOrNull(unit));
Writer.WL($@"
public double {unit.PluralName} => As({_unitEnumName}.{unit.SingularName});
public {_quantity.ValueType} {unit.PluralName} => As({_unitEnumName}.{unit.SingularName});
");
}

Expand Down Expand Up @@ -651,7 +651,7 @@ private void GenerateArithmeticOperators()
}}

/// <summary>Get ratio value from dividing <see cref=""{_quantity.Name}""/> by <see cref=""{_quantity.Name}""/>.</summary>
public static double operator /({_quantity.Name} left, {_quantity.Name} right)
public static {_quantity.ValueType} operator /({_quantity.Name} left, {_quantity.Name} right)
{{
return left.{_baseUnit.PluralName} / right.{_baseUnit.PluralName};
}}
Expand Down Expand Up @@ -806,13 +806,13 @@ public int CompareTo({_quantity.Name} other)
/// <param name=""tolerance"">The absolute or relative tolerance value. Must be greater than or equal to 0.</param>
/// <param name=""comparisonType"">The comparison type: either relative or absolute.</param>
/// <returns>True if the absolute difference between the two values is not greater than the specified relative or absolute tolerance.</returns>
public bool Equals({_quantity.Name} other, double tolerance, ComparisonType comparisonType)
public bool Equals({_quantity.Name} other, {_quantity.ValueType} tolerance, ComparisonType comparisonType)
{{
if (tolerance < 0)
throw new ArgumentOutOfRangeException(""tolerance"", ""Tolerance must be greater than or equal to 0."");

double thisValue = (double)this.Value;
double otherValueInThisUnits = other.As(this.Unit);
{_quantity.ValueType} thisValue = this.Value;
{_quantity.ValueType} otherValueInThisUnits = other.As(this.Unit);

return UnitsNet.Comparison.Equals(thisValue, otherValueInThisUnits, tolerance, comparisonType);
}}
Expand All @@ -839,17 +839,30 @@ private void GenerateConversionMethods()
/// Convert to the unit representation <paramref name=""unit"" />.
/// </summary>
/// <returns>Value converted to the specified unit.</returns>
public double As({_unitEnumName} unit)
public {_quantity.ValueType} As({_unitEnumName} unit)
{{
if (Unit == unit)
return Convert.ToDouble(Value);
return Value;

return GetValueAs(unit);
}}
");

var converted = GetValueAs(unit);
return Convert.ToDouble(converted);
if (_quantity.ValueType == "decimal")
{
Writer.WL($@"

double IQuantity<{_unitEnumName}>.As({_unitEnumName} unit)
{{
return (double)As(unit);
}}
");
}

Writer.WL($@"

/// <inheritdoc cref=""IQuantity.As(UnitSystem)""/>
public double As(UnitSystem unitSystem)
public {_quantity.ValueType} As(UnitSystem unitSystem)
{{
if (unitSystem is null)
throw new ArgumentNullException(nameof(unitSystem));
Expand All @@ -862,14 +875,27 @@ public double As(UnitSystem unitSystem)

return As(firstUnitInfo.Value);
}}
");

if (_quantity.ValueType == "decimal")
{
Writer.WL($@"
/// <inheritdoc cref=""IQuantity.As(UnitSystem)""/>
double IQuantity.As(UnitSystem unitSystem)
{{
return (double)As(unitSystem);
}}
");
}

Writer.WL($@"
/// <inheritdoc />
double IQuantity.As(Enum unit)
{{
if (!(unit is {_unitEnumName} unitAs{_unitEnumName}))
if (!(unit is {_unitEnumName} typedUnit))
throw new ArgumentException($""The given unit is of type {{unit.GetType()}}. Only {{typeof({_unitEnumName})}} is supported."", nameof(unit));

return As(unitAs{_unitEnumName});
return (double)As(typedUnit);
}}

/// <summary>
Expand Down Expand Up @@ -916,10 +942,10 @@ double IQuantity.As(Enum unit)
/// <inheritdoc />
IQuantity IQuantity.ToUnit(Enum unit)
{{
if (!(unit is {_unitEnumName} unitAs{_unitEnumName}))
if (!(unit is {_unitEnumName} typedUnit))
throw new ArgumentException($""The given unit is of type {{unit.GetType()}}. Only {{typeof({_unitEnumName})}} is supported."", nameof(unit));

return ToUnit(unitAs{_unitEnumName}, DefaultConversionFunctions);
return ToUnit(typedUnit, DefaultConversionFunctions);
}}

/// <inheritdoc cref=""IQuantity.ToUnit(UnitSystem)""/>
Expand Down
8 changes: 4 additions & 4 deletions CodeGen/Generators/UnitsNetGen/UnitTestBaseClassGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public abstract partial class {_quantity.Name}TestsBase : QuantityTestsBase
continue;

Writer.WL($@"
protected abstract double {unit.PluralName}InOne{_baseUnit.SingularName} {{ get; }}");
protected abstract {_quantity.ValueType} {unit.PluralName}InOne{_baseUnit.SingularName} {{ get; }}");
}

Writer.WL("");
Expand All @@ -114,12 +114,12 @@ public abstract partial class {_quantity.Name}TestsBase : QuantityTestsBase
continue;

Writer.WL($@"
protected virtual double {unit.PluralName}Tolerance {{ get {{ return 1e-5; }} }}");
protected virtual {_quantity.ValueType} {unit.PluralName}Tolerance {{ get {{ return { (_quantity.ValueType == "decimal" ? "1e-9m" : "1e-5") }; }} }}");
}
Writer.WL($@"
// ReSharper restore VirtualMemberNeverOverriden.Global

protected (double UnitsInBaseUnit, double Tolerence) GetConversionFactor({_unitEnumName} unit)
protected ({_quantity.ValueType} UnitsInBaseUnit, {_quantity.ValueType} Tolerence) GetConversionFactor({_unitEnumName} unit)
{{
return unit switch
{{");
Expand Down Expand Up @@ -355,7 +355,7 @@ public void ToUnit({_unitEnumName} unit)
var converted = inBaseUnits.ToUnit(unit);

var conversionFactor = GetConversionFactor(unit);
AssertEx.EqualTolerance(conversionFactor.UnitsInBaseUnit, (double)converted.Value, conversionFactor.Tolerence);
AssertEx.EqualTolerance(conversionFactor.UnitsInBaseUnit, converted.Value, conversionFactor.Tolerence);
Assert.Equal(unit, converted.Unit);
}}

Expand Down
4 changes: 2 additions & 2 deletions Common/UnitDefinitions/Power.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@
{
"SingularName": "BritishThermalUnitPerHour",
"PluralName": "BritishThermalUnitsPerHour",
"FromUnitToBaseFunc": "{x} * 0.293071m",
"FromBaseToUnitFunc": "{x} / 0.293071m",
"FromUnitToBaseFunc": "{x} * 0.29307107017m",
"FromBaseToUnitFunc": "{x} / 0.29307107017m",
"Prefixes": [ "Kilo", "Mega" ],
"Localization": [
{
Expand Down
12 changes: 6 additions & 6 deletions UnitsNet.NanoFramework/GeneratedCode/Quantities/Power.g.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public void UnitsNetBaseJsonConverter_ConvertValueUnit_works_as_expected()

Assert.NotNull(result);
Assert.IsType<Power>(result);
Assert.True(Power.FromWatts(10.2365m).Equals((Power)result, 1E-5, ComparisonType.Absolute));
Assert.True(Power.FromWatts(10.2365m).Equals((Power)result, 1E-5m, ComparisonType.Absolute));

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public void UnitsNetIComparableJsonConverter_ReadJson_works_as_expected()

Assert.NotNull(result);
Assert.IsType<Power>(result);
Assert.Equal(120D, ((Power)result).Watts);
Assert.Equal(120M, ((Power)result).Watts);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public void UnitsNetIQuantityJsonConverter_ReadJson_works_as_expected()

Assert.NotNull(result);
Assert.IsType<Power>(result);
Assert.Equal(10.3654D, ((Power)result).Watts);
Assert.Equal(10.3654M, ((Power)result).Watts);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public override void WriteJson(JsonWriter writer, IQuantity? quantity, JsonSeria
}
else
{
writer.WriteValue(quantity.Value);
writer.WriteValue((double)quantity.Value);
}

// write the 'Unit' abbreviation
Expand Down
5 changes: 3 additions & 2 deletions UnitsNet.Serialization.JsonNet/UnitsNetBaseJsonConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,14 @@ protected ValueUnit ConvertIQuantity(IQuantity quantity)
return new ExtendedValueUnit
{
Unit = $"{quantity.QuantityInfo.UnitType.Name}.{quantity.Unit}",
Value = quantity.Value,
// The type of "Value" is still double
Value = (double)quantity.Value,
ValueString = d.Value.ToString(CultureInfo.InvariantCulture),
ValueType = "decimal"
};
}

return new ValueUnit {Value = quantity.Value, Unit = $"{quantity.QuantityInfo.UnitType.Name}.{quantity.Unit}"};
return new ValueUnit {Value = (double)quantity.Value, Unit = $"{quantity.QuantityInfo.UnitType.Name}.{quantity.Unit}"};
}

/// <summary>
Expand Down
18 changes: 18 additions & 0 deletions UnitsNet.Tests/AssertEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,23 @@ public static void EqualTolerance(double expected, double actual, double toleran
Assert.True( areEqual, $"Values are not equal within absolute tolerance: {tolerance}\nExpected: {expected}\nActual: {actual}\nDiff: {actual - expected:e}" );
}
}

public static void EqualTolerance(decimal expected, decimal actual, decimal tolerance, ComparisonType comparisonType = ComparisonType.Relative)
{
if (comparisonType == ComparisonType.Relative)
{
bool areEqual = Comparison.EqualsRelative(expected, actual, tolerance);

decimal difference = Math.Abs(expected - actual);
decimal relativeDifference = difference / expected;

Assert.True(areEqual, $"Values are not equal within relative tolerance: {tolerance:P4}\nExpected: {expected}\nActual: {actual}\nDiff: {relativeDifference:P4}");
}
else if (comparisonType == ComparisonType.Absolute)
{
bool areEqual = Comparison.EqualsAbsolute(expected, actual, tolerance);
Assert.True(areEqual, $"Values are not equal within absolute tolerance: {tolerance}\nExpected: {expected}\nActual: {actual}\nDiff: {actual - expected:e}");
}
}
}
}
52 changes: 26 additions & 26 deletions UnitsNet.Tests/CustomCode/BitRateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,37 +29,37 @@ public class BitRateTests : BitRateTestsBase
{
protected override bool SupportsSIUnitSystem => false;

protected override double BitsPerSecondInOneBitPerSecond => 1d;
protected override double BytesPerSecondInOneBitPerSecond => 1.25E-1d;
protected override decimal BitsPerSecondInOneBitPerSecond => 1m;
protected override decimal BytesPerSecondInOneBitPerSecond => 1.25E-1m;

protected override double KilobitsPerSecondInOneBitPerSecond => 1E-3d;
protected override double KilobytesPerSecondInOneBitPerSecond => 1.25E-4d;
protected override double KibibitsPerSecondInOneBitPerSecond => 0.0009765625d;
protected override double KibibytesPerSecondInOneBitPerSecond => 0.0001220703125d;
protected override decimal KilobitsPerSecondInOneBitPerSecond => 1E-3m;
protected override decimal KilobytesPerSecondInOneBitPerSecond => 1.25E-4m;
protected override decimal KibibitsPerSecondInOneBitPerSecond => 0.0009765625m;
protected override decimal KibibytesPerSecondInOneBitPerSecond => 0.0001220703125m;

protected override double MegabitsPerSecondInOneBitPerSecond => 1E-6d;
protected override double MegabytesPerSecondInOneBitPerSecond => 1.25E-07d;
protected override double MebibitsPerSecondInOneBitPerSecond => 9.5367431640625E-07d;
protected override double MebibytesPerSecondInOneBitPerSecond => 1.19209289550781E-07d;
protected override decimal MegabitsPerSecondInOneBitPerSecond => 1E-6m;
protected override decimal MegabytesPerSecondInOneBitPerSecond => 1.25E-07m;
protected override decimal MebibitsPerSecondInOneBitPerSecond => 9.5367431640625E-07m;
protected override decimal MebibytesPerSecondInOneBitPerSecond => 1.19209289550781E-07m;

protected override double GigabitsPerSecondInOneBitPerSecond => 1E-9d;
protected override double GigabytesPerSecondInOneBitPerSecond => 1.25E-10d;
protected override double GibibitsPerSecondInOneBitPerSecond => 9.31322574615479E-10d;
protected override double GibibytesPerSecondInOneBitPerSecond => 1.16415321826935E-10d;
protected override decimal GigabitsPerSecondInOneBitPerSecond => 1E-9m;
protected override decimal GigabytesPerSecondInOneBitPerSecond => 1.25E-10m;
protected override decimal GibibitsPerSecondInOneBitPerSecond => 9.31322574615479E-10m;
protected override decimal GibibytesPerSecondInOneBitPerSecond => 1.16415321826935E-10m;

protected override double TerabitsPerSecondInOneBitPerSecond => 1E-12d;
protected override double TerabytesPerSecondInOneBitPerSecond => 1.25E-13d;
protected override double TebibitsPerSecondInOneBitPerSecond => 9.09494701772928E-13d;
protected override double TebibytesPerSecondInOneBitPerSecond => 1.13686837721616E-13d;
protected override decimal TerabitsPerSecondInOneBitPerSecond => 1E-12m;
protected override decimal TerabytesPerSecondInOneBitPerSecond => 1.25E-13m;
protected override decimal TebibitsPerSecondInOneBitPerSecond => 9.09494701772928E-13m;
protected override decimal TebibytesPerSecondInOneBitPerSecond => 1.13686837721616E-13m;

protected override double PetabitsPerSecondInOneBitPerSecond => 1E-15d;
protected override double PetabytesPerSecondInOneBitPerSecond => 1.25E-16d;
protected override double PebibitsPerSecondInOneBitPerSecond => 8.88178419700125E-16d;
protected override double PebibytesPerSecondInOneBitPerSecond => 1.11022302462516E-16d;
protected override decimal PetabitsPerSecondInOneBitPerSecond => 1E-15m;
protected override decimal PetabytesPerSecondInOneBitPerSecond => 1.25E-16m;
protected override decimal PebibitsPerSecondInOneBitPerSecond => 8.88178419700125E-16m;
protected override decimal PebibytesPerSecondInOneBitPerSecond => 1.11022302462516E-16m;

protected override double ExabitsPerSecondInOneBitPerSecond => 1E-18d;
protected override double ExabytesPerSecondInOneBitPerSecond => 1.25E-19d;
protected override double ExbibitsPerSecondInOneBitPerSecond => 8.67361738E-19d;
protected override double ExbibytesPerSecondInOneBitPerSecond => 1.0842021724855E-19d;
protected override decimal ExabitsPerSecondInOneBitPerSecond => 1E-18m;
protected override decimal ExabytesPerSecondInOneBitPerSecond => 1.25E-19m;
protected override decimal ExbibitsPerSecondInOneBitPerSecond => 8.67361738E-19m;
protected override decimal ExbibytesPerSecondInOneBitPerSecond => 1.0842021724855E-19m;
}
}
Loading