1
0
mirror of https://github.com/chylex/Query.git synced 2025-07-19 15:04:33 +02:00
Query/Calculator/Math/Units.cs

157 lines
6.8 KiB
C#

using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Calculator.Parser;
using ExtendedNumerics;
namespace Calculator.Math;
[SuppressMessage("ReSharper", "ConvertToConstant.Local")]
[SuppressMessage("ReSharper", "HeapView.ObjectAllocation")]
static class Units {
public static UnitUniverse Time { get; } = TimeUniverse().Build();
public static UnitUniverse Length { get; } = LengthUniverse().Build();
public static UnitUniverse Mass { get; } = MassUniverse().Build();
public static UnitUniverse Area { get; } = AreaUniverse().Build();
public static UnitUniverse Volume { get; } = VolumeUniverse().Build();
public static UnitUniverse Angle { get; } = AngleUniverse().Build();
public static UnitUniverse Temperature { get; } = TemperatureUniverse().Build();
public static UnitUniverse InformationEntropy { get; } = InformationEntropyUniverse().Build();
public static UnitUniverses All { get; } = new (Time, Length, Mass, Area, Volume, Angle, Temperature, InformationEntropy);
private static UnitUniverse.Builder TimeUniverse() {
var minute = 60;
var hour = minute * 60;
var day = hour * 24;
var week = day * 7;
return new UnitUniverse.Builder("Time", new Unit("s", Pluralize("second")))
.AddUnit(new Unit("min", Pluralize("minute")), minute)
.AddUnit(new Unit("h", Pluralize("hour")), hour)
.AddUnit(new Unit("d", Pluralize("day")), day)
.AddUnit(new Unit("wk", Pluralize("week")), week);
}
private static UnitUniverse.Builder LengthUniverse() {
var inch = Parse("0", "0254");
var foot = inch * 12;
var yard = foot * 3;
var furlong = yard * 220;
var mile = yard * 1760;
var nauticalMile = 1_852;
var lightYear = 9_460_730_472_580_800;
return new UnitUniverse.Builder("Length", new Unit("m", Pluralize("meter", "metre")))
.AddSI()
.AddUnit(new Unit("in", [ "inch", "inches", "\"" ]), inch)
.AddUnit(new Unit("ft", [ "foot", "feet", "'" ]), foot)
.AddUnit(new Unit("yd", Pluralize("yard")), yard)
.AddUnit(new Unit("fur", Pluralize("furlong")), furlong)
.AddUnit(new Unit("mi", Pluralize("mile")), mile)
.AddUnit(new Unit("nmi", Pluralize("nautical mile")), nauticalMile)
.AddUnit(new Unit("ly", Pluralize("light-year", "light year")), lightYear);
}
private static UnitUniverse.Builder MassUniverse() {
var pound = Parse("453", "59237");
var stone = pound * 14;
var ounce = pound / 16;
var dram = ounce / 16;
return new UnitUniverse.Builder("Mass", new Unit("g", Pluralize("gram")))
.AddSI()
.AddUnit(new Unit("lb", [ "lbs", "pound", "pounds" ]), pound)
.AddUnit(new Unit("st", Pluralize("stone")), stone)
.AddUnit(new Unit("oz", Pluralize("ounce")), ounce)
.AddUnit(new Unit("dr", Pluralize("dram")), dram);
}
private static UnitUniverse.Builder AreaUniverse() {
static Unit SquareMeter(string shortPrefix, string longPrefix) {
return new Unit(shortPrefix + "m2", [
$"square {shortPrefix}m",
$"{shortPrefix}m square",
$"{shortPrefix}m squared",
$"{longPrefix}meter squared",
$"{longPrefix}meters squared",
$"{longPrefix}metre squared",
$"{longPrefix}metres squared",
..Pluralize($"square {longPrefix}meter", $"square {longPrefix}metre")
]);
}
return new UnitUniverse.Builder("Area", SquareMeter(string.Empty, string.Empty))
.AddSI(static si => SquareMeter(si.ShortPrefix, si.LongPrefix), static factor => factor * 2)
.AddUnit(new Unit("a", Pluralize("are")), amountInPrimaryUnit: 100)
.AddUnit(new Unit("ha", Pluralize("hectare")), amountInPrimaryUnit: 10_000);
}
private static UnitUniverse.Builder VolumeUniverse() {
static Unit CubicMeter(string shortPrefix, string longPrefix) {
return new Unit(shortPrefix + "m3", [
$"cubic {shortPrefix}m",
$"{shortPrefix}m cubed",
$"{longPrefix}meter cubed",
$"{longPrefix}meters cubed",
$"{longPrefix}metre cubed",
$"{longPrefix}metres cubed",
..Pluralize($"cubic {longPrefix}meter", $"cubic {longPrefix}metre")
]);
}
return new UnitUniverse.Builder("Volume", new Unit("l", Pluralize("litre", "liter")))
.AddSI()
.AddUnit(CubicMeter(string.Empty, string.Empty), amountInPrimaryUnit: 1000)
.AddSI(static si => CubicMeter(si.ShortPrefix, si.LongPrefix), static factor => (factor * 3) + 3);
}
private static UnitUniverse.Builder AngleUniverse() {
return new UnitUniverse.Builder("Angle", new Unit("deg", [ "°", "degree", "degrees" ]))
.AddUnit(new Unit("rad", Pluralize("radian")), new Number.Decimal((decimal) System.Math.PI / 180M))
.AddUnit(new Unit("grad", Pluralize("gradian", "grade", "gon")), Ratio(numerator: 9, denominator: 10));
}
private static BigRational KelvinOffset { get; } = Parse("273", "15");
private static UnitUniverse.Builder TemperatureUniverse() {
return new UnitUniverse.Builder("Temperature", new Unit("°C", [ "C", "Celsius", "celsius" ]))
.AddUnit(new Unit("°F", [ "F", "Fahrenheit", "fahrenheit" ]), static f => (f - 32) * Ratio(numerator: 5, denominator: 9), static c => c * Ratio(numerator: 9, denominator: 5) + 32)
.AddUnit(new Unit("K", [ "Kelvin", "kelvin" ]), static k => k - KelvinOffset, static c => c + KelvinOffset);
}
private static UnitUniverse.Builder InformationEntropyUniverse() {
var bit = Ratio(numerator: 1, denominator: 8);
var nibble = bit * 4;
return new UnitUniverse.Builder("Information Entropy", new Unit("B", Pluralize("byte")))
.AddSI()
.AddUnit(new Unit("b", Pluralize("bit")), bit)
.AddUnit(new Unit("nibbles", [ "nibble" ]), nibble)
.AddUnit(new Unit("KiB", Pluralize("kibibyte")), Pow(value: 1024, exponent: 1))
.AddUnit(new Unit("MiB", Pluralize("mebibyte")), Pow(value: 1024, exponent: 2))
.AddUnit(new Unit("GiB", Pluralize("gibibyte")), Pow(value: 1024, exponent: 3))
.AddUnit(new Unit("TiB", Pluralize("tebibyte")), Pow(value: 1024, exponent: 4))
.AddUnit(new Unit("PiB", Pluralize("pebibyte")), Pow(value: 1024, exponent: 5))
.AddUnit(new Unit("EiB", Pluralize("exbibyte")), Pow(value: 1024, exponent: 6))
.AddUnit(new Unit("ZiB", Pluralize("zebibyte")), Pow(value: 1024, exponent: 7))
.AddUnit(new Unit("YiB", Pluralize("yobibyte")), Pow(value: 1024, exponent: 8));
}
private static BigRational Parse(string integerPart, string fractionalPart) {
return Tokenizer.ParseNumber(integerPart, fractionalPart);
}
private static BigRational Ratio(long numerator, long denominator) {
return new BigRational(numerator, denominator);
}
private static BigRational Pow(int value, int exponent) {
return BigRational.Pow(value, exponent);
}
private static ImmutableArray<string> Pluralize(params string[] names) {
return [..names.SelectMany(static name => new [] { name, name + "s" })];
}
}