-
Notifications
You must be signed in to change notification settings - Fork 386
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Introduce conversion methods between Angle and Ratio #1342
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. |
This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days. |
This PR was automatically closed due to inactivity. |
@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. ?