diff --git a/csharp/Lib/Units/Angle.cs b/csharp/Lib/Units/Angle.cs index 87a3ed2b4..b8972c826 100644 --- a/csharp/Lib/Units/Angle.cs +++ b/csharp/Lib/Units/Angle.cs @@ -4,7 +4,7 @@ using InnovEnergy.Lib.Utils; namespace InnovEnergy.Lib.Units; -[Generate] +[Sum] public readonly partial struct Angle { public static String Unit => "rad"; diff --git a/csharp/Lib/Units/Angle.generated.cs b/csharp/Lib/Units/Angle.generated.cs index 77f634fd3..ad576594a 100644 --- a/csharp/Lib/Units/Angle.generated.cs +++ b/csharp/Lib/Units/Angle.generated.cs @@ -1,4 +1,7 @@ #nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +#define Sum + +using static System.Math; namespace InnovEnergy.Lib.Units; @@ -16,10 +19,39 @@ public readonly partial struct Angle public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); // addition - + + #if Sum + public static T operator +(T left, T right) => new T(left.Value + right.Value); public static T operator -(T left, T right) => new T(left.Value - right.Value); public static T operator -(T t) => new T(-t.Value); + + #elif Mean + + public static T operator +(T left, T right) => new T((left.Value + right.Value)/2m); + + #elif Equal + + public static T operator +(T left, T right) + { + var d = Max(Abs(left.Value), Abs(right.Value)); + + if (d != 0m) + return new T(0m); + + var relativeError = Abs(left.Value - right.Value) / d; + + const Decimal maxRelativeError = 0.05m; + + if (relativeError > maxRelativeError) + throw new Exception($"{nameof(left)} and {nameof(right)} must be approximately equal.\n" + + $"Difference > {maxRelativeError * 100}% detected\n" + + $"{nameof(left)} : {left}\n" + + $"{nameof(right)}: {right}"); + + return new T((left.Value + right.Value) / 2m); + } + #endif // compare @@ -43,4 +75,4 @@ public readonly partial struct Angle public override Boolean Equals(Object? obj) => obj is T other && Equals(other); public override Int32 GetHashCode() => Value.GetHashCode(); -} \ No newline at end of file +} diff --git a/csharp/Lib/Units/ApparentPower.cs b/csharp/Lib/Units/ApparentPower.cs index b2a5bba6c..8c92385de 100644 --- a/csharp/Lib/Units/ApparentPower.cs +++ b/csharp/Lib/Units/ApparentPower.cs @@ -2,7 +2,7 @@ using InnovEnergy.Lib.Units.Generator; namespace InnovEnergy.Lib.Units; -[Generate] +[Sum] public readonly partial struct ApparentPower { public static String Unit => "VA"; diff --git a/csharp/Lib/Units/ApparentPower.generated.cs b/csharp/Lib/Units/ApparentPower.generated.cs index f413a8811..cfa6174ed 100644 --- a/csharp/Lib/Units/ApparentPower.generated.cs +++ b/csharp/Lib/Units/ApparentPower.generated.cs @@ -1,4 +1,7 @@ #nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +#define Sum + +using static System.Math; namespace InnovEnergy.Lib.Units; @@ -16,10 +19,39 @@ public readonly partial struct ApparentPower public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); // addition - + + #if Sum + public static T operator +(T left, T right) => new T(left.Value + right.Value); public static T operator -(T left, T right) => new T(left.Value - right.Value); public static T operator -(T t) => new T(-t.Value); + + #elif Mean + + public static T operator +(T left, T right) => new T((left.Value + right.Value)/2m); + + #elif Equal + + public static T operator +(T left, T right) + { + var d = Max(Abs(left.Value), Abs(right.Value)); + + if (d != 0m) + return new T(0m); + + var relativeError = Abs(left.Value - right.Value) / d; + + const Decimal maxRelativeError = 0.05m; + + if (relativeError > maxRelativeError) + throw new Exception($"{nameof(left)} and {nameof(right)} must be approximately equal.\n" + + $"Difference > {maxRelativeError * 100}% detected\n" + + $"{nameof(left)} : {left}\n" + + $"{nameof(right)}: {right}"); + + return new T((left.Value + right.Value) / 2m); + } + #endif // compare @@ -43,4 +75,4 @@ public readonly partial struct ApparentPower public override Boolean Equals(Object? obj) => obj is T other && Equals(other); public override Int32 GetHashCode() => Value.GetHashCode(); -} \ No newline at end of file +} diff --git a/csharp/Lib/Units/Composite/Ac1Phase.cs b/csharp/Lib/Units/Composite/Ac1Phase.cs index 00f823791..e48807866 100644 --- a/csharp/Lib/Units/Composite/Ac1Phase.cs +++ b/csharp/Lib/Units/Composite/Ac1Phase.cs @@ -1,10 +1,26 @@ +using System.Diagnostics.CodeAnalysis; + namespace InnovEnergy.Lib.Units.Composite; public record Ac1Phase ( - Voltage Voltage, - Current Current, - Angle Phi, + Voltage Voltage, + Current Current, + Angle Phi, Frequency Frequency -) : -AcPhase(Voltage, Current, Phi); \ No newline at end of file +) + : AcPhase(Voltage, Current, Phi) +{ + + [SuppressMessage("ReSharper", "RedundantCast")] + public static Ac1Phase operator +(Ac1Phase left, Ac1Phase right) + { + var f = (left.Frequency + right.Frequency) / 2m; // TODO: check that l & r approximately equal + var acPhase = (AcPhase)left + (AcPhase)right; + return new Ac1Phase(acPhase.Voltage, acPhase.Current, acPhase.Phi, f); + } + +} + + + diff --git a/csharp/Lib/Units/Composite/Ac3Phase.cs b/csharp/Lib/Units/Composite/Ac3Phase.cs index be4f7c73d..a5788e452 100644 --- a/csharp/Lib/Units/Composite/Ac3Phase.cs +++ b/csharp/Lib/Units/Composite/Ac3Phase.cs @@ -2,11 +2,24 @@ using static DecimalMath.DecimalEx; namespace InnovEnergy.Lib.Units.Composite; -public record Ac3Phase(AcPhase L1, AcPhase L2, AcPhase L3, Decimal Frequency) +public record Ac3Phase(AcPhase L1, AcPhase L2, AcPhase L3, Frequency Frequency) { public ApparentPower ApparentPower => L1.ApparentPower + L2.ApparentPower + L3.ApparentPower; public ReactivePower ReactivePower => L1.ReactivePower + L2.ReactivePower + L3.ReactivePower; public Power ActivePower => L1.ActivePower + L2.ActivePower + L3.ActivePower; public Angle Phi => ATan2(ReactivePower, ActivePower); + + + public static Ac3Phase operator +(Ac3Phase left, Ac3Phase right) + { + var f = (left.Frequency + right.Frequency) / 2m; // TODO: check that l & r approximately equal + + var l1 = left.L1 + right.L1; + var l2 = left.L2 + right.L2; + var l3 = left.L3 + right.L3; + + return new Ac3Phase(l1, l2, l3, f); + } + } \ No newline at end of file diff --git a/csharp/Lib/Units/Composite/AcPhase.cs b/csharp/Lib/Units/Composite/AcPhase.cs index f194f28af..70cd952b2 100644 --- a/csharp/Lib/Units/Composite/AcPhase.cs +++ b/csharp/Lib/Units/Composite/AcPhase.cs @@ -15,8 +15,40 @@ public record AcPhase : Phase public Angle Phi { get; } - public ApparentPower ApparentPower => Math.Abs(Voltage.Value * Current.Value) ; + public ApparentPower ApparentPower => Voltage.Value * Current.Value ; public Power ActivePower => ApparentPower.Value * PowerFactor; public ReactivePower ReactivePower => ApparentPower.Value * Sin(Phi); public Decimal PowerFactor => Cos(Phi); + + + public static AcPhase operator +(AcPhase left, AcPhase right) + { + // the Voltages of two phases are expected to be in phase and equal + + var v = (left.Voltage + right.Voltage) / 2m; // TODO: check that l & r approximately equal + + // currents (RMS) can be different and out of phase + // https://www.johndcook.com/blog/2020/08/17/adding-phase-shifted-sine-waves/ + + // IF + // left(t) = ILeft sin(ωt) + // right(t) = IRight sin(ωt + φ). + // sum(t) = left(t) + right(t) = ISum sin(ωt + ψ). + // THEN + + // ψ = arctan( IRight * sin(φ) / (ILeft + IRight cos(φ)) ). + // C = IRight * sin(φ) / sin(ψ). + + // in this calc left(t) has zero phase shift. + // we can shift both waves by -left.Phi, so + // φ := right.phi - left.phi + + + var phi = right.Phi - left.Phi; + + var phiSum = ATan2(right.Current * Sin(phi), left.Current + right.Current * Cos(phi)); + var iSum = right.Current * Sin(phi) / Sin(phiSum); + + return new AcPhase(v, iSum, phiSum); + } } \ No newline at end of file diff --git a/csharp/Lib/Units/Composite/DcPhase.cs b/csharp/Lib/Units/Composite/DcPhase.cs index 8e73313bf..af6d1049a 100644 --- a/csharp/Lib/Units/Composite/DcPhase.cs +++ b/csharp/Lib/Units/Composite/DcPhase.cs @@ -3,4 +3,13 @@ namespace InnovEnergy.Lib.Units.Composite; public record DcPhase(Voltage Voltage, Current Current) : Phase(Voltage, Current) { public Power Power => Current * Voltage; + + public static DcPhase operator +(DcPhase left, DcPhase right) + { + var v = (left.Voltage + right.Voltage) / 2m; + var i = left.Current + right.Current; + + return new DcPhase(v, i); + } + } \ No newline at end of file diff --git a/csharp/Lib/Units/Current.cs b/csharp/Lib/Units/Current.cs index d2d674d04..b3c36ee34 100644 --- a/csharp/Lib/Units/Current.cs +++ b/csharp/Lib/Units/Current.cs @@ -3,7 +3,7 @@ using InnovEnergy.Lib.Units.Generator; namespace InnovEnergy.Lib.Units; -[Generate] +[Sum] public readonly partial struct Current { public static String Unit => "A"; diff --git a/csharp/Lib/Units/Current.generated.cs b/csharp/Lib/Units/Current.generated.cs index bc1964810..cda7eeadf 100644 --- a/csharp/Lib/Units/Current.generated.cs +++ b/csharp/Lib/Units/Current.generated.cs @@ -1,4 +1,7 @@ #nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +#define Sum + +using static System.Math; namespace InnovEnergy.Lib.Units; @@ -16,10 +19,39 @@ public readonly partial struct Current public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); // addition - + + #if Sum + public static T operator +(T left, T right) => new T(left.Value + right.Value); public static T operator -(T left, T right) => new T(left.Value - right.Value); public static T operator -(T t) => new T(-t.Value); + + #elif Mean + + public static T operator +(T left, T right) => new T((left.Value + right.Value)/2m); + + #elif Equal + + public static T operator +(T left, T right) + { + var d = Max(Abs(left.Value), Abs(right.Value)); + + if (d != 0m) + return new T(0m); + + var relativeError = Abs(left.Value - right.Value) / d; + + const Decimal maxRelativeError = 0.05m; + + if (relativeError > maxRelativeError) + throw new Exception($"{nameof(left)} and {nameof(right)} must be approximately equal.\n" + + $"Difference > {maxRelativeError * 100}% detected\n" + + $"{nameof(left)} : {left}\n" + + $"{nameof(right)}: {right}"); + + return new T((left.Value + right.Value) / 2m); + } + #endif // compare @@ -43,4 +75,4 @@ public readonly partial struct Current public override Boolean Equals(Object? obj) => obj is T other && Equals(other); public override Int32 GetHashCode() => Value.GetHashCode(); -} \ No newline at end of file +} diff --git a/csharp/Lib/Units/Frequency.cs b/csharp/Lib/Units/Frequency.cs index 173f5037d..3041325c2 100644 --- a/csharp/Lib/Units/Frequency.cs +++ b/csharp/Lib/Units/Frequency.cs @@ -2,12 +2,17 @@ using InnovEnergy.Lib.Units.Generator; namespace InnovEnergy.Lib.Units; - -[Generate] +[Equal] public readonly partial struct Frequency { public static String Unit => "Hz"; public static String Symbol => "f"; - public Frequency(Decimal value) => Value = value; + public Frequency(Decimal value) + { + if (value < 0) + throw new ArgumentException(nameof(Frequency) + " cannot be negative", nameof(value)); + + Value = value; + } } \ No newline at end of file diff --git a/csharp/Lib/Units/Frequency.generated.cs b/csharp/Lib/Units/Frequency.generated.cs index 2959bdbc4..015d67536 100644 --- a/csharp/Lib/Units/Frequency.generated.cs +++ b/csharp/Lib/Units/Frequency.generated.cs @@ -1,4 +1,7 @@ #nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +#define Equal + +using static System.Math; namespace InnovEnergy.Lib.Units; @@ -16,10 +19,39 @@ public readonly partial struct Frequency public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); // addition - + + #if Sum + public static T operator +(T left, T right) => new T(left.Value + right.Value); public static T operator -(T left, T right) => new T(left.Value - right.Value); public static T operator -(T t) => new T(-t.Value); + + #elif Mean + + public static T operator +(T left, T right) => new T((left.Value + right.Value)/2m); + + #elif Equal + + public static T operator +(T left, T right) + { + var d = Max(Abs(left.Value), Abs(right.Value)); + + if (d != 0m) + return new T(0m); + + var relativeError = Abs(left.Value - right.Value) / d; + + const Decimal maxRelativeError = 0.05m; + + if (relativeError > maxRelativeError) + throw new Exception($"{nameof(left)} and {nameof(right)} must be approximately equal.\n" + + $"Difference > {maxRelativeError * 100}% detected\n" + + $"{nameof(left)} : {left}\n" + + $"{nameof(right)}: {right}"); + + return new T((left.Value + right.Value) / 2m); + } + #endif // compare @@ -43,4 +75,4 @@ public readonly partial struct Frequency public override Boolean Equals(Object? obj) => obj is T other && Equals(other); public override Int32 GetHashCode() => Value.GetHashCode(); -} \ No newline at end of file +} diff --git a/csharp/Lib/Units/Generator/GenerateAttribute.cs b/csharp/Lib/Units/Generator/EqualAttribute.cs similarity index 65% rename from csharp/Lib/Units/Generator/GenerateAttribute.cs rename to csharp/Lib/Units/Generator/EqualAttribute.cs index c6643d2d7..c0131044a 100644 --- a/csharp/Lib/Units/Generator/GenerateAttribute.cs +++ b/csharp/Lib/Units/Generator/EqualAttribute.cs @@ -1,5 +1,5 @@ namespace InnovEnergy.Lib.Units.Generator; [AttributeUsage(AttributeTargets.Struct)] -internal class GenerateAttribute: Attribute +internal class EqualAttribute: Attribute {} \ No newline at end of file diff --git a/csharp/Lib/Units/Generator/MeanAttribute.cs b/csharp/Lib/Units/Generator/MeanAttribute.cs new file mode 100644 index 000000000..161da8b0e --- /dev/null +++ b/csharp/Lib/Units/Generator/MeanAttribute.cs @@ -0,0 +1,5 @@ +namespace InnovEnergy.Lib.Units.Generator; + +[AttributeUsage(AttributeTargets.Struct)] +internal class MeanAttribute: Attribute +{} \ No newline at end of file diff --git a/csharp/Lib/Units/Generator/SumAttribute.cs b/csharp/Lib/Units/Generator/SumAttribute.cs new file mode 100644 index 000000000..c4af9a156 --- /dev/null +++ b/csharp/Lib/Units/Generator/SumAttribute.cs @@ -0,0 +1,5 @@ +namespace InnovEnergy.Lib.Units.Generator; + +[AttributeUsage(AttributeTargets.Struct)] +internal class SumAttribute: Attribute +{} \ No newline at end of file diff --git a/csharp/Lib/Units/Generator/Template.txt b/csharp/Lib/Units/Generator/Template.txt index 6055ace01..c656f51df 100644 --- a/csharp/Lib/Units/Generator/Template.txt +++ b/csharp/Lib/Units/Generator/Template.txt @@ -1,4 +1,7 @@ #nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +#define Type + +using static System.Math; namespace InnovEnergy.Lib.Units; @@ -16,10 +19,39 @@ public readonly partial struct Template public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); // addition - + + #if Sum + public static T operator +(T left, T right) => new T(left.Value + right.Value); public static T operator -(T left, T right) => new T(left.Value - right.Value); public static T operator -(T t) => new T(-t.Value); + + #elif Mean + + public static T operator +(T left, T right) => new T((left.Value + right.Value)/2m); + + #elif Equal + + public static T operator +(T left, T right) + { + var d = Max(Abs(left.Value), Abs(right.Value)); + + if (d != 0m) + return new T(0m); + + var relativeError = Abs(left.Value - right.Value) / d; + + const Decimal maxRelativeError = 0.05m; + + if (relativeError > maxRelativeError) + throw new Exception($"{nameof(left)} and {nameof(right)} must be approximately equal.\n" + + $"Difference > {maxRelativeError * 100}% detected\n" + + $"{nameof(left)} : {left}\n" + + $"{nameof(right)}: {right}"); + + return new T((left.Value + right.Value) / 2m); + } + #endif // compare diff --git a/csharp/Lib/Units/Generator/generate.sh b/csharp/Lib/Units/Generator/generate.sh index 01ff06f64..625f32f89 100755 --- a/csharp/Lib/Units/Generator/generate.sh +++ b/csharp/Lib/Units/Generator/generate.sh @@ -4,10 +4,12 @@ scriptDir=$( dirname -- "$0"; ) cd "$scriptDir/.." || exit -for file in $(grep -l '\[Generate\]' *.cs) +for match in $(grep -e '\[Sum\]\|\[Equal\]\|\[Mean\]' -o *.cs | tr -d '[]') do - filename=$(basename -- "$file") - class="${filename%.*}" - echo "generating $filename" - sed "s/Template/$class/g" "./Generator/Template.txt" > "./$class.generated.cs" + path="${match%:*}" + type="${match#*:}" + file=$(basename -- "$path") + class="${file%.*}" + echo "generating $file" + sed "s/Template/$class/g; s/Type/$type/" "./Generator/Template.txt" > "./$class.generated.cs" done \ No newline at end of file diff --git a/csharp/Lib/Units/Power.cs b/csharp/Lib/Units/Power.cs index 716336a5e..eaedbf7f2 100644 --- a/csharp/Lib/Units/Power.cs +++ b/csharp/Lib/Units/Power.cs @@ -3,7 +3,7 @@ using InnovEnergy.Lib.Units.Generator; namespace InnovEnergy.Lib.Units; -[Generate] +[Sum] public readonly partial struct Power { public static String Unit => "W"; diff --git a/csharp/Lib/Units/Power.generated.cs b/csharp/Lib/Units/Power.generated.cs index 3d4d12a65..c26ad26fd 100644 --- a/csharp/Lib/Units/Power.generated.cs +++ b/csharp/Lib/Units/Power.generated.cs @@ -1,10 +1,13 @@ #nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +#define Sum + +using static System.Math; namespace InnovEnergy.Lib.Units; -using T = ReactivePower; +using T = Power; -public readonly partial struct ReactivePower +public readonly partial struct Power { public Decimal Value { get; } public override String ToString() => Value + Unit; @@ -16,10 +19,39 @@ public readonly partial struct ReactivePower public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); // addition - + + #if Sum + public static T operator +(T left, T right) => new T(left.Value + right.Value); public static T operator -(T left, T right) => new T(left.Value - right.Value); public static T operator -(T t) => new T(-t.Value); + + #elif Mean + + public static T operator +(T left, T right) => new T((left.Value + right.Value)/2m); + + #elif Equal + + public static T operator +(T left, T right) + { + var d = Max(Abs(left.Value), Abs(right.Value)); + + if (d != 0m) + return new T(0m); + + var relativeError = Abs(left.Value - right.Value) / d; + + const Decimal maxRelativeError = 0.05m; + + if (relativeError > maxRelativeError) + throw new Exception($"{nameof(left)} and {nameof(right)} must be approximately equal.\n" + + $"Difference > {maxRelativeError * 100}% detected\n" + + $"{nameof(left)} : {left}\n" + + $"{nameof(right)}: {right}"); + + return new T((left.Value + right.Value) / 2m); + } + #endif // compare @@ -43,4 +75,4 @@ public readonly partial struct ReactivePower public override Boolean Equals(Object? obj) => obj is T other && Equals(other); public override Int32 GetHashCode() => Value.GetHashCode(); -} \ No newline at end of file +} diff --git a/csharp/Lib/Units/ReactivePower.cs b/csharp/Lib/Units/ReactivePower.cs index a7017cb32..30d7641b9 100644 --- a/csharp/Lib/Units/ReactivePower.cs +++ b/csharp/Lib/Units/ReactivePower.cs @@ -3,7 +3,7 @@ using InnovEnergy.Lib.Units.Generator; namespace InnovEnergy.Lib.Units; -[Generate] +[Sum] public readonly partial struct ReactivePower { public static String Unit => "var"; diff --git a/csharp/Lib/Units/ReactivePower.generated.cs b/csharp/Lib/Units/ReactivePower.generated.cs index 20a55cccc..9b8def505 100644 --- a/csharp/Lib/Units/ReactivePower.generated.cs +++ b/csharp/Lib/Units/ReactivePower.generated.cs @@ -1,10 +1,13 @@ #nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +#define Sum + +using static System.Math; namespace InnovEnergy.Lib.Units; -using T = Power; +using T = ReactivePower; -public readonly partial struct Power +public readonly partial struct ReactivePower { public Decimal Value { get; } public override String ToString() => Value + Unit; @@ -16,10 +19,39 @@ public readonly partial struct Power public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); // addition - + + #if Sum + public static T operator +(T left, T right) => new T(left.Value + right.Value); public static T operator -(T left, T right) => new T(left.Value - right.Value); public static T operator -(T t) => new T(-t.Value); + + #elif Mean + + public static T operator +(T left, T right) => new T((left.Value + right.Value)/2m); + + #elif Equal + + public static T operator +(T left, T right) + { + var d = Max(Abs(left.Value), Abs(right.Value)); + + if (d != 0m) + return new T(0m); + + var relativeError = Abs(left.Value - right.Value) / d; + + const Decimal maxRelativeError = 0.05m; + + if (relativeError > maxRelativeError) + throw new Exception($"{nameof(left)} and {nameof(right)} must be approximately equal.\n" + + $"Difference > {maxRelativeError * 100}% detected\n" + + $"{nameof(left)} : {left}\n" + + $"{nameof(right)}: {right}"); + + return new T((left.Value + right.Value) / 2m); + } + #endif // compare @@ -43,4 +75,4 @@ public readonly partial struct Power public override Boolean Equals(Object? obj) => obj is T other && Equals(other); public override Int32 GetHashCode() => Value.GetHashCode(); -} \ No newline at end of file +} diff --git a/csharp/Lib/Units/Resistance.cs b/csharp/Lib/Units/Resistance.cs index f31cd4a4b..ce426e229 100644 --- a/csharp/Lib/Units/Resistance.cs +++ b/csharp/Lib/Units/Resistance.cs @@ -2,7 +2,7 @@ using InnovEnergy.Lib.Units.Generator; namespace InnovEnergy.Lib.Units; -[Generate] +[Sum] public readonly partial struct Resistance { public static String Unit => "Ω"; @@ -13,7 +13,5 @@ public readonly partial struct Resistance // U=RI public static Voltage operator *(Resistance resistance, Current current) => new Voltage(resistance.Value * current.Value); - - } \ No newline at end of file diff --git a/csharp/Lib/Units/Resistance.generated.cs b/csharp/Lib/Units/Resistance.generated.cs index 9a715bf51..5be7685b6 100644 --- a/csharp/Lib/Units/Resistance.generated.cs +++ b/csharp/Lib/Units/Resistance.generated.cs @@ -1,4 +1,7 @@ #nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +#define Sum + +using static System.Math; namespace InnovEnergy.Lib.Units; @@ -16,10 +19,39 @@ public readonly partial struct Resistance public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); // addition - + + #if Sum + public static T operator +(T left, T right) => new T(left.Value + right.Value); public static T operator -(T left, T right) => new T(left.Value - right.Value); public static T operator -(T t) => new T(-t.Value); + + #elif Mean + + public static T operator +(T left, T right) => new T((left.Value + right.Value)/2m); + + #elif Equal + + public static T operator +(T left, T right) + { + var d = Max(Abs(left.Value), Abs(right.Value)); + + if (d != 0m) + return new T(0m); + + var relativeError = Abs(left.Value - right.Value) / d; + + const Decimal maxRelativeError = 0.05m; + + if (relativeError > maxRelativeError) + throw new Exception($"{nameof(left)} and {nameof(right)} must be approximately equal.\n" + + $"Difference > {maxRelativeError * 100}% detected\n" + + $"{nameof(left)} : {left}\n" + + $"{nameof(right)}: {right}"); + + return new T((left.Value + right.Value) / 2m); + } + #endif // compare @@ -43,4 +75,4 @@ public readonly partial struct Resistance public override Boolean Equals(Object? obj) => obj is T other && Equals(other); public override Int32 GetHashCode() => Value.GetHashCode(); -} \ No newline at end of file +} diff --git a/csharp/Lib/Units/Temperature.cs b/csharp/Lib/Units/Temperature.cs index 243487d7f..dc2d7e5ad 100644 --- a/csharp/Lib/Units/Temperature.cs +++ b/csharp/Lib/Units/Temperature.cs @@ -2,11 +2,15 @@ using InnovEnergy.Lib.Units.Generator; namespace InnovEnergy.Lib.Units; -[Generate] +using T=Temperature; + +[Mean] public readonly partial struct Temperature { public static String Unit => "°C"; public static String Symbol => "T"; public Temperature(Decimal value) => Value = value; + + } \ No newline at end of file diff --git a/csharp/Lib/Units/Temperature.generated.cs b/csharp/Lib/Units/Temperature.generated.cs index 1c87f4c31..edc3fdbfa 100644 --- a/csharp/Lib/Units/Temperature.generated.cs +++ b/csharp/Lib/Units/Temperature.generated.cs @@ -1,4 +1,7 @@ #nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +#define Mean + +using static System.Math; namespace InnovEnergy.Lib.Units; @@ -16,10 +19,39 @@ public readonly partial struct Temperature public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); // addition - + + #if Sum + public static T operator +(T left, T right) => new T(left.Value + right.Value); public static T operator -(T left, T right) => new T(left.Value - right.Value); public static T operator -(T t) => new T(-t.Value); + + #elif Mean + + public static T operator +(T left, T right) => new T((left.Value + right.Value)/2m); + + #elif Equal + + public static T operator +(T left, T right) + { + var d = Max(Abs(left.Value), Abs(right.Value)); + + if (d != 0m) + return new T(0m); + + var relativeError = Abs(left.Value - right.Value) / d; + + const Decimal maxRelativeError = 0.05m; + + if (relativeError > maxRelativeError) + throw new Exception($"{nameof(left)} and {nameof(right)} must be approximately equal.\n" + + $"Difference > {maxRelativeError * 100}% detected\n" + + $"{nameof(left)} : {left}\n" + + $"{nameof(right)}: {right}"); + + return new T((left.Value + right.Value) / 2m); + } + #endif // compare @@ -43,4 +75,4 @@ public readonly partial struct Temperature public override Boolean Equals(Object? obj) => obj is T other && Equals(other); public override Int32 GetHashCode() => Value.GetHashCode(); -} \ No newline at end of file +} diff --git a/csharp/Lib/Units/Voltage.cs b/csharp/Lib/Units/Voltage.cs index 5bbfc088f..2c65129e4 100644 --- a/csharp/Lib/Units/Voltage.cs +++ b/csharp/Lib/Units/Voltage.cs @@ -2,7 +2,7 @@ using InnovEnergy.Lib.Units.Generator; namespace InnovEnergy.Lib.Units; -[Generate] +[Equal] public readonly partial struct Voltage { public static String Unit => "V"; diff --git a/csharp/Lib/Units/Voltage.generated.cs b/csharp/Lib/Units/Voltage.generated.cs index d64264d60..07dc88d06 100644 --- a/csharp/Lib/Units/Voltage.generated.cs +++ b/csharp/Lib/Units/Voltage.generated.cs @@ -1,4 +1,7 @@ #nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. +#define Equal + +using static System.Math; namespace InnovEnergy.Lib.Units; @@ -16,10 +19,39 @@ public readonly partial struct Voltage public static T operator /(T t, Decimal scalar) => new T(t.Value / scalar); // addition - + + #if Sum + public static T operator +(T left, T right) => new T(left.Value + right.Value); public static T operator -(T left, T right) => new T(left.Value - right.Value); public static T operator -(T t) => new T(-t.Value); + + #elif Mean + + public static T operator +(T left, T right) => new T((left.Value + right.Value)/2m); + + #elif Equal + + public static T operator +(T left, T right) + { + var d = Max(Abs(left.Value), Abs(right.Value)); + + if (d != 0m) + return new T(0m); + + var relativeError = Abs(left.Value - right.Value) / d; + + const Decimal maxRelativeError = 0.05m; + + if (relativeError > maxRelativeError) + throw new Exception($"{nameof(left)} and {nameof(right)} must be approximately equal.\n" + + $"Difference > {maxRelativeError * 100}% detected\n" + + $"{nameof(left)} : {left}\n" + + $"{nameof(right)}: {right}"); + + return new T((left.Value + right.Value) / 2m); + } + #endif // compare @@ -43,4 +75,4 @@ public readonly partial struct Voltage public override Boolean Equals(Object? obj) => obj is T other && Equals(other); public override Int32 GetHashCode() => Value.GetHashCode(); -} \ No newline at end of file +}