From 55dbded76b19b522480b679febf284bc1da8c5a2 Mon Sep 17 00:00:00 2001 From: Tristan Milnthorp Date: Fri, 14 Dec 2018 10:04:41 -0500 Subject: [PATCH] Conversions using Math.Floor return incorrect values for negative numbers. Using Math.Truncate instead. Adding tests. --- UnitsNet.Tests/CustomCode/LengthTests.cs | 16 +++++++++++++++- UnitsNet.Tests/CustomCode/MassTests.cs | 17 +++++++++++++++++ .../CustomCode/Quantities/Length.extra.cs | 18 +++++++++--------- UnitsNet/CustomCode/Quantities/Mass.extra.cs | 19 ++++++++++--------- 4 files changed, 51 insertions(+), 19 deletions(-) diff --git a/UnitsNet.Tests/CustomCode/LengthTests.cs b/UnitsNet.Tests/CustomCode/LengthTests.cs index 875ba7dff8..9b64a25383 100644 --- a/UnitsNet.Tests/CustomCode/LengthTests.cs +++ b/UnitsNet.Tests/CustomCode/LengthTests.cs @@ -161,6 +161,20 @@ public void MinValueIsCorrectForUnitWithBaseTypeDouble() Assert.Equal(double.MinValue, Length.MinValue.Meters); } - + [Fact] + public void NegativeLengthToStonePoundsReturnsCorrectValues() + { + var negativeLength = Length.FromInches(-1.0); + var feetInches = negativeLength.FeetInches; + + Assert.Equal(0, feetInches.Feet); + Assert.Equal(-1.0, feetInches.Inches); + + negativeLength = Length.FromInches(-25.0); + feetInches = negativeLength.FeetInches; + + Assert.Equal(-2.0, feetInches.Feet); + Assert.Equal(-1.0, feetInches.Inches); + } } } diff --git a/UnitsNet.Tests/CustomCode/MassTests.cs b/UnitsNet.Tests/CustomCode/MassTests.cs index 9cbc92c2de..6b0a9b70ed 100644 --- a/UnitsNet.Tests/CustomCode/MassTests.cs +++ b/UnitsNet.Tests/CustomCode/MassTests.cs @@ -20,6 +20,7 @@ // THE SOFTWARE. using System; +using UnitsNet.Units; using Xunit; namespace UnitsNet.Tests.CustomCode @@ -106,5 +107,21 @@ public void MassTimesAccelerationEqualsForce() Force force = Mass.FromKilograms(18)*Acceleration.FromMetersPerSecondSquared(3); Assert.Equal(force, Force.FromNewtons(54)); } + + [Fact] + public void NegativeMassToStonePoundsReturnsCorrectValues() + { + var negativeMass = Mass.FromPounds(-1.0); + var stonePounds = negativeMass.StonePounds; + + Assert.Equal(0, stonePounds.Stone); + Assert.Equal(-1.0, stonePounds.Pounds); + + negativeMass = Mass.FromPounds(-25.0); + stonePounds = negativeMass.StonePounds; + + Assert.Equal(-1.0, stonePounds.Stone); + Assert.Equal(-11.0, stonePounds.Pounds); + } } } diff --git a/UnitsNet/CustomCode/Quantities/Length.extra.cs b/UnitsNet/CustomCode/Quantities/Length.extra.cs index 8ba55134c1..e33d5e462e 100644 --- a/UnitsNet/CustomCode/Quantities/Length.extra.cs +++ b/UnitsNet/CustomCode/Quantities/Length.extra.cs @@ -41,7 +41,7 @@ public sealed partial class Length public partial struct Length #endif { - private const double FeetToInches = 12; + private const double InchesInOneFoot = 12; /// /// Converts the length to a customary feet/inches combination. @@ -50,11 +50,11 @@ public FeetInches FeetInches { get { - double totalInches = Inches; - double wholeFeet = Math.Floor(totalInches/FeetToInches); - double inches = totalInches%FeetToInches; + var inInches = Inches; + var feet = Math.Truncate(inInches / InchesInOneFoot); + var inches = inInches % InchesInOneFoot; - return new FeetInches(wholeFeet, inches); + return new FeetInches(feet, inches); } } @@ -63,7 +63,7 @@ public FeetInches FeetInches /// public static Length FromFeetInches(double feet, double inches) { - return FromInches(FeetToInches*feet + inches); + return FromInches(InchesInOneFoot*feet + inches); } // Windows Runtime Component does not allow operator overloads: https://msdn.microsoft.com/en-us/library/br230301.aspx @@ -140,9 +140,9 @@ public string ToString([CanBeNull] Culture cultureInfo) { // Note that it isn't customary to use fractions - one wouldn't say "I am 5 feet and 4.5 inches". // So inches are rounded when converting from base units to feet/inches. - UnitSystem unitSystem = UnitSystem.GetCached(cultureInfo); - string footUnit = unitSystem.GetDefaultAbbreviation(LengthUnit.Foot); - string inchUnit = unitSystem.GetDefaultAbbreviation(LengthUnit.Inch); + var unitSystem = UnitSystem.GetCached(cultureInfo); + var footUnit = unitSystem.GetDefaultAbbreviation(LengthUnit.Foot); + var inchUnit = unitSystem.GetDefaultAbbreviation(LengthUnit.Inch); return string.Format(unitSystem.Culture, "{0:n0} {1} {2:n0} {3}", Feet, footUnit, Math.Round(Inches), inchUnit); diff --git a/UnitsNet/CustomCode/Quantities/Mass.extra.cs b/UnitsNet/CustomCode/Quantities/Mass.extra.cs index c6e95535ba..36978514c0 100644 --- a/UnitsNet/CustomCode/Quantities/Mass.extra.cs +++ b/UnitsNet/CustomCode/Quantities/Mass.extra.cs @@ -50,7 +50,7 @@ public static Mass FromGravitationalForce(Force f) /// StonePounds related code makes it easier to work with Stone/Pound combination, which are customarily used in the UK /// to express body weight. For example, someone weighs 11 stone 4 pounds (about 72 kilograms). /// - private const double StoneToPounds = 14; + private const double StonesInOnePound = 14.0; /// /// Converts the mass to a customary stone/pounds combination. @@ -59,11 +59,12 @@ public StonePounds StonePounds { get { - double totalPounds = Pounds; - double wholeStone = Math.Floor(totalPounds/StoneToPounds); - double pounds = totalPounds%StoneToPounds; + var inPounds = Pounds; - return new StonePounds(wholeStone, pounds); + var stones = Math.Truncate(inPounds / StonesInOnePound); + var pounds = inPounds % StonesInOnePound; + + return new StonePounds(stones, pounds); } } @@ -72,7 +73,7 @@ public StonePounds StonePounds /// public static Mass FromStonePounds(double stone, double pounds) { - return FromPounds(StoneToPounds*stone + pounds); + return FromPounds(StonesInOnePound*stone + pounds); } // Windows Runtime Component does not allow operator overloads: https://msdn.microsoft.com/en-us/library/br230301.aspx @@ -130,9 +131,9 @@ public string ToString([CanBeNull] Culture cultureInfo) // Note that it isn't customary to use fractions - one wouldn't say "I am 11 stone and 4.5 pounds". // So pounds are rounded here. - UnitSystem unitSystem = UnitSystem.GetCached(cultureInfo); - string stoneUnit = unitSystem.GetDefaultAbbreviation(MassUnit.Stone); - string poundUnit = unitSystem.GetDefaultAbbreviation(MassUnit.Pound); + var unitSystem = UnitSystem.GetCached(cultureInfo); + var stoneUnit = unitSystem.GetDefaultAbbreviation(MassUnit.Stone); + var poundUnit = unitSystem.GetDefaultAbbreviation(MassUnit.Pound); return string.Format(unitSystem.Culture, "{0:n0} {1} {2:n0} {3}", Stone, stoneUnit, Math.Round(Pounds), poundUnit);