/// <summary> /// Divides the right unit from the left unit: <paramref name="Left"/>/<paramref name="Right"/>. /// </summary> /// <param name="Left">Left unit.</param> /// <param name="Right">Right unit.</param> /// <param name="ResidueExponent">Any residual exponent resulting from the division.</param> /// <returns>Resulting unit.</returns> public static Unit Divide(Unit Left, Unit Right, out int ResidueExponent) { LinkedList <KeyValuePair <AtomicUnit, int> > Result = new LinkedList <KeyValuePair <AtomicUnit, int> >(); int LeftExponent = Prefixes.PrefixToExponent(Left.prefix); int RightExponent = Prefixes.PrefixToExponent(Right.prefix); int ResultExponent = LeftExponent - RightExponent; Prefix ResultPrefix = Prefixes.ExponentToPrefix(ResultExponent, out ResidueExponent); LinkedListNode <KeyValuePair <AtomicUnit, int> > Loop; string Name; int Exponent; bool Found; foreach (KeyValuePair <AtomicUnit, int> Factor in Left.factors) { Result.AddLast(Factor); } foreach (KeyValuePair <AtomicUnit, int> Factor in Right.factors) { Name = Factor.Key.Name; Loop = Result.First; Found = false; while (!(Loop is null) && !Found) { if (Loop.Value.Key.Name == Name) { Found = true; Exponent = Loop.Value.Value - Factor.Value; if (Exponent == 0) { Result.Remove(Loop); } else { Loop.Value = new KeyValuePair <AtomicUnit, int>(Loop.Value.Key, Exponent); } } else { Loop = Loop.Next; } } if (Found) { continue; } Result.AddLast(new KeyValuePair <AtomicUnit, int>(Factor.Key, -Factor.Value)); } return(new Unit(ResultPrefix, Result)); }
/// <summary> /// Inverts the unit. /// </summary> /// <param name="ResidueExponent">Any exponential residue. If this value is 0, it means the exponent corresponds exactly /// to the returned prefix.</param> /// <returns>Inverted unit.</returns> public Unit Invert(out int ResidueExponent) { int Exponent = Prefixes.PrefixToExponent(this.prefix); LinkedList <KeyValuePair <AtomicUnit, int> > Factors = new LinkedList <KeyValuePair <AtomicUnit, int> >(); foreach (KeyValuePair <AtomicUnit, int> Factor in this.factors) { Factors.AddLast(new KeyValuePair <AtomicUnit, int>(Factor.Key, -Factor.Value)); } return(new Unit(Prefixes.ExponentToPrefix(-Exponent, out ResidueExponent), Factors)); }
/// <summary> /// Tries to convert a magnitude in one unit to a magnitude in another. /// </summary> /// <param name="From">Original magnitude.</param> /// <param name="FromUnit">Original unit.</param> /// <param name="ToUnit">Desired unit.</param> /// <param name="To">Converted magnitude.</param> /// <returns>If conversion was successful.</returns> public static bool TryConvert(double From, Unit FromUnit, Unit ToUnit, out double To) { if (FromUnit.Equals(ToUnit)) { To = From; return(true); } FromUnit = FromUnit.ToReferenceUnits(ref From); To = From; ToUnit = ToUnit.FromReferenceUnits(ref To); Unit Div = Unit.Divide(FromUnit, ToUnit, out int Exponent); Exponent += Prefixes.PrefixToExponent(Div.prefix); if (Exponent != 0) { To *= Math.Pow(10, Exponent); } return(!Div.HasFactors); }
/// <summary> /// Converts the unit to a series of reference unit factors. (Unrecognized units will be assumed to be reference units.) /// </summary> /// <param name="Magnitude">Reference magnitude.</param> /// <returns>Unit consisting of reference unit factors.</returns> public Unit FromReferenceUnits(ref double Magnitude) { if (this.hasReferenceUnits) { return(this); } lock (synchObject) { if (baseUnits is null) { Search(); } bool HasNonReference = false; foreach (KeyValuePair <AtomicUnit, int> Factor in this.factors) { if (!referenceUnits.ContainsKey(Factor.Key.Name)) { HasNonReference = true; break; } } if (HasNonReference) { LinkedList <KeyValuePair <AtomicUnit, int> > ReferenceFactors = new LinkedList <KeyValuePair <AtomicUnit, int> >(); int Exponent = Prefixes.PrefixToExponent(this.prefix); int FactorExponent; string Name; foreach (KeyValuePair <AtomicUnit, int> Factor in this.factors) { FactorExponent = Factor.Value; if (referenceUnits.ContainsKey(Name = Factor.Key.Name)) { this.Add(ReferenceFactors, Factor.Key, Factor.Value); } else if (baseUnits.TryGetValue(Name, out IBaseQuantity BaseQuantity)) { if (BaseQuantity.FromReferenceUnit(ref Magnitude, Name, FactorExponent)) { this.Add(ReferenceFactors, BaseQuantity.ReferenceUnit, FactorExponent); } else { this.Add(ReferenceFactors, Factor.Key, Factor.Value); } } else if (derivedUnits.TryGetValue(Name, out PhysicalQuantity Quantity)) { Magnitude *= Math.Pow(Quantity.Magnitude, FactorExponent); Exponent += Prefixes.PrefixToExponent(Quantity.Unit.prefix) * FactorExponent; foreach (KeyValuePair <AtomicUnit, int> Segment in Quantity.Unit.factors) { if (referenceUnits.ContainsKey(Name = Segment.Key.Name)) { this.Add(ReferenceFactors, Segment.Key, Segment.Value * FactorExponent); } else if (baseUnits.TryGetValue(Name, out BaseQuantity)) { if (BaseQuantity.FromReferenceUnit(ref Magnitude, Name, Segment.Value * FactorExponent)) { this.Add(ReferenceFactors, BaseQuantity.ReferenceUnit, Segment.Value * FactorExponent); } else { this.Add(ReferenceFactors, Segment.Key, Segment.Value * FactorExponent); } } else { this.Add(ReferenceFactors, Segment.Key, Segment.Value * FactorExponent); } } } else if (compoundUnits.TryGetValue(Name, out KeyValuePair <AtomicUnit, int>[] Units)) { foreach (KeyValuePair <AtomicUnit, int> Segment in Units) { if (referenceUnits.ContainsKey(Name = Segment.Key.Name)) { this.Add(ReferenceFactors, Segment.Key, Segment.Value * FactorExponent); } else if (baseUnits.TryGetValue(Name, out BaseQuantity)) { if (BaseQuantity.FromReferenceUnit(ref Magnitude, Name, Segment.Value * FactorExponent)) { this.Add(ReferenceFactors, BaseQuantity.ReferenceUnit, Segment.Value * FactorExponent); } else { this.Add(ReferenceFactors, Segment.Key, Segment.Value * FactorExponent); } } else { this.Add(ReferenceFactors, Segment.Key, Segment.Value * FactorExponent); } } } else { this.Add(ReferenceFactors, Factor.Key, Factor.Value); } } Unit Result = new Unit(Prefixes.ExponentToPrefix(Exponent, out FactorExponent), ReferenceFactors); if (FactorExponent != 0) { Magnitude *= Math.Pow(10, FactorExponent); } Result.hasBaseUnits = true; Result.hasReferenceUnits = true; return(Result); } else { this.hasBaseUnits = true; this.hasReferenceUnits = true; return(this); } } }
/// <summary> /// Converts the unit to a string. /// </summary> /// <param name="IncludePrefix">If the prefix should be included in the string or not.</param> public string ToString(bool IncludePrefix) { StringBuilder Numerator = null; StringBuilder Denominator = null; int NrDenominators = 0; foreach (KeyValuePair <AtomicUnit, int> Factor in this.factors) { if (Factor.Value > 0) { if (Numerator is null) { if (IncludePrefix) { Numerator = new StringBuilder(Prefixes.ToString(this.prefix)); } else { Numerator = new StringBuilder(); } } else { Numerator.Append('⋅'); } Numerator.Append(Factor.Key.Name); if (Factor.Value > 1) { if (Factor.Value == 2) { Numerator.Append('²'); } else if (Factor.Value == 3) { Numerator.Append('³'); } else { Numerator.Append('^'); Numerator.Append(Factor.Value.ToString()); } } } else { if (Denominator is null) { Denominator = new StringBuilder(); } else { Denominator.Append('⋅'); } NrDenominators++; Denominator.Append(Factor.Key.Name); if (Factor.Value < -1) { if (Factor.Value == -2) { Denominator.Append('²'); } else if (Factor.Value == -3) { Denominator.Append('³'); } else { Denominator.Append('^'); Denominator.Append((-Factor.Value).ToString()); } } } } if (Numerator is null) { if (IncludePrefix) { Numerator = new StringBuilder(Prefixes.ToString(this.prefix)); } else { Numerator = new StringBuilder(); } } if (!(Denominator is null)) { Numerator.Append('/'); if (NrDenominators > 1) { Numerator.Append('('); } Numerator.Append(Denominator.ToString()); if (NrDenominators > 1) { Numerator.Append(')'); } } return(Numerator.ToString()); }