New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce conversion methods between Angle and Ratio #1342
base: master
Are you sure you want to change the base?
Introduce conversion methods between Angle and Ratio #1342
Conversation
I could simply add the following method to Ratio.extra.cs: /// <summary>
/// Converts the ratio to a string representing slope in a more detailed fraction format.
/// </summary>
/// <param name="cultureInfo">The culture info to format the string. If null, the current culture is used.</param>
/// <returns>A string representing the slope in a detailed fraction format like "3 in 4" or "3 : 4".</returns>
public string ToDetailedSlopeString(CultureInfo cultureInfo)
{
cultureInfo = cultureInfo ?? CultureInfo.CurrentCulture;
// Find the closest fraction to represent the slope
(int numerator, int denominator) = ConvertToFraction(this.DecimalFractions);
string slopeFormat = cultureInfo.Name == "en-US" ? "{0} in {1}" : "{0} : {1}";
return string.Format(cultureInfo, slopeFormat, numerator, denominator);
}
private (int, int) ConvertToFraction(double decimalFraction, int maxDenominator = 100)
{
if (decimalFraction == 0)
{
return (0, 1);
}
int sign = Math.Sign(decimalFraction);
decimalFraction = Math.Abs(decimalFraction);
int wholePart = (int)decimalFraction;
decimalFraction -= wholePart;
int lowerNumerator = 0, lowerDenominator = 1, upperNumerator = 1, upperDenominator = 1;
while (lowerDenominator <= maxDenominator && upperDenominator <= maxDenominator)
{
int middleDenominator = lowerDenominator + upperDenominator;
int middleNumerator = lowerNumerator + upperNumerator;
if (middleDenominator > maxDenominator) break;
double middleValue = (double)middleNumerator / middleDenominator;
if (decimalFraction < middleValue)
{
upperNumerator = middleNumerator;
upperDenominator = middleDenominator;
}
else if (decimalFraction > middleValue)
{
lowerNumerator = middleNumerator;
lowerDenominator = middleDenominator;
}
else
{
lowerNumerator = upperNumerator = middleNumerator;
lowerDenominator = upperDenominator = middleDenominator;
break;
}
}
// Choose the fraction that is closer to the original decimalFraction
double lowerDiff = decimalFraction - (double)lowerNumerator / lowerDenominator;
double upperDiff = (double)upperNumerator / upperDenominator - decimalFraction;
int finalNumerator, finalDenominator;
if (lowerDiff < upperDiff)
{
finalNumerator = wholePart * lowerDenominator + lowerNumerator;
finalDenominator = lowerDenominator;
}
else
{
finalNumerator = wholePart * upperDenominator + upperNumerator;
finalDenominator = upperDenominator;
}
return (finalNumerator * sign, finalDenominator);
} |
I don't know what the correct term is, but I'd expect something like This could be a method just like you proposed above. |
There is some similar work here, for UnitsNet/UnitsNet/CustomCode/Quantities/Length.extra.cs Lines 238 to 314 in a95e33f
Maybe it can be reused or take inspiration from. |
@angularsen, following your suggestions from #1337, here is an updated PR adding the conversion methods between Angle and Slope.
How do you suggest we proceed with creating strings like "1 in 2, 1 in 5, 1:2, 1:5" etc. ?