From ed09e80702e26c0909262c30567b38eb790dd8a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=A4gi?= Date: Thu, 21 Sep 2023 15:25:42 +0200 Subject: [PATCH 1/9] Show that units can be defined in terms of other units. --- quantities/ISystems.cs | 13 ++++++++ quantities/common/ITransform.cs | 1 + quantities/units/IDerived.cs | 30 +++++++++++++++++++ quantities/units/Si/Derived/Gram.cs | 5 ++-- quantities/units/Si/IMetricUnit.cs | 15 +++++----- quantities/units/Si/Metric/HorsePower.cs | 5 ++-- quantities/units/Si/Metric/Time.cs | 20 +++++-------- quantities/units/Si/Metric/Tonne.cs | 5 ++-- .../units/Si/Metric/UnitsOfInformation.cs | 2 ++ 9 files changed, 71 insertions(+), 25 deletions(-) create mode 100644 quantities/ISystems.cs create mode 100644 quantities/units/IDerived.cs diff --git a/quantities/ISystems.cs b/quantities/ISystems.cs new file mode 100644 index 00000000..e940a4c9 --- /dev/null +++ b/quantities/ISystems.cs @@ -0,0 +1,13 @@ +using Quantities.Units.Imperial; +using Quantities.Units.NonStandard; +using Quantities.Units.Si; + +namespace Quantities; + +public interface ISystems +{ + public TResult Si() where TInjectedUnit : ISiUnit, TConstraint; + public TResult Metric() where TInjectedUnit : IMetricUnit, TConstraint; + public TResult Imperial() where TInjectedUnit : IImperialUnit, TConstraint; + public TResult NonStandard() where TInjectedUnit : INoSystemUnit, TConstraint; +} diff --git a/quantities/common/ITransform.cs b/quantities/common/ITransform.cs index c853c591..9e75bf6b 100644 --- a/quantities/common/ITransform.cs +++ b/quantities/common/ITransform.cs @@ -2,5 +2,6 @@ public interface ITransform { + // ToDo: Make this method internal! static abstract Transformation ToSi(Transformation self); } diff --git a/quantities/units/IDerived.cs b/quantities/units/IDerived.cs new file mode 100644 index 00000000..f1709349 --- /dev/null +++ b/quantities/units/IDerived.cs @@ -0,0 +1,30 @@ +using Quantities.Dimensions; +using Quantities.Units.Imperial; +using Quantities.Units.NonStandard; +using Quantities.Units.Si; + +namespace Quantities.Units; + +public interface IDerived + where TDimension : IDimension +{ + static abstract Transformation Derived(in From from); +} + +public readonly ref struct From + where TDimension : IDimension +{ + private readonly Transformation transformation; + internal From(Transformation transformation) => this.transformation = transformation; + public Transformation Imperial() + where TUnit : IImperialUnit, TDimension => TUnit.ToSi(this.transformation); + + public Transformation Metric() + where TUnit : IMetricUnit, TDimension => TUnit.ToSi(this.transformation); + + public Transformation NonStandard() + where TUnit : INoSystemUnit, TDimension => TUnit.ToSi(this.transformation); + + public Transformation Si() + where TUnit : ISiUnit, TDimension => this.transformation; +} diff --git a/quantities/units/Si/Derived/Gram.cs b/quantities/units/Si/Derived/Gram.cs index c8c6920b..359fbeb2 100644 --- a/quantities/units/Si/Derived/Gram.cs +++ b/quantities/units/Si/Derived/Gram.cs @@ -1,9 +1,10 @@ using Quantities.Dimensions; -using Quantities.Prefixes; namespace Quantities.Units.Si.Derived; -public readonly struct Gram : IMetricUnit, IMass +public readonly struct Gram : IMetricUnit, IMass { + public static Transformation Derived(in From from) => from.Si() / 1000; public static String Representation => "g"; + } diff --git a/quantities/units/Si/IMetricUnit.cs b/quantities/units/Si/IMetricUnit.cs index 3eeb4607..f12ab2d8 100644 --- a/quantities/units/Si/IMetricUnit.cs +++ b/quantities/units/Si/IMetricUnit.cs @@ -1,4 +1,5 @@ -using Quantities.Prefixes; +using Quantities.Dimensions; +using Quantities.Prefixes; namespace Quantities.Units.Si; @@ -7,11 +8,11 @@ namespace Quantities.Units.Si; // SI units. /// public interface IMetricUnit : ITransform, IUnit +{ /* marker interface */ } + +public interface IMetricUnit : IDerived, IMetricUnit, IUnit + where TSelf : IMetricUnit, TDimension + where TDimension : IDimension { - static Transformation ITransform.ToSi(Transformation self) => self; -} -public interface IMetricUnit : IMetricUnit - where TPrefix : IMetricPrefix -{ - static Transformation ITransform.ToSi(Transformation self) => TPrefix.ToSi(self); + static Transformation ITransform.ToSi(Transformation self) => TSelf.Derived(new From(self)); } diff --git a/quantities/units/Si/Metric/HorsePower.cs b/quantities/units/Si/Metric/HorsePower.cs index e16a0e8a..72fd584c 100644 --- a/quantities/units/Si/Metric/HorsePower.cs +++ b/quantities/units/Si/Metric/HorsePower.cs @@ -1,10 +1,11 @@ using Quantities.Dimensions; +using Quantities.Units.Si.Derived; namespace Quantities.Units.Si.Metric; // See: https://en.wikipedia.org/wiki/Horsepower -public readonly struct HorsePower : IMetricUnit, IPower +public readonly struct HorsePower : IMetricUnit, IPower { - public static Transformation ToSi(Transformation self) => 75 * self * 9.80665; // ~735.49875 W in 1 hp + public static Transformation Derived(in From basis) => 75 * basis.Si() * 9.80665; public static String Representation => "hp"; } diff --git a/quantities/units/Si/Metric/Time.cs b/quantities/units/Si/Metric/Time.cs index 3774fbec..1fe7a6cf 100644 --- a/quantities/units/Si/Metric/Time.cs +++ b/quantities/units/Si/Metric/Time.cs @@ -2,27 +2,23 @@ namespace Quantities.Units.Si.Metric; -public readonly struct Minute : IMetricUnit, ITime +public readonly struct Minute : IMetricUnit, ITime { - internal const Double toSeconds = 60; // min -> s - public static Transformation ToSi(Transformation self) => self * toSeconds; + public static Transformation Derived(in From from) => 60 * from.Si(); public static String Representation => "m"; } -public readonly struct Hour : IMetricUnit, ITime +public readonly struct Hour : IMetricUnit, ITime { - internal const Double toSeconds = 60 * Minute.toSeconds; // Hour -> s - public static Transformation ToSi(Transformation self) => self * toSeconds; + public static Transformation Derived(in From from) => 60 * from.Metric(); public static String Representation => "h"; } -public readonly struct Day : IMetricUnit, ITime +public readonly struct Day : IMetricUnit, ITime { - internal const Double toSeconds = 24 * Hour.toSeconds; // Day -> s - public static Transformation ToSi(Transformation self) => self * toSeconds; + public static Transformation Derived(in From from) => 24 * from.Metric(); public static String Representation => "d"; } -public readonly struct Week : IMetricUnit, ITime +public readonly struct Week : IMetricUnit, ITime { - internal const Double toSeconds = 7 * Day.toSeconds; // Week -> s - public static Transformation ToSi(Transformation self) => self * toSeconds; + public static Transformation Derived(in From from) => 7 * from.Metric(); public static String Representation => "w"; } diff --git a/quantities/units/Si/Metric/Tonne.cs b/quantities/units/Si/Metric/Tonne.cs index 521f7d03..67ef8cbc 100644 --- a/quantities/units/Si/Metric/Tonne.cs +++ b/quantities/units/Si/Metric/Tonne.cs @@ -1,9 +1,10 @@ using Quantities.Dimensions; -using Quantities.Prefixes; namespace Quantities.Units.Si.Metric; -public readonly struct Tonne : IMetricUnit, IMass +public readonly struct Tonne : IMetricUnit, IMass { + public static Transformation Derived(in From from) => 1000 * from.Si(); public static String Representation => "t"; + } diff --git a/quantities/units/Si/Metric/UnitsOfInformation.cs b/quantities/units/Si/Metric/UnitsOfInformation.cs index fab3fb77..ff41e03c 100644 --- a/quantities/units/Si/Metric/UnitsOfInformation.cs +++ b/quantities/units/Si/Metric/UnitsOfInformation.cs @@ -9,7 +9,9 @@ This is what we'll use here... */ public readonly struct Bit : IMetricUnit, IAmountOfInformation { + public static Transformation ToSi(Transformation self) => self; public static String Representation => "bit"; + } public readonly struct Nibble : IMetricUnit, IAmountOfInformation { From 4b5322050adf376b94583753df39bdcabb3fa933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=A4gi?= Date: Thu, 21 Sep 2023 15:38:29 +0200 Subject: [PATCH 2/9] Apply to more metric units. --- quantities/units/Si/Derived/Celsius.cs | 5 ++--- quantities/units/Si/Metric/AstronomicalUnit.cs | 5 ++--- "quantities/units/Si/Metric/\303\205ngstr\303\266m.cs" | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/quantities/units/Si/Derived/Celsius.cs b/quantities/units/Si/Derived/Celsius.cs index e6e5c7dd..32ae076e 100644 --- a/quantities/units/Si/Derived/Celsius.cs +++ b/quantities/units/Si/Derived/Celsius.cs @@ -4,9 +4,8 @@ namespace Quantities.Units.Si.Derived; // [K] ≡ [°C] + 273.15 // Celsius is officially an SI derived unit. -public readonly struct Celsius : IMetricUnit, ITemperature +public readonly struct Celsius : IMetricUnit, ITemperature { - private const Double kelvinOffset = 273.15d; - public static Transformation ToSi(Transformation self) => self + kelvinOffset; + public static Transformation Derived(in From from) => from.Si() + 273.15d; public static String Representation => "°C"; } diff --git a/quantities/units/Si/Metric/AstronomicalUnit.cs b/quantities/units/Si/Metric/AstronomicalUnit.cs index 11f400d0..ad0ab140 100644 --- a/quantities/units/Si/Metric/AstronomicalUnit.cs +++ b/quantities/units/Si/Metric/AstronomicalUnit.cs @@ -3,9 +3,8 @@ namespace Quantities.Units.Si.Metric; // https://en.wikipedia.org/wiki/Astronomical_unit -public readonly struct AstronomicalUnit : IMetricUnit, ILength +public readonly struct AstronomicalUnit : IMetricUnit, ILength { - internal const Double astronomicalUnitToMetre = 149597870700; // au -> m - public static Transformation ToSi(Transformation self) => astronomicalUnitToMetre * self; + public static Transformation Derived(in From from) => 149597870700 * from.Si(); public static String Representation => "au"; } diff --git "a/quantities/units/Si/Metric/\303\205ngstr\303\266m.cs" "b/quantities/units/Si/Metric/\303\205ngstr\303\266m.cs" index 6ab1d2e9..291689e2 100644 --- "a/quantities/units/Si/Metric/\303\205ngstr\303\266m.cs" +++ "b/quantities/units/Si/Metric/\303\205ngstr\303\266m.cs" @@ -2,9 +2,8 @@ namespace Quantities.Units.Si.Metric; -public readonly struct Ångström : IMetricUnit, ILength +public readonly struct Ångström : IMetricUnit<Ångström, ILength>, ILength { - internal const Double metreToÅngström = 1e10; // m -> Å - public static Transformation ToSi(Transformation self) => self / metreToÅngström; + public static Transformation Derived(in From from) => from.Si() / 1e10; public static String Representation => "Å"; } From c20a0f96eded51fb9637e45ae68b5a43461c706c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=A4gi?= Date: Thu, 21 Sep 2023 18:14:26 +0200 Subject: [PATCH 3/9] Start applying recursive unit definitions on Imperial units --- quantities.test/AreaTest.cs | 2 +- quantities.test/prefixes/TestPrefix.cs | 1 - quantities/units/Imperial/IImperialUnit.cs | 11 ++++++++++- quantities/units/Imperial/Length/Chain.cs | 4 ++-- quantities/units/Imperial/Length/Foot.cs | 6 +++--- quantities/units/Imperial/Length/Furlong.cs | 4 ++-- quantities/units/Imperial/Length/Inch.cs | 6 +++--- quantities/units/Imperial/Length/Mile.cs | 4 ++-- quantities/units/Imperial/Length/Rod.cs | 4 ++-- quantities/units/Imperial/Length/Yard.cs | 4 ++-- quantities/units/Imperial/Volume/Gallon.cs | 3 ++- quantities/units/Si/IMetricUnit.cs | 7 +++---- 12 files changed, 32 insertions(+), 24 deletions(-) diff --git a/quantities.test/AreaTest.cs b/quantities.test/AreaTest.cs index ed4d11bc..b8c27561 100644 --- a/quantities.test/AreaTest.cs +++ b/quantities.test/AreaTest.cs @@ -34,7 +34,7 @@ public void SquareMetresToSquareKilometres() public void SquareMilesToSquareKilometres() { Area squareMiles = Area.Of(2).Square.Imperial(); - Area expected = Area.Of(2 * squareMileInSquareKilometres).Square.Si(); + Area expected = Area.Of(5.179976220672).Square.Si(); Area actual = squareMiles.To.Square.Si(); diff --git a/quantities.test/prefixes/TestPrefix.cs b/quantities.test/prefixes/TestPrefix.cs index 23d08ea9..8894d00f 100644 --- a/quantities.test/prefixes/TestPrefix.cs +++ b/quantities.test/prefixes/TestPrefix.cs @@ -17,6 +17,5 @@ public sealed class TestPrefix : ITestPrefix public TestPrefix(Double factor = Double.NaN) => Factor = Double.IsNaN(factor) ? prefix * 1d : factor; public Double ToSi(Double value) => prefix * value; public Double FromSi(Double value) => prefix / value; - public override String ToString() => TPrefix.Representation; } diff --git a/quantities/units/Imperial/IImperialUnit.cs b/quantities/units/Imperial/IImperialUnit.cs index 5460ea41..fef2fe08 100644 --- a/quantities/units/Imperial/IImperialUnit.cs +++ b/quantities/units/Imperial/IImperialUnit.cs @@ -1,3 +1,12 @@ -namespace Quantities.Units.Imperial; +using Quantities.Dimensions; + +namespace Quantities.Units.Imperial; public interface IImperialUnit : IUnit, ITransform { /* marker interface */ } + +public interface IImperialUnit : IDerived, IImperialUnit + where TSelf : IImperialUnit, TDimension, IImperialUnit + where TDimension : IDimension +{ + static Transformation ITransform.ToSi(Transformation self) => TSelf.Derived(new From(self)); +} diff --git a/quantities/units/Imperial/Length/Chain.cs b/quantities/units/Imperial/Length/Chain.cs index da76defb..717d7996 100644 --- a/quantities/units/Imperial/Length/Chain.cs +++ b/quantities/units/Imperial/Length/Chain.cs @@ -2,8 +2,8 @@ namespace Quantities.Units.Imperial.Length; -public readonly struct Chain : IImperialUnit, ILength +public readonly struct Chain : IImperialUnit, ILength { - public static Transformation ToSi(Transformation self) => 20.1168 * self; + public static Transformation Derived(in From from) => 22 * from.Imperial(); public static String Representation => "ch"; } diff --git a/quantities/units/Imperial/Length/Foot.cs b/quantities/units/Imperial/Length/Foot.cs index 80a59c7d..8176eab0 100644 --- a/quantities/units/Imperial/Length/Foot.cs +++ b/quantities/units/Imperial/Length/Foot.cs @@ -1,10 +1,10 @@ using Quantities.Dimensions; +using Quantities.Units.Si; namespace Quantities.Units.Imperial.Length; -public readonly struct Foot : IImperialUnit, ILength +public readonly struct Foot : IImperialUnit, ILength { - public const Double ToMetre = 0.3048; - public static Transformation ToSi(Transformation self) => ToMetre * self; + public static Transformation Derived(in From from) => 3048 * from.Si() / 10000; public static String Representation => "ft"; } diff --git a/quantities/units/Imperial/Length/Furlong.cs b/quantities/units/Imperial/Length/Furlong.cs index a1a36b4f..e5d0dec1 100644 --- a/quantities/units/Imperial/Length/Furlong.cs +++ b/quantities/units/Imperial/Length/Furlong.cs @@ -2,8 +2,8 @@ namespace Quantities.Units.Imperial.Length; -public readonly struct Furlong : IImperialUnit, ILength +public readonly struct Furlong : IImperialUnit, ILength { - public static Transformation ToSi(Transformation self) => 201.168 * self; + public static Transformation Derived(in From from) => from.Imperial() / 8; public static String Representation => "fur"; } diff --git a/quantities/units/Imperial/Length/Inch.cs b/quantities/units/Imperial/Length/Inch.cs index 3e34ce6b..33098443 100644 --- a/quantities/units/Imperial/Length/Inch.cs +++ b/quantities/units/Imperial/Length/Inch.cs @@ -2,9 +2,9 @@ namespace Quantities.Units.Imperial.Length; -public readonly struct Inch : IImperialUnit, ILength +public readonly struct Inch : IImperialUnit, ILength { - public const Double ToMetre = 0.0254; - public static Transformation ToSi(Transformation self) => ToMetre * self; + public const Double ToMetre = 0.0254; // ToDo: Remove! + public static Transformation Derived(in From from) => from.Imperial() / 12; public static String Representation => "in"; } diff --git a/quantities/units/Imperial/Length/Mile.cs b/quantities/units/Imperial/Length/Mile.cs index ae6b4d19..ea7ad748 100644 --- a/quantities/units/Imperial/Length/Mile.cs +++ b/quantities/units/Imperial/Length/Mile.cs @@ -2,8 +2,8 @@ namespace Quantities.Units.Imperial.Length; -public readonly struct Mile : IImperialUnit, ILength +public readonly struct Mile : IImperialUnit, ILength { - public static Transformation ToSi(Transformation self) => 1609.344 * self; + public static Transformation Derived(in From from) => 5280 * from.Imperial(); public static String Representation => "mi"; } diff --git a/quantities/units/Imperial/Length/Rod.cs b/quantities/units/Imperial/Length/Rod.cs index f6ed0b81..a4947b2d 100644 --- a/quantities/units/Imperial/Length/Rod.cs +++ b/quantities/units/Imperial/Length/Rod.cs @@ -4,8 +4,8 @@ namespace Quantities.Units.Imperial.Length; // https://en.wikipedia.org/wiki/Rod_(unit) // https://en.wikipedia.org/wiki/Imperial_units -public readonly struct Rod : IImperialUnit, ILength +public readonly struct Rod : IImperialUnit, ILength { - public static Transformation ToSi(Transformation self) => 5.0292 * self; + public static Transformation Derived(in From from) => 66 * from.Imperial() / 4; public static String Representation => "rod"; } diff --git a/quantities/units/Imperial/Length/Yard.cs b/quantities/units/Imperial/Length/Yard.cs index 6718f691..3562e4ae 100644 --- a/quantities/units/Imperial/Length/Yard.cs +++ b/quantities/units/Imperial/Length/Yard.cs @@ -2,8 +2,8 @@ namespace Quantities.Units.Imperial.Length; -public readonly struct Yard : IImperialUnit, ILength +public readonly struct Yard : IImperialUnit, ILength { - public static Transformation ToSi(Transformation self) => 0.9144 * self; + public static Transformation Derived(in From from) => 3 * from.Imperial(); public static String Representation => "yd"; } diff --git a/quantities/units/Imperial/Volume/Gallon.cs b/quantities/units/Imperial/Volume/Gallon.cs index fc866b3d..d7efbe2a 100644 --- a/quantities/units/Imperial/Volume/Gallon.cs +++ b/quantities/units/Imperial/Volume/Gallon.cs @@ -6,11 +6,12 @@ namespace Quantities.Units.Imperial.Volume; // https://en.wikipedia.org/wiki/Gallon public readonly struct Gallon : IImperialUnit, IVolume, IInjectUnit { + const Double footToMetre = 0.3048; internal const Double toCubicMetre = 4.54609e-3; // gal -> m³ public static Transformation ToSi(Transformation self) => 4.54609 * self / 1e3; static T IInjectUnit.Inject(in Creator inject, in Double self) { - const Double gallonToCubicFeet = toCubicMetre / (Foot.ToMetre * Foot.ToMetre * Foot.ToMetre); + const Double gallonToCubicFeet = toCubicMetre / (footToMetre * footToMetre * footToMetre); return inject.Imperial(gallonToCubicFeet * self); } public static String Representation => "gal"; diff --git a/quantities/units/Si/IMetricUnit.cs b/quantities/units/Si/IMetricUnit.cs index f12ab2d8..3b83a8c3 100644 --- a/quantities/units/Si/IMetricUnit.cs +++ b/quantities/units/Si/IMetricUnit.cs @@ -7,11 +7,10 @@ namespace Quantities.Units.Si; /// Metric units are accepted by the SI system, but are themselves not considered to be // SI units. /// -public interface IMetricUnit : ITransform, IUnit -{ /* marker interface */ } +public interface IMetricUnit : ITransform, IUnit { /* marker interface */ } -public interface IMetricUnit : IDerived, IMetricUnit, IUnit - where TSelf : IMetricUnit, TDimension +public interface IMetricUnit : IDerived, IMetricUnit + where TSelf : IMetricUnit, TDimension, IMetricUnit where TDimension : IDimension { static Transformation ITransform.ToSi(Transformation self) => TSelf.Derived(new From(self)); From e2ea543d339b0b351f6d6f116a18944e56e9e827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=A4gi?= Date: Fri, 22 Sep 2023 13:41:03 +0200 Subject: [PATCH 4/9] Improve accuracy of Polynomial by simplifying. --- quantities.benchmark/PolynomialBenchmark.cs | 24 ++++++++------- quantities/numerics/Algorithms.cs | 16 ++++++++++ quantities/numerics/Polynomial.cs | 33 +++++++++++---------- 3 files changed, 47 insertions(+), 26 deletions(-) create mode 100644 quantities/numerics/Algorithms.cs diff --git a/quantities.benchmark/PolynomialBenchmark.cs b/quantities.benchmark/PolynomialBenchmark.cs index 1d761aa2..e93741ec 100644 --- a/quantities.benchmark/PolynomialBenchmark.cs +++ b/quantities.benchmark/PolynomialBenchmark.cs @@ -11,27 +11,31 @@ public class PolynomialBenchmark private const Double offset = Math.Tau + Math.E; private const Double argument = 0.1321; private static readonly Polynomial polynomial = Poly(nominator: scale, denominator: Math.PI, offset: offset); + private static readonly Polynomial polynomialWithoutOffset = Poly(nominator: scale, denominator: Math.PI); [Benchmark(Baseline = true)] public Double EvaluateTrivial() => Trivial(argument); [Benchmark] public Double EvaluatePolynomial() => polynomial * argument; + [Benchmark] + public Double EvaluatePolynomialWithoutOffset() => polynomialWithoutOffset * argument; [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] private static Double Trivial(Double value) => scale * value / Math.PI + offset; } /* -// * Summary * -BenchmarkDotNet=v0.13.5, OS=arch +BenchmarkDotNet v0.13.8, Arch Linux Intel Core i7-8565U CPU 1.80GHz (Whiskey Lake), 1 CPU, 8 logical and 4 physical cores -.NET SDK=7.0.110 - [Host] : .NET 7.0.10 (7.0.1023.41001), X64 RyuJIT AVX2 - DefaultJob : .NET 7.0.10 (7.0.1023.41001), X64 RyuJIT AVX2 - -| Method | Mean | Error | StdDev | Ratio | RatioSD | -|------------------- |----------:|----------:|----------:|------:|--------:| -| EvaluateTrivial | 1.1944 ns | 0.0361 ns | 0.0320 ns | 1.00 | 0.00 | -| EvaluatePolynomial | 0.3643 ns | 0.0216 ns | 0.0180 ns | 0.31 | 0.02 | +.NET SDK 7.0.111 + [Host] : .NET 7.0.11 (7.0.1123.46301), X64 RyuJIT AVX2 + DefaultJob : .NET 7.0.11 (7.0.1123.46301), X64 RyuJIT AVX2 + + +| Method | Mean | Error | StdDev | Ratio | RatioSD | +|-------------------------------- |----------:|----------:|----------:|------:|--------:| +| EvaluateTrivial | 0.9766 ns | 0.0133 ns | 0.0117 ns | 1.00 | 0.00 | +| EvaluatePolynomial | 0.4931 ns | 0.0413 ns | 0.0442 ns | 0.52 | 0.04 | +| EvaluatePolynomialWithoutOffset | 0.4047 ns | 0.0076 ns | 0.0067 ns | 0.41 | 0.01 | */ diff --git a/quantities/numerics/Algorithms.cs b/quantities/numerics/Algorithms.cs new file mode 100644 index 00000000..b807ac67 --- /dev/null +++ b/quantities/numerics/Algorithms.cs @@ -0,0 +1,16 @@ +using System.Numerics; + +namespace Quantities.Numerics; + +internal static class Algorithms +{ + // Implements: https://en.wikipedia.org/wiki/Euclidean_algorithm + public static T Gcd(T a, T b) + where T : INumberBase, IModulusOperators + { + var big = T.MaxMagnitude(a, b); + var small = T.MinMagnitude(a, b); + return Impl(T.Abs(big), T.Abs(small)); + static T Impl(T max, T min) => T.IsZero(min) ? max : Impl(min, max % min); + } +} diff --git a/quantities/numerics/Polynomial.cs b/quantities/numerics/Polynomial.cs index 211818c1..d444a251 100644 --- a/quantities/numerics/Polynomial.cs +++ b/quantities/numerics/Polynomial.cs @@ -1,4 +1,5 @@ using System.Numerics; +using static Quantities.Numerics.Algorithms; namespace Quantities.Numerics; @@ -14,13 +15,21 @@ namespace Quantities.Numerics; public Polynomial() => (this.nominator, this.denominator, this.offset) = (1, 1, 0); private Polynomial(in Double nominator, in Double denominator, in Double offset) { - this.offset = offset; - (this.nominator, this.denominator) = denominator >= 0 ? (nominator, denominator) : (-nominator, -denominator); + (this.nominator, this.denominator, this.offset) = (nominator, denominator, offset); } public static Polynomial Of(Transformation transformation) { - var (nominator, denominator, offset) = transformation; - return new(in nominator, in denominator, in offset); + var (n, d, offset) = transformation; + (n, d) = Simplify(n, d); + return d >= 0 ? new(n, d, offset) : new(-n, -d, offset); + static (Double n, Double d) Simplify(Double n, Double d) + { + if (Double.IsInteger(n) && Double.IsInteger(d) && Double.Abs(Double.MaxMagnitude(n, d)) < Int64.MaxValue) { + Int64 gcd = Gcd((Int64)n, (Int64)d); + return gcd <= 1 ? (n, d) : (n / gcd, d / gcd); + } + return (n, d); + } } public static Polynomial Of() where TTransform : ITransform => Cache.Polynomial; @@ -32,24 +41,16 @@ public static Double Convert(in Double value) where TFrom : ITransform where TTo : ITransform => Converter.Polynomial * value; public static Double operator *(Polynomial left, Double right) - { - return Double.FusedMultiplyAdd(left.nominator, right, left.denominator * left.offset) / left.denominator; - } + => Double.FusedMultiplyAdd(left.nominator, right, left.denominator * left.offset) / left.denominator; public static Polynomial operator *(Polynomial left, Polynomial right) - { - return new(left.nominator * right.nominator, left.denominator * right.denominator, left * right.offset); - } + => new(left.nominator * right.nominator, left.denominator * right.denominator, left * right.offset); public static Polynomial operator /(Polynomial left, Polynomial right) - { - return new(left.nominator * right.denominator, left.denominator * right.nominator, right / left.offset); - } + => new(left.nominator * right.denominator, left.denominator * right.nominator, right / left.offset); public static Double operator /(Polynomial left, Double right) - { - return left.denominator * (right - left.offset) / left.nominator; - } + => left.denominator * (right - left.offset) / left.nominator; public override String ToString() { From 57f25401542ba2806a9726503962e535f4d26d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=A4gi?= Date: Fri, 22 Sep 2023 13:46:00 +0200 Subject: [PATCH 5/9] Chain binary prefix definitions. --- quantities/Extensions.cs | 1 + quantities/prefixes/BinaryPrefixes.cs | 37 +++++++++++++++------------ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/quantities/Extensions.cs b/quantities/Extensions.cs index 99d06bde..c7ab1fef 100644 --- a/quantities/Extensions.cs +++ b/quantities/Extensions.cs @@ -5,6 +5,7 @@ namespace Quantities; public static class Extensions { + internal static Transformation With(this Transformation self) where Transform : ITransform => Transform.ToSi(self); public static String ToString(this IFormattable formattable, String format) => formattable.ToString(format, CultureInfo.InvariantCulture); internal static Quantity To(this in Double value) where TMeasure : IMeasure diff --git a/quantities/prefixes/BinaryPrefixes.cs b/quantities/prefixes/BinaryPrefixes.cs index a22538dd..9bfa3fff 100644 --- a/quantities/prefixes/BinaryPrefixes.cs +++ b/quantities/prefixes/BinaryPrefixes.cs @@ -13,59 +13,64 @@ zebi Zi 1180591620717411303424 2^70 yobi Yi 1208925819614629174706176 2^80 */ +file static class Binary +{ + public const Int32 Base = 1024; +} + [DebuggerDisplay(nameof(Kibi))] public readonly struct Kibi : IBinaryPrefix, IScaleUp { - internal const Double Factor = 1024; - static Transformation ITransform.ToSi(Transformation self) => Factor * self; + internal const Double Factor = Binary.Base; + static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self; public static String Representation => "Ki"; } [DebuggerDisplay(nameof(Mebi))] public readonly struct Mebi : IBinaryPrefix, IScaleUp { - internal const Double Factor = 1048576; - static Transformation ITransform.ToSi(Transformation self) => Factor * self; + internal const Double Factor = Kibi.Factor * Kibi.Factor; + static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.With(); public static String Representation => "Mi"; } [DebuggerDisplay(nameof(Gibi))] public readonly struct Gibi : IBinaryPrefix, IScaleUp { - internal const Double Factor = 1073741824; - static Transformation ITransform.ToSi(Transformation self) => Factor * self; + internal const Double Factor = Kibi.Factor * Mebi.Factor; + static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.With(); public static String Representation => "Gi"; } [DebuggerDisplay(nameof(Tebi))] public readonly struct Tebi : IBinaryPrefix, IScaleUp { - internal const Double Factor = 1099511627776; - static Transformation ITransform.ToSi(Transformation self) => Factor * self; + internal const Double Factor = Mebi.Factor * Mebi.Factor; + static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.With(); public static String Representation => "Ti"; } [DebuggerDisplay(nameof(Pebi))] public readonly struct Pebi : IBinaryPrefix, IScaleUp { - internal const Double Factor = 1125899906842624; - static Transformation ITransform.ToSi(Transformation self) => Factor * self; + internal const Double Factor = Kibi.Factor * Tebi.Factor; + static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.With(); public static String Representation => "Pi"; } [DebuggerDisplay(nameof(Exbi))] public readonly struct Exbi : IBinaryPrefix, IScaleUp { - internal const Double Factor = 1152921504606846976; - static Transformation ITransform.ToSi(Transformation self) => Factor * self; + internal const Double Factor = Mebi.Factor * Tebi.Factor; + static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.With(); public static String Representation => "Ei"; } [DebuggerDisplay(nameof(Zebi))] public readonly struct Zebi : IBinaryPrefix, IScaleUp { - internal const Double Factor = Gibi.Factor * Tebi.Factor; // 1180591620717411303424 - static Transformation ITransform.ToSi(Transformation self) => Factor * self; + internal const Double Factor = Gibi.Factor * Tebi.Factor; + static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.With(); public static String Representation => "Zi"; } [DebuggerDisplay(nameof(Yobi))] public readonly struct Yobi : IBinaryPrefix, IScaleUp { - internal const Double Factor = Tebi.Factor * Tebi.Factor; // 1208925819614629174706176 - static Transformation ITransform.ToSi(Transformation self) => Factor * self; + internal const Double Factor = Tebi.Factor * Tebi.Factor; + static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.With(); public static String Representation => "Yi"; } From cb0acdb4cc5b46f81962340c9943696600396914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=A4gi?= Date: Sat, 23 Sep 2023 02:19:42 +0200 Subject: [PATCH 6/9] Simplify back to use of extension methods. --- quantities/Extensions.cs | 7 ++++- quantities/prefixes/BinaryPrefixes.cs | 14 ++++----- quantities/units/IDerived.cs | 30 ------------------- quantities/units/Imperial/IImperialUnit.cs | 11 +------ quantities/units/Imperial/Length/Chain.cs | 4 +-- quantities/units/Imperial/Length/Foot.cs | 4 +-- quantities/units/Imperial/Length/Furlong.cs | 4 +-- quantities/units/Imperial/Length/Inch.cs | 4 +-- quantities/units/Imperial/Length/Mile.cs | 4 +-- quantities/units/Imperial/Length/Rod.cs | 4 +-- quantities/units/Imperial/Length/Yard.cs | 4 +-- quantities/units/Si/Derived/Celsius.cs | 4 +-- quantities/units/Si/Derived/Gram.cs | 4 +-- quantities/units/Si/IMetricUnit.cs | 12 +------- .../units/Si/Metric/AstronomicalUnit.cs | 4 +-- quantities/units/Si/Metric/HorsePower.cs | 5 ++-- quantities/units/Si/Metric/Time.cs | 16 +++++----- quantities/units/Si/Metric/Tonne.cs | 4 +-- .../Si/Metric/\303\205ngstr\303\266m.cs" | 4 +-- 19 files changed, 49 insertions(+), 94 deletions(-) delete mode 100644 quantities/units/IDerived.cs diff --git a/quantities/Extensions.cs b/quantities/Extensions.cs index c7ab1fef..51b8ef35 100644 --- a/quantities/Extensions.cs +++ b/quantities/Extensions.cs @@ -1,11 +1,16 @@ using System.Globalization; using Quantities.Measures; +using Quantities.Prefixes; +using Quantities.Units; +using Quantities.Units.Si; namespace Quantities; public static class Extensions { - internal static Transformation With(this Transformation self) where Transform : ITransform => Transform.ToSi(self); + internal static Transformation RootedIn(this Transformation self) where TSi : ISiUnit => self; + internal static Transformation From(this Transformation self) where TBasis : IPrefix => TBasis.ToSi(self); + internal static Transformation DerivedFrom(this Transformation self) where TBasis : IUnit, ITransform => TBasis.ToSi(self); public static String ToString(this IFormattable formattable, String format) => formattable.ToString(format, CultureInfo.InvariantCulture); internal static Quantity To(this in Double value) where TMeasure : IMeasure diff --git a/quantities/prefixes/BinaryPrefixes.cs b/quantities/prefixes/BinaryPrefixes.cs index 9bfa3fff..3aa10c55 100644 --- a/quantities/prefixes/BinaryPrefixes.cs +++ b/quantities/prefixes/BinaryPrefixes.cs @@ -29,48 +29,48 @@ file static class Binary public readonly struct Mebi : IBinaryPrefix, IScaleUp { internal const Double Factor = Kibi.Factor * Kibi.Factor; - static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.With(); + static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.From(); public static String Representation => "Mi"; } [DebuggerDisplay(nameof(Gibi))] public readonly struct Gibi : IBinaryPrefix, IScaleUp { internal const Double Factor = Kibi.Factor * Mebi.Factor; - static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.With(); + static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.From(); public static String Representation => "Gi"; } [DebuggerDisplay(nameof(Tebi))] public readonly struct Tebi : IBinaryPrefix, IScaleUp { internal const Double Factor = Mebi.Factor * Mebi.Factor; - static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.With(); + static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.From(); public static String Representation => "Ti"; } [DebuggerDisplay(nameof(Pebi))] public readonly struct Pebi : IBinaryPrefix, IScaleUp { internal const Double Factor = Kibi.Factor * Tebi.Factor; - static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.With(); + static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.From(); public static String Representation => "Pi"; } [DebuggerDisplay(nameof(Exbi))] public readonly struct Exbi : IBinaryPrefix, IScaleUp { internal const Double Factor = Mebi.Factor * Tebi.Factor; - static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.With(); + static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.From(); public static String Representation => "Ei"; } [DebuggerDisplay(nameof(Zebi))] public readonly struct Zebi : IBinaryPrefix, IScaleUp { internal const Double Factor = Gibi.Factor * Tebi.Factor; - static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.With(); + static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.From(); public static String Representation => "Zi"; } [DebuggerDisplay(nameof(Yobi))] public readonly struct Yobi : IBinaryPrefix, IScaleUp { internal const Double Factor = Tebi.Factor * Tebi.Factor; - static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.With(); + static Transformation ITransform.ToSi(Transformation self) => Binary.Base * self.From(); public static String Representation => "Yi"; } diff --git a/quantities/units/IDerived.cs b/quantities/units/IDerived.cs deleted file mode 100644 index f1709349..00000000 --- a/quantities/units/IDerived.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Quantities.Dimensions; -using Quantities.Units.Imperial; -using Quantities.Units.NonStandard; -using Quantities.Units.Si; - -namespace Quantities.Units; - -public interface IDerived - where TDimension : IDimension -{ - static abstract Transformation Derived(in From from); -} - -public readonly ref struct From - where TDimension : IDimension -{ - private readonly Transformation transformation; - internal From(Transformation transformation) => this.transformation = transformation; - public Transformation Imperial() - where TUnit : IImperialUnit, TDimension => TUnit.ToSi(this.transformation); - - public Transformation Metric() - where TUnit : IMetricUnit, TDimension => TUnit.ToSi(this.transformation); - - public Transformation NonStandard() - where TUnit : INoSystemUnit, TDimension => TUnit.ToSi(this.transformation); - - public Transformation Si() - where TUnit : ISiUnit, TDimension => this.transformation; -} diff --git a/quantities/units/Imperial/IImperialUnit.cs b/quantities/units/Imperial/IImperialUnit.cs index fef2fe08..5460ea41 100644 --- a/quantities/units/Imperial/IImperialUnit.cs +++ b/quantities/units/Imperial/IImperialUnit.cs @@ -1,12 +1,3 @@ -using Quantities.Dimensions; - -namespace Quantities.Units.Imperial; +namespace Quantities.Units.Imperial; public interface IImperialUnit : IUnit, ITransform { /* marker interface */ } - -public interface IImperialUnit : IDerived, IImperialUnit - where TSelf : IImperialUnit, TDimension, IImperialUnit - where TDimension : IDimension -{ - static Transformation ITransform.ToSi(Transformation self) => TSelf.Derived(new From(self)); -} diff --git a/quantities/units/Imperial/Length/Chain.cs b/quantities/units/Imperial/Length/Chain.cs index 717d7996..69727491 100644 --- a/quantities/units/Imperial/Length/Chain.cs +++ b/quantities/units/Imperial/Length/Chain.cs @@ -2,8 +2,8 @@ namespace Quantities.Units.Imperial.Length; -public readonly struct Chain : IImperialUnit, ILength +public readonly struct Chain : IImperialUnit, ILength { - public static Transformation Derived(in From from) => 22 * from.Imperial(); + public static Transformation ToSi(Transformation self) => 22 * self.DerivedFrom(); public static String Representation => "ch"; } diff --git a/quantities/units/Imperial/Length/Foot.cs b/quantities/units/Imperial/Length/Foot.cs index 8176eab0..f4b7ce91 100644 --- a/quantities/units/Imperial/Length/Foot.cs +++ b/quantities/units/Imperial/Length/Foot.cs @@ -3,8 +3,8 @@ namespace Quantities.Units.Imperial.Length; -public readonly struct Foot : IImperialUnit, ILength +public readonly struct Foot : IImperialUnit, ILength { - public static Transformation Derived(in From from) => 3048 * from.Si() / 10000; + public static Transformation ToSi(Transformation self) => 3048 * self.RootedIn() / 1e4; public static String Representation => "ft"; } diff --git a/quantities/units/Imperial/Length/Furlong.cs b/quantities/units/Imperial/Length/Furlong.cs index e5d0dec1..4df4b77a 100644 --- a/quantities/units/Imperial/Length/Furlong.cs +++ b/quantities/units/Imperial/Length/Furlong.cs @@ -2,8 +2,8 @@ namespace Quantities.Units.Imperial.Length; -public readonly struct Furlong : IImperialUnit, ILength +public readonly struct Furlong : IImperialUnit, ILength { - public static Transformation Derived(in From from) => from.Imperial() / 8; + public static Transformation ToSi(Transformation self) => 22 * self.DerivedFrom() / 8; public static String Representation => "fur"; } diff --git a/quantities/units/Imperial/Length/Inch.cs b/quantities/units/Imperial/Length/Inch.cs index 33098443..b8d66193 100644 --- a/quantities/units/Imperial/Length/Inch.cs +++ b/quantities/units/Imperial/Length/Inch.cs @@ -2,9 +2,9 @@ namespace Quantities.Units.Imperial.Length; -public readonly struct Inch : IImperialUnit, ILength +public readonly struct Inch : IImperialUnit, ILength { public const Double ToMetre = 0.0254; // ToDo: Remove! - public static Transformation Derived(in From from) => from.Imperial() / 12; + public static Transformation ToSi(Transformation self) => self.DerivedFrom() / 12; public static String Representation => "in"; } diff --git a/quantities/units/Imperial/Length/Mile.cs b/quantities/units/Imperial/Length/Mile.cs index ea7ad748..29eafabe 100644 --- a/quantities/units/Imperial/Length/Mile.cs +++ b/quantities/units/Imperial/Length/Mile.cs @@ -2,8 +2,8 @@ namespace Quantities.Units.Imperial.Length; -public readonly struct Mile : IImperialUnit, ILength +public readonly struct Mile : IImperialUnit, ILength { - public static Transformation Derived(in From from) => 5280 * from.Imperial(); + public static Transformation ToSi(Transformation self) => 5280 * self.DerivedFrom(); public static String Representation => "mi"; } diff --git a/quantities/units/Imperial/Length/Rod.cs b/quantities/units/Imperial/Length/Rod.cs index a4947b2d..b7643e44 100644 --- a/quantities/units/Imperial/Length/Rod.cs +++ b/quantities/units/Imperial/Length/Rod.cs @@ -4,8 +4,8 @@ namespace Quantities.Units.Imperial.Length; // https://en.wikipedia.org/wiki/Rod_(unit) // https://en.wikipedia.org/wiki/Imperial_units -public readonly struct Rod : IImperialUnit, ILength +public readonly struct Rod : IImperialUnit, ILength { - public static Transformation Derived(in From from) => 66 * from.Imperial() / 4; + public static Transformation ToSi(Transformation self) => 66 * self.DerivedFrom() / 4; public static String Representation => "rod"; } diff --git a/quantities/units/Imperial/Length/Yard.cs b/quantities/units/Imperial/Length/Yard.cs index 3562e4ae..3810f446 100644 --- a/quantities/units/Imperial/Length/Yard.cs +++ b/quantities/units/Imperial/Length/Yard.cs @@ -2,8 +2,8 @@ namespace Quantities.Units.Imperial.Length; -public readonly struct Yard : IImperialUnit, ILength +public readonly struct Yard : IImperialUnit, ILength { - public static Transformation Derived(in From from) => 3 * from.Imperial(); + public static Transformation ToSi(Transformation self) => 3 * self.DerivedFrom(); public static String Representation => "yd"; } diff --git a/quantities/units/Si/Derived/Celsius.cs b/quantities/units/Si/Derived/Celsius.cs index 32ae076e..fc543e33 100644 --- a/quantities/units/Si/Derived/Celsius.cs +++ b/quantities/units/Si/Derived/Celsius.cs @@ -4,8 +4,8 @@ namespace Quantities.Units.Si.Derived; // [K] ≡ [°C] + 273.15 // Celsius is officially an SI derived unit. -public readonly struct Celsius : IMetricUnit, ITemperature +public readonly struct Celsius : IMetricUnit, ITemperature { - public static Transformation Derived(in From from) => from.Si() + 273.15d; + public static Transformation ToSi(Transformation self) => self.RootedIn() + 273.15d; public static String Representation => "°C"; } diff --git a/quantities/units/Si/Derived/Gram.cs b/quantities/units/Si/Derived/Gram.cs index 359fbeb2..5b20e722 100644 --- a/quantities/units/Si/Derived/Gram.cs +++ b/quantities/units/Si/Derived/Gram.cs @@ -2,9 +2,9 @@ namespace Quantities.Units.Si.Derived; -public readonly struct Gram : IMetricUnit, IMass +public readonly struct Gram : IMetricUnit, IMass { - public static Transformation Derived(in From from) => from.Si() / 1000; + public static Transformation ToSi(Transformation self) => self.RootedIn() / 1000; public static String Representation => "g"; } diff --git a/quantities/units/Si/IMetricUnit.cs b/quantities/units/Si/IMetricUnit.cs index 3b83a8c3..d823984b 100644 --- a/quantities/units/Si/IMetricUnit.cs +++ b/quantities/units/Si/IMetricUnit.cs @@ -1,17 +1,7 @@ -using Quantities.Dimensions; -using Quantities.Prefixes; - -namespace Quantities.Units.Si; +namespace Quantities.Units.Si; /// /// Metric units are accepted by the SI system, but are themselves not considered to be // SI units. /// public interface IMetricUnit : ITransform, IUnit { /* marker interface */ } - -public interface IMetricUnit : IDerived, IMetricUnit - where TSelf : IMetricUnit, TDimension, IMetricUnit - where TDimension : IDimension -{ - static Transformation ITransform.ToSi(Transformation self) => TSelf.Derived(new From(self)); -} diff --git a/quantities/units/Si/Metric/AstronomicalUnit.cs b/quantities/units/Si/Metric/AstronomicalUnit.cs index ad0ab140..b49206e4 100644 --- a/quantities/units/Si/Metric/AstronomicalUnit.cs +++ b/quantities/units/Si/Metric/AstronomicalUnit.cs @@ -3,8 +3,8 @@ namespace Quantities.Units.Si.Metric; // https://en.wikipedia.org/wiki/Astronomical_unit -public readonly struct AstronomicalUnit : IMetricUnit, ILength +public readonly struct AstronomicalUnit : IMetricUnit, ILength { - public static Transformation Derived(in From from) => 149597870700 * from.Si(); + public static Transformation ToSi(Transformation self) => 149597870700 * self.RootedIn(); public static String Representation => "au"; } diff --git a/quantities/units/Si/Metric/HorsePower.cs b/quantities/units/Si/Metric/HorsePower.cs index 72fd584c..4daf6de3 100644 --- a/quantities/units/Si/Metric/HorsePower.cs +++ b/quantities/units/Si/Metric/HorsePower.cs @@ -1,11 +1,10 @@ using Quantities.Dimensions; -using Quantities.Units.Si.Derived; namespace Quantities.Units.Si.Metric; // See: https://en.wikipedia.org/wiki/Horsepower -public readonly struct HorsePower : IMetricUnit, IPower +public readonly struct HorsePower : IMetricUnit, IPower { - public static Transformation Derived(in From basis) => 75 * basis.Si() * 9.80665; + public static Transformation ToSi(Transformation self) => 9.80665 * 75 * self.RootedIn(); public static String Representation => "hp"; } diff --git a/quantities/units/Si/Metric/Time.cs b/quantities/units/Si/Metric/Time.cs index 1fe7a6cf..f8f8886f 100644 --- a/quantities/units/Si/Metric/Time.cs +++ b/quantities/units/Si/Metric/Time.cs @@ -2,23 +2,23 @@ namespace Quantities.Units.Si.Metric; -public readonly struct Minute : IMetricUnit, ITime +public readonly struct Minute : IMetricUnit, ITime { - public static Transformation Derived(in From from) => 60 * from.Si(); + public static Transformation ToSi(Transformation self) => 60 * self.RootedIn(); public static String Representation => "m"; } -public readonly struct Hour : IMetricUnit, ITime +public readonly struct Hour : IMetricUnit, ITime { - public static Transformation Derived(in From from) => 60 * from.Metric(); + public static Transformation ToSi(Transformation self) => 60 * self.DerivedFrom(); public static String Representation => "h"; } -public readonly struct Day : IMetricUnit, ITime +public readonly struct Day : IMetricUnit, ITime { - public static Transformation Derived(in From from) => 24 * from.Metric(); + public static Transformation ToSi(Transformation self) => 24 * self.DerivedFrom(); public static String Representation => "d"; } -public readonly struct Week : IMetricUnit, ITime +public readonly struct Week : IMetricUnit, ITime { - public static Transformation Derived(in From from) => 7 * from.Metric(); + public static Transformation ToSi(Transformation self) => 7 * self.DerivedFrom(); public static String Representation => "w"; } diff --git a/quantities/units/Si/Metric/Tonne.cs b/quantities/units/Si/Metric/Tonne.cs index 67ef8cbc..be51d351 100644 --- a/quantities/units/Si/Metric/Tonne.cs +++ b/quantities/units/Si/Metric/Tonne.cs @@ -2,9 +2,9 @@ namespace Quantities.Units.Si.Metric; -public readonly struct Tonne : IMetricUnit, IMass +public readonly struct Tonne : IMetricUnit, IMass { - public static Transformation Derived(in From from) => 1000 * from.Si(); + public static Transformation ToSi(Transformation self) => 1000 * self.RootedIn(); public static String Representation => "t"; } diff --git "a/quantities/units/Si/Metric/\303\205ngstr\303\266m.cs" "b/quantities/units/Si/Metric/\303\205ngstr\303\266m.cs" index 291689e2..6bca75f1 100644 --- "a/quantities/units/Si/Metric/\303\205ngstr\303\266m.cs" +++ "b/quantities/units/Si/Metric/\303\205ngstr\303\266m.cs" @@ -2,8 +2,8 @@ namespace Quantities.Units.Si.Metric; -public readonly struct Ångström : IMetricUnit<Ångström, ILength>, ILength +public readonly struct Ångström : IMetricUnit, ILength { - public static Transformation Derived(in From from) => from.Si() / 1e10; + public static Transformation ToSi(Transformation self) => self.RootedIn() / 1e10; public static String Representation => "Å"; } From 8eefe160f85deef17b754ffad7b320ef0dba3d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=A4gi?= Date: Sat, 23 Sep 2023 03:39:00 +0200 Subject: [PATCH 7/9] Derive units from other units. --- quantities.test/Convenience.cs | 8 +++++++- quantities.test/VelocityTest.cs | 2 +- quantities/Extensions.cs | 2 ++ quantities/units/Imperial/Temperature/Farenheit.cs | 5 +++-- quantities/units/Imperial/Temperature/GasMark.cs | 2 +- quantities/units/Imperial/Temperature/Rankine.cs | 5 +++-- quantities/units/NonStandard/Length/LightYear.cs | 4 ++-- quantities/units/NonStandard/Length/NauticalMile.cs | 4 ++-- quantities/units/NonStandard/Mass/Pfund.cs | 4 ++-- quantities/units/NonStandard/Mass/Zentner.cs | 4 ++-- quantities/units/NonStandard/Temperature/Delisle.cs | 5 +++-- quantities/units/NonStandard/Temperature/Newton.cs | 5 +++-- .../units/NonStandard/Temperature/R\303\251aumur.cs" | 5 +++-- .../units/NonStandard/Temperature/R\303\270mer.cs" | 5 +++-- quantities/units/NonStandard/Velocity/Knot.cs | 10 +++++----- quantities/units/Si/Metric/UnitsOfInformation.cs | 6 ++---- 16 files changed, 44 insertions(+), 32 deletions(-) diff --git a/quantities.test/Convenience.cs b/quantities.test/Convenience.cs index 4508da36..e75b6835 100644 --- a/quantities.test/Convenience.cs +++ b/quantities.test/Convenience.cs @@ -27,7 +27,13 @@ public static void Matches(this TQuantity actual, TQuantity expected) public static void Matches(this TQuantity actual, TQuantity expected, Int32 precision) where TQuantity : struct, IQuantity, Dimensions.IDimension { - Equals(actual, expected, precision); + try { + Equals(actual, expected, precision); + } + catch (EqualException) { + const String roundTripSafe = "G17"; + throw new EqualException(expected.ToString(roundTripSafe), actual.ToString(roundTripSafe), precision, precision + 1); + } Assert.True(actual.Value.HasSameMeasure(expected.Value), $"Measure mismatch: {actual} != {expected}"); } public static void Equals(this T actual, T expected, Int32 precision) diff --git a/quantities.test/VelocityTest.cs b/quantities.test/VelocityTest.cs index 336dd0fe..543d8351 100644 --- a/quantities.test/VelocityTest.cs +++ b/quantities.test/VelocityTest.cs @@ -1,5 +1,5 @@ using Quantities.units.NonStandard.Length; -using Quantities.units.NonStandard.Velocity; +using Quantities.Units.NonStandard.Velocity; using Quantities.Units.Si.Metric; namespace Quantities.Test; diff --git a/quantities/Extensions.cs b/quantities/Extensions.cs index 51b8ef35..79ce7654 100644 --- a/quantities/Extensions.cs +++ b/quantities/Extensions.cs @@ -1,5 +1,6 @@ using System.Globalization; using Quantities.Measures; +using Quantities.Numerics; using Quantities.Prefixes; using Quantities.Units; using Quantities.Units.Si; @@ -8,6 +9,7 @@ namespace Quantities; public static class Extensions { + internal static Double ValueOf() where T : ITransform => Polynomial.Of() * 1d; internal static Transformation RootedIn(this Transformation self) where TSi : ISiUnit => self; internal static Transformation From(this Transformation self) where TBasis : IPrefix => TBasis.ToSi(self); internal static Transformation DerivedFrom(this Transformation self) where TBasis : IUnit, ITransform => TBasis.ToSi(self); diff --git a/quantities/units/Imperial/Temperature/Farenheit.cs b/quantities/units/Imperial/Temperature/Farenheit.cs index bb8a0add..f2cd0994 100644 --- a/quantities/units/Imperial/Temperature/Farenheit.cs +++ b/quantities/units/Imperial/Temperature/Farenheit.cs @@ -1,11 +1,12 @@ using Quantities.Dimensions; +using Quantities.Units.Si; namespace Quantities.Units.Imperial.Temperature; // [K] ≡ ([°F] + 459.67) × ​5⁄9 -// See: https://en.wikipedia.org/wiki/Conversion_of_units#Temperature +// See: https://en.wikipedia.org/wiki/Conversion_of_scales_of_temperature public readonly struct Fahrenheit : IImperialUnit, ITemperature { - public static Transformation ToSi(Transformation self) => 5 * (self + 459.67) / 9; + public static Transformation ToSi(Transformation self) => 5 * (self.RootedIn() + 459.67) / 9; public static String Representation => "°F"; } diff --git a/quantities/units/Imperial/Temperature/GasMark.cs b/quantities/units/Imperial/Temperature/GasMark.cs index f66af8d6..939f8ec3 100644 --- a/quantities/units/Imperial/Temperature/GasMark.cs +++ b/quantities/units/Imperial/Temperature/GasMark.cs @@ -3,7 +3,7 @@ namespace Quantities.Units.Imperial.Temperature; // [K] ≡ [GM] × ​125⁄9 + 394.261 -// See: https://en.wikipedia.org/wiki/Conversion_of_units#Temperature +// See: https://en.wikipedia.org/wiki/Gas_mark public readonly struct GasMark : IImperialUnit, ITemperature { public static Transformation ToSi(Transformation self) => self.FusedMultiplyAdd(125, 5d * 218d + 9 * 273.15d) / 9; diff --git a/quantities/units/Imperial/Temperature/Rankine.cs b/quantities/units/Imperial/Temperature/Rankine.cs index 6fc5ff99..29127671 100644 --- a/quantities/units/Imperial/Temperature/Rankine.cs +++ b/quantities/units/Imperial/Temperature/Rankine.cs @@ -1,11 +1,12 @@ using Quantities.Dimensions; +using Quantities.Units.Si; namespace Quantities.Units.Imperial.Temperature; // [K] ≡ [°R] × 5/9 -// See: https://en.wikipedia.org/wiki/Conversion_of_units#Temperature +// See: https://en.wikipedia.org/wiki/Conversion_of_scales_of_temperature public readonly struct Rankine : IImperialUnit, ITemperature { - public static Transformation ToSi(Transformation self) => 5d * self / 9d; + public static Transformation ToSi(Transformation self) => 5d * self.RootedIn() / 9d; public static String Representation => "°R"; } diff --git a/quantities/units/NonStandard/Length/LightYear.cs b/quantities/units/NonStandard/Length/LightYear.cs index 21db1710..ad17bb60 100644 --- a/quantities/units/NonStandard/Length/LightYear.cs +++ b/quantities/units/NonStandard/Length/LightYear.cs @@ -1,11 +1,11 @@ using Quantities.Dimensions; +using Quantities.Units.Si; namespace Quantities.Units.NonStandard.Length; // https://en.wikipedia.org/wiki/Light-year public readonly struct LightYear : INoSystemUnit, ILength { - internal const Double lightYearToMetre = 9460730472580800; // ly -> m - public static Transformation ToSi(Transformation self) => lightYearToMetre * self; + public static Transformation ToSi(Transformation self) => 9460730472580800 * self.RootedIn(); public static String Representation => "ly"; } diff --git a/quantities/units/NonStandard/Length/NauticalMile.cs b/quantities/units/NonStandard/Length/NauticalMile.cs index 35e9ff5d..30874ec0 100644 --- a/quantities/units/NonStandard/Length/NauticalMile.cs +++ b/quantities/units/NonStandard/Length/NauticalMile.cs @@ -1,12 +1,12 @@ using Quantities.Dimensions; using Quantities.Units.NonStandard; +using Quantities.Units.Si; namespace Quantities.units.NonStandard.Length; // https://en.wikipedia.org/wiki/Nautical_mile public readonly struct NauticalMile : INoSystemUnit, ILength { - private const Double oneNauticalMile = 1852; // m - public static Transformation ToSi(Transformation self) => oneNauticalMile * self; + public static Transformation ToSi(Transformation self) => 1852 * self.RootedIn(); public static String Representation => "nmi"; } diff --git a/quantities/units/NonStandard/Mass/Pfund.cs b/quantities/units/NonStandard/Mass/Pfund.cs index a7e174a1..45d47bcb 100644 --- a/quantities/units/NonStandard/Mass/Pfund.cs +++ b/quantities/units/NonStandard/Mass/Pfund.cs @@ -1,11 +1,11 @@ using Quantities.Dimensions; +using Quantities.Units.Si; namespace Quantities.Units.NonStandard.Mass; // https://de.wikipedia.org/wiki/Pfund public readonly struct Pfund : INoSystemUnit, IMass { - internal const Double toKilogram = 0.5; // ℔ -> Kg - public static Transformation ToSi(Transformation self) => toKilogram * self; + public static Transformation ToSi(Transformation self) => self.RootedIn() / 2; public static String Representation => "℔"; } diff --git a/quantities/units/NonStandard/Mass/Zentner.cs b/quantities/units/NonStandard/Mass/Zentner.cs index e0d8324b..9ba33094 100644 --- a/quantities/units/NonStandard/Mass/Zentner.cs +++ b/quantities/units/NonStandard/Mass/Zentner.cs @@ -1,11 +1,11 @@ using Quantities.Dimensions; +using Quantities.Units.Si; namespace Quantities.Units.NonStandard.Mass; // https://de.wikipedia.org/wiki/Zentner public readonly struct Zentner : INoSystemUnit, IMass { - internal const Double toKilogram = 50; // Ztr -> Kg - public static Transformation ToSi(Transformation self) => toKilogram * self; + public static Transformation ToSi(Transformation self) => 50 * self.RootedIn(); public static String Representation => "Ztr"; } diff --git a/quantities/units/NonStandard/Temperature/Delisle.cs b/quantities/units/NonStandard/Temperature/Delisle.cs index 99314fe5..ffe7cdc0 100644 --- a/quantities/units/NonStandard/Temperature/Delisle.cs +++ b/quantities/units/NonStandard/Temperature/Delisle.cs @@ -1,11 +1,12 @@ using Quantities.Dimensions; +using Quantities.Units.Si; namespace Quantities.Units.NonStandard.Temperature; // [K] = 373.15 − [°De] × ​2⁄3 -// See: https://en.wikipedia.org/wiki/Conversion_of_units#Temperature +// See: https://en.wikipedia.org/wiki/Conversion_of_scales_of_temperature public readonly struct Delisle : ITransform, INoSystemUnit, ITemperature { - public static Transformation ToSi(Transformation self) => -2d / 3 * self + 373.15; + public static Transformation ToSi(Transformation self) => -2d / 3d * self.RootedIn() + 373.15; public static String Representation => "°De"; } diff --git a/quantities/units/NonStandard/Temperature/Newton.cs b/quantities/units/NonStandard/Temperature/Newton.cs index 80c77c49..79077285 100644 --- a/quantities/units/NonStandard/Temperature/Newton.cs +++ b/quantities/units/NonStandard/Temperature/Newton.cs @@ -1,11 +1,12 @@ using Quantities.Dimensions; +using Quantities.Units.Si; namespace Quantities.Units.NonStandard.Temperature; // [K] = [°N] × ​100⁄33 + 273.15 -// See: https://en.wikipedia.org/wiki/Conversion_of_units#Temperature +// See: https://en.wikipedia.org/wiki/Conversion_of_scales_of_temperature public readonly struct Newton : INoSystemUnit, ITemperature { - public static Transformation ToSi(Transformation self) => 100d / 33d * self + 273.15; + public static Transformation ToSi(Transformation self) => 100d / 33 * self.RootedIn() + 273.15; public static String Representation => "°N"; } diff --git "a/quantities/units/NonStandard/Temperature/R\303\251aumur.cs" "b/quantities/units/NonStandard/Temperature/R\303\251aumur.cs" index 49f414a7..867cbf5f 100644 --- "a/quantities/units/NonStandard/Temperature/R\303\251aumur.cs" +++ "b/quantities/units/NonStandard/Temperature/R\303\251aumur.cs" @@ -1,11 +1,12 @@ using Quantities.Dimensions; +using Quantities.Units.Si; namespace Quantities.Units.NonStandard.Temperature; // [K] = [°Ré] × ​5⁄4 + 273.15 -// See: https://en.wikipedia.org/wiki/Conversion_of_units#Temperature +// See: https://en.wikipedia.org/wiki/Conversion_of_scales_of_temperature public readonly struct Réaumur : INoSystemUnit, ITemperature { - public static Transformation ToSi(Transformation self) => 5d * self / 4d + 273.15; + public static Transformation ToSi(Transformation self) => 5 * self.RootedIn() / 4 + 273.15; public static String Representation => "°Ré"; } diff --git "a/quantities/units/NonStandard/Temperature/R\303\270mer.cs" "b/quantities/units/NonStandard/Temperature/R\303\270mer.cs" index dc11b28e..d15f314b 100644 --- "a/quantities/units/NonStandard/Temperature/R\303\270mer.cs" +++ "b/quantities/units/NonStandard/Temperature/R\303\270mer.cs" @@ -1,11 +1,12 @@ using Quantities.Dimensions; +using Quantities.Units.Si; namespace Quantities.Units.NonStandard.Temperature; // [K] = ([°Rø] − 7.5) × ​40⁄21 + 273.15 -// See: https://en.wikipedia.org/wiki/Conversion_of_units#Temperature +// See: https://en.wikipedia.org/wiki/Conversion_of_scales_of_temperature public readonly struct Rømer : INoSystemUnit, ITemperature { - public static Transformation ToSi(Transformation self) => 40 * (self - 7.5) / 21 + 273.15; + public static Transformation ToSi(Transformation self) => 40 * (self.RootedIn() - 7.5) / 21 + 273.15; public static String Representation => "°Rø"; } diff --git a/quantities/units/NonStandard/Velocity/Knot.cs b/quantities/units/NonStandard/Velocity/Knot.cs index 30ecbfea..db0764bb 100644 --- a/quantities/units/NonStandard/Velocity/Knot.cs +++ b/quantities/units/NonStandard/Velocity/Knot.cs @@ -1,13 +1,13 @@ using Quantities.Dimensions; -using Quantities.Units.NonStandard; +using Quantities.units.NonStandard.Length; +using Quantities.Units.Si.Metric; +using static Quantities.Extensions; -namespace Quantities.units.NonStandard.Velocity; +namespace Quantities.Units.NonStandard.Velocity; // https://en.wikipedia.org/wiki/Knot_(unit) public readonly struct Knot : INoSystemUnit, IVelocity { - private const Double oneHour = 3600; // s - private const Double oneNauticalMile = 1852; // m - public static Transformation ToSi(Transformation self) => oneNauticalMile * self / oneHour; + public static Transformation ToSi(Transformation self) => self.DerivedFrom() / ValueOf(); public static String Representation => "kn"; } diff --git a/quantities/units/Si/Metric/UnitsOfInformation.cs b/quantities/units/Si/Metric/UnitsOfInformation.cs index ff41e03c..0c4fe74b 100644 --- a/quantities/units/Si/Metric/UnitsOfInformation.cs +++ b/quantities/units/Si/Metric/UnitsOfInformation.cs @@ -15,13 +15,11 @@ This is what we'll use here... } public readonly struct Nibble : IMetricUnit, IAmountOfInformation { - private const Double toBit = 4d; - public static Transformation ToSi(Transformation value) => value * toBit; + public static Transformation ToSi(Transformation self) => 4 * self.DerivedFrom(); public static String Representation => "N"; } public readonly struct Byte : IMetricUnit, IAmountOfInformation { - private const Double toBit = 8d; - public static Transformation ToSi(Transformation value) => value * toBit; + public static Transformation ToSi(Transformation self) => 8 * self.DerivedFrom(); public static String Representation => "B"; } From 3025b132e95816b82f5ed9062abf05c8e1a3be38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=A4gi?= Date: Sat, 23 Sep 2023 04:02:31 +0200 Subject: [PATCH 8/9] Pretty print equal messages. --- quantities.test/Convenience.cs | 25 +++++++++++++++++-------- quantities/Extensions.cs | 4 ++-- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/quantities.test/Convenience.cs b/quantities.test/Convenience.cs index e75b6835..caec55e8 100644 --- a/quantities.test/Convenience.cs +++ b/quantities.test/Convenience.cs @@ -4,6 +4,8 @@ using Quantities.Numerics; using Xunit.Sdk; +using static Quantities.Extensions; + namespace Quantities.Test; public static class Convenience { @@ -16,7 +18,7 @@ public static class Convenience public static String Join(String leftUnit, String rightUnit) => $"{leftUnit}\u200C{rightUnit}"; internal static void IsSameAs(this Quantity actual, Quantity expected, Int32 precision = fullPrecision) { - PrecisionIsBounded(expected, actual, precision); + ReformatEqualMessage((e, a, p) => PrecisionIsBounded(e, a, p), expected, actual, precision); Assert.True(actual.HasSameMeasure(in expected), $"Measure mismatch: {actual} != {expected}"); } public static void Matches(this TQuantity actual, TQuantity expected) @@ -27,13 +29,7 @@ public static void Matches(this TQuantity actual, TQuantity expected) public static void Matches(this TQuantity actual, TQuantity expected, Int32 precision) where TQuantity : struct, IQuantity, Dimensions.IDimension { - try { - Equals(actual, expected, precision); - } - catch (EqualException) { - const String roundTripSafe = "G17"; - throw new EqualException(expected.ToString(roundTripSafe), actual.ToString(roundTripSafe), precision, precision + 1); - } + ReformatEqualMessage((e, a, p) => a.Equals(e, p), expected, actual, precision); Assert.True(actual.Value.HasSameMeasure(expected.Value), $"Measure mismatch: {actual} != {expected}"); } public static void Equals(this T actual, T expected, Int32 precision) @@ -77,4 +73,17 @@ internal static Polynomial Poly(in Double nominator = 1, in Double denominator = var value = new Transformation(); return Polynomial.Of(nominator * value / denominator + offset); } + + private static void ReformatEqualMessage(Action assertion, T expected, T actual, Int32 precision) + where T : IFormattable + { + try { + assertion(expected, actual, precision); + } + catch (EqualException) { + var actualValue = actual.ToString(RoundTripFormat); + var expectedValue = expected.ToString(RoundTripFormat); + throw new EqualException(expectedValue, actualValue, precision, precision + 1); + } + } } diff --git a/quantities/Extensions.cs b/quantities/Extensions.cs index 79ce7654..0b1a2537 100644 --- a/quantities/Extensions.cs +++ b/quantities/Extensions.cs @@ -9,14 +9,14 @@ namespace Quantities; public static class Extensions { + internal static String RoundTripFormat = "G17"; // https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings#RFormatString internal static Double ValueOf() where T : ITransform => Polynomial.Of() * 1d; internal static Transformation RootedIn(this Transformation self) where TSi : ISiUnit => self; internal static Transformation From(this Transformation self) where TBasis : IPrefix => TBasis.ToSi(self); internal static Transformation DerivedFrom(this Transformation self) where TBasis : IUnit, ITransform => TBasis.ToSi(self); public static String ToString(this IFormattable formattable, String format) => formattable.ToString(format, CultureInfo.InvariantCulture); internal static Quantity To(this in Double value) - where TMeasure : IMeasure - => Quantity.Of(in value); + where TMeasure : IMeasure => Quantity.Of(in value); public static void Serialize(this IQuantity quantity, IWriter writer) where TQuantity : struct, IQuantity, Dimensions.IDimension { From 781b91926bb88078ea01c0fbb4cf357a1079416f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=A4gi?= Date: Sat, 23 Sep 2023 06:55:52 +0200 Subject: [PATCH 9/9] Fix minor things --- quantities/Extensions.cs | 2 +- quantities/common/ITransform.cs | 1 - quantities/units/Imperial/Length/Furlong.cs | 2 +- quantities/units/Imperial/Volume/Gallon.cs | 5 +++-- quantities/units/NonStandard/Temperature/Delisle.cs | 2 +- quantities/units/Si/Metric/UnitsOfInformation.cs | 3 ++- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/quantities/Extensions.cs b/quantities/Extensions.cs index 0b1a2537..544c9bca 100644 --- a/quantities/Extensions.cs +++ b/quantities/Extensions.cs @@ -10,7 +10,7 @@ namespace Quantities; public static class Extensions { internal static String RoundTripFormat = "G17"; // https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings#RFormatString - internal static Double ValueOf() where T : ITransform => Polynomial.Of() * 1d; + internal static Double ValueOf(Int32 exponent = 1) where T : ITransform => Math.Pow(Polynomial.Of() * 1d, exponent); internal static Transformation RootedIn(this Transformation self) where TSi : ISiUnit => self; internal static Transformation From(this Transformation self) where TBasis : IPrefix => TBasis.ToSi(self); internal static Transformation DerivedFrom(this Transformation self) where TBasis : IUnit, ITransform => TBasis.ToSi(self); diff --git a/quantities/common/ITransform.cs b/quantities/common/ITransform.cs index 9e75bf6b..c853c591 100644 --- a/quantities/common/ITransform.cs +++ b/quantities/common/ITransform.cs @@ -2,6 +2,5 @@ public interface ITransform { - // ToDo: Make this method internal! static abstract Transformation ToSi(Transformation self); } diff --git a/quantities/units/Imperial/Length/Furlong.cs b/quantities/units/Imperial/Length/Furlong.cs index 4df4b77a..7f7d75bc 100644 --- a/quantities/units/Imperial/Length/Furlong.cs +++ b/quantities/units/Imperial/Length/Furlong.cs @@ -4,6 +4,6 @@ namespace Quantities.Units.Imperial.Length; public readonly struct Furlong : IImperialUnit, ILength { - public static Transformation ToSi(Transformation self) => 22 * self.DerivedFrom() / 8; + public static Transformation ToSi(Transformation self) => self.DerivedFrom() / 8; public static String Representation => "fur"; } diff --git a/quantities/units/Imperial/Volume/Gallon.cs b/quantities/units/Imperial/Volume/Gallon.cs index d7efbe2a..edddc35f 100644 --- a/quantities/units/Imperial/Volume/Gallon.cs +++ b/quantities/units/Imperial/Volume/Gallon.cs @@ -1,17 +1,18 @@ using Quantities.Dimensions; using Quantities.Units.Imperial.Length; +using static Quantities.Extensions; + namespace Quantities.Units.Imperial.Volume; // https://en.wikipedia.org/wiki/Gallon public readonly struct Gallon : IImperialUnit, IVolume, IInjectUnit { - const Double footToMetre = 0.3048; internal const Double toCubicMetre = 4.54609e-3; // gal -> m³ + private static readonly Double gallonToCubicFeet = toCubicMetre / ValueOf(exponent: 3); public static Transformation ToSi(Transformation self) => 4.54609 * self / 1e3; static T IInjectUnit.Inject(in Creator inject, in Double self) { - const Double gallonToCubicFeet = toCubicMetre / (footToMetre * footToMetre * footToMetre); return inject.Imperial(gallonToCubicFeet * self); } public static String Representation => "gal"; diff --git a/quantities/units/NonStandard/Temperature/Delisle.cs b/quantities/units/NonStandard/Temperature/Delisle.cs index ffe7cdc0..0048f79e 100644 --- a/quantities/units/NonStandard/Temperature/Delisle.cs +++ b/quantities/units/NonStandard/Temperature/Delisle.cs @@ -7,6 +7,6 @@ namespace Quantities.Units.NonStandard.Temperature; // See: https://en.wikipedia.org/wiki/Conversion_of_scales_of_temperature public readonly struct Delisle : ITransform, INoSystemUnit, ITemperature { - public static Transformation ToSi(Transformation self) => -2d / 3d * self.RootedIn() + 373.15; + public static Transformation ToSi(Transformation self) => -2d / 3 * self.RootedIn() + 373.15; public static String Representation => "°De"; } diff --git a/quantities/units/Si/Metric/UnitsOfInformation.cs b/quantities/units/Si/Metric/UnitsOfInformation.cs index 0c4fe74b..347d5590 100644 --- a/quantities/units/Si/Metric/UnitsOfInformation.cs +++ b/quantities/units/Si/Metric/UnitsOfInformation.cs @@ -11,13 +11,14 @@ This is what we'll use here... { public static Transformation ToSi(Transformation self) => self; public static String Representation => "bit"; - } + public readonly struct Nibble : IMetricUnit, IAmountOfInformation { public static Transformation ToSi(Transformation self) => 4 * self.DerivedFrom(); public static String Representation => "N"; } + public readonly struct Byte : IMetricUnit, IAmountOfInformation { public static Transformation ToSi(Transformation self) => 8 * self.DerivedFrom();