Round Units to 3 significant digits by default (ToString). Add JsonConverters to generator

This commit is contained in:
ig 2023-03-02 17:15:10 +01:00
parent 19188fa430
commit 8ae9119858
22 changed files with 256 additions and 103 deletions

View File

@ -6,6 +6,6 @@ public static class Utils
{
public static Decimal Round3(this Decimal d)
{
return DecimalUtils.RoundToSignificantFigures(d, 3);
return DecimalUtils.RoundToSignificantDigits(d, 3);
}
}

View File

@ -2,6 +2,9 @@
#define Sum
using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Angle;
public readonly partial struct Angle
{
public Decimal Value { get; }
public override String ToString() => Value + Unit;
public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Angle
public override Int32 GetHashCode() => Value.GetHashCode();
}
internal class AngleConverter : JsonConverter<Angle>
{
public override Angle Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Angle(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Angle value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -2,6 +2,9 @@
#define Sum
using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = ApparentPower;
public readonly partial struct ApparentPower
{
public Decimal Value { get; }
public override String ToString() => Value + Unit;
public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct ApparentPower
public override Int32 GetHashCode() => Value.GetHashCode();
}
internal class ApparentPowerConverter : JsonConverter<ApparentPower>
{
public override ApparentPower Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new ApparentPower(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, ApparentPower value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -2,6 +2,9 @@
#define Sum
using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Current;
public readonly partial struct Current
{
public Decimal Value { get; }
public override String ToString() => Value + Unit;
public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Current
public override Int32 GetHashCode() => Value.GetHashCode();
}
internal class CurrentConverter : JsonConverter<Current>
{
public override Current Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Current(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Current value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -2,6 +2,9 @@
#define Equal
using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Frequency;
public readonly partial struct Frequency
{
public Decimal Value { get; }
public override String ToString() => Value + Unit;
public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Frequency
public override Int32 GetHashCode() => Value.GetHashCode();
}
internal class FrequencyConverter : JsonConverter<Frequency>
{
public override Frequency Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Frequency(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Frequency value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -1,7 +1,10 @@
#nullable enable // Auto-generated code requires an explicit '#nullable' directive in source.
#define Type
#define AggregationType
using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Template;
public readonly partial struct Template
{
public Decimal Value { get; }
public override String ToString() => Value + Unit;
public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Template
public override Int32 GetHashCode() => Value.GetHashCode();
}
internal class TemplateConverter : JsonConverter<Template>
{
public override Template Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Template(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Template value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -11,5 +11,5 @@ do
file=$(basename -- "$path")
class="${file%.*}"
echo "generating $file"
sed "s/Template/$class/g; s/Type/$type/" "./Generator/Template.txt" > "./$class.generated.cs"
sed "s/Template/$class/g; s/AggregationType/$type/g" "./Generator/Template.txt" > "./$class.generated.cs"
done

View File

@ -1,17 +0,0 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace InnovEnergy.Lib.Units.Json;
public class CurrentConverter : JsonConverter<Current>
{
public override Current Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Current(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Current value, JsonSerializerOptions options)
{
writer.WriteNumberValue(value.Value);
}
}

View File

@ -1,17 +0,0 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace InnovEnergy.Lib.Units.Json;
public class PowerConverter : JsonConverter<Power>
{
public override Power Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Power(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Power value, JsonSerializerOptions options)
{
writer.WriteNumberValue(value.Value);
}
}

View File

@ -1,17 +0,0 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace InnovEnergy.Lib.Units.Json;
public class ResistanceConverter : JsonConverter<Current>
{
public override Current Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Current(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Current value, JsonSerializerOptions options)
{
writer.WriteNumberValue(value.Value);
}
}

View File

@ -1,17 +0,0 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace InnovEnergy.Lib.Units.Json;
public class VoltageConverter : JsonConverter<Voltage>
{
public override Voltage Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Voltage(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Voltage value, JsonSerializerOptions options)
{
writer.WriteNumberValue(value.Value);
}
}

View File

@ -2,6 +2,9 @@
#define Sum
using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Number;
public readonly partial struct Number
{
public Decimal Value { get; }
public override String ToString() => Value + Unit;
public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Number
public override Int32 GetHashCode() => Value.GetHashCode();
}
internal class NumberConverter : JsonConverter<Number>
{
public override Number Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Number(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Number value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -10,7 +10,6 @@ public readonly partial struct Power
public static String Symbol => "P";
public Power(Decimal value) => Value = value;
// P=UI
public static Voltage operator /(Power power, Current current) => new Voltage(power.Value / current.Value);

View File

@ -2,6 +2,9 @@
#define Sum
using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Power;
public readonly partial struct Power
{
public Decimal Value { get; }
public override String ToString() => Value + Unit;
public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Power
public override Int32 GetHashCode() => Value.GetHashCode();
}
internal class PowerConverter : JsonConverter<Power>
{
public override Power Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Power(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Power value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -2,6 +2,9 @@
#define Sum
using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = ReactivePower;
public readonly partial struct ReactivePower
{
public Decimal Value { get; }
public override String ToString() => Value + Unit;
public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct ReactivePower
public override Int32 GetHashCode() => Value.GetHashCode();
}
internal class ReactivePowerConverter : JsonConverter<ReactivePower>
{
public override ReactivePower Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new ReactivePower(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, ReactivePower value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -2,6 +2,9 @@
#define Sum
using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Resistance;
public readonly partial struct Resistance
{
public Decimal Value { get; }
public override String ToString() => Value + Unit;
public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Resistance
public override Int32 GetHashCode() => Value.GetHashCode();
}
internal class ResistanceConverter : JsonConverter<Resistance>
{
public override Resistance Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Resistance(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Resistance value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -22,8 +22,8 @@ public readonly struct State : IReadOnlyList<String>
public static implicit operator State(Boolean s) => new(s.ToString());
public static implicit operator State(List<String> s) => new((IReadOnlyList<String>)s);
public static implicit operator State(String[] s) => new((IReadOnlyList<String>)s);
public static implicit operator State(List<Enum> es) => new(es.Select(e => e.ToString()).ToArray());
public static implicit operator State(Enum[] es) => new(es.Select(e => e.ToString()).ToArray());
public static implicit operator State(List<Enum> es) => new(es.Select(e => e.ToString()).ToList());
public static implicit operator State(Enum[] es) => new(es.Select(e => e.ToString()).ToList());
public static State operator |(State left, State right) => new(left, right);

View File

@ -2,6 +2,9 @@
#define Mean
using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Temperature;
public readonly partial struct Temperature
{
public Decimal Value { get; }
public override String ToString() => Value + Unit;
public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Temperature
public override Int32 GetHashCode() => Value.GetHashCode();
}
internal class TemperatureConverter : JsonConverter<Temperature>
{
public override Temperature Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Temperature(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Temperature value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -1,10 +1,27 @@
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Units.Json;
namespace InnovEnergy.Lib.Units;
public static class Units
{
static Units()
{
JsonConverters = typeof(Units)
.Assembly
.GetTypes()
.Where(t => t.IsAssignableTo(typeof(JsonConverter)))
.Select(Activator.CreateInstance)
.Cast<JsonConverter>()
.ToArray();
}
public static IReadOnlyList<JsonConverter> JsonConverters { get; }
public static Byte DisplaySignificantDigits { get; set; } = 3;
public static Byte JsonSignificantDigits { get; set; } = 3;
public const Decimal MaxRelativeError = 0.05m; // 5%
public static Current A (this Decimal value) => new Current(value);
@ -16,14 +33,6 @@ public static class Units
public static Frequency Hz (this Decimal value) => new Frequency(value);
public static Angle Rad (this Decimal value) => new Angle(value);
public static Temperature Celsius(this Decimal value) => new Temperature(value);
public static readonly IReadOnlyList<JsonConverter> JsonConverters = new JsonConverter[]
{
new CurrentConverter(),
new VoltageConverter(),
new PowerConverter(),
new ResistanceConverter(),
// TODO
};
}

View File

@ -2,6 +2,9 @@
#define Equal
using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Voltage;
public readonly partial struct Voltage
{
public Decimal Value { get; }
public override String ToString() => Value + Unit;
public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Voltage
public override Int32 GetHashCode() => Value.GetHashCode();
}
internal class VoltageConverter : JsonConverter<Voltage>
{
public override Voltage Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Voltage(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Voltage value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -1,32 +1,36 @@
using DecimalMath;
using static System.Math;
using static DecimalMath.DecimalEx;
namespace InnovEnergy.Lib.Utils;
public static class DecimalUtils
{
public static Double RoundToSignificantFigures(this Double num, Int32 n)
public static Double RoundToSignificantDigits(this Double num, Int32 n)
{
if (num == 0)
return 0;
var d = Math.Ceiling(Math.Log10(num < 0 ? -num : num));
var d = Ceiling(Log10(num < 0 ? -num : num));
var power = n - (Int32)d;
var magnitude = Math.Pow(10, power);
var shifted = Math.Round(num * magnitude);
var shifted = Round(num * magnitude);
return shifted / magnitude;
}
public static Decimal RoundToSignificantFigures(this Decimal num, Int32 n)
public static Decimal RoundToSignificantDigits(this Decimal num, Int32 n)
{
if (num == 0)
return 0;
var d = Math.Ceiling(DecimalEx.Log10(num < 0 ? -num : num));
var d = Ceiling(Log10(num < 0 ? -num : num));
var power = n - (Int32)d;
var magnitude = DecimalEx.Pow(10, power);
var shifted = Math.Round(num * magnitude);
var shifted = Round(num * magnitude);
return shifted / magnitude;
}
}

View File

@ -106,7 +106,7 @@ public static class EnumerableUtils
public static IEnumerable<T> NullableToEnumerable<T>(this T? t)
{
if (t is not null)
yield return t!;
yield return t;
}
public static IEnumerable<(T left, T right)> Pairwise<T>(this IEnumerable<T> ts)
@ -246,7 +246,7 @@ public static class EnumerableUtils
public static IEnumerable<T> Generate<T>(this T seed, Func<T, T> next)
{
var value = seed;
while (true)
while (value is not null)
{
yield return value;
value = next(value);