Introduction
Recently, I was challenged with writing a report to generate a quote for an engineering specification. One of the requirements for this report was to convert decimals to fractions, and vice versa. It was also required to round the fractions to the nearest 1/16 of an inch.
Background
I had run several internet searches to help me solve these issues and turned up some interesting stuff, but nothing to "do it all." So I combined what I found out there into one class, made some modifications, used it in my report, then decided to share this with my comrades here on CodeProject. My hope is that this class can be utilized, expanded upon, and / or optimized by the community.
Using the Code
I used Visual Studio to compile and run the class. Writing a test app to use this class should be simple enough. If not, let me know and I'll push something up here.
Notes
- I default the fractions to round to 1/16 as this was the requirement for the report. You can skip rounding all together by not passing in the last two parameters into the "
Convert
" function returning the string
(fraction) value.
- I wrote a handy little formatter for feet and inches that might help someone too (another requirement for the report I had to write).
public static class FractionConverter
{
public static string Convert(decimal pvalue,
bool skip_rounding = false, decimal dplaces = (decimal)0.0625)
{
decimal value = pvalue;
if (!skip_rounding)
value = FractionConverter.DecimalRound(pvalue, dplaces);
if (value == Math.Round(value, 0)) return value.ToString();
decimal mWhole = Math.Truncate(value);
decimal mFraction = value - mWhole;
uint mNumerator = 0;
uint mDenomenator = 1;
if (mFraction > 0m)
{
string strFraction = mFraction.ToString().Remove(0, 2);
uint intFractLength = (uint)strFraction.Length;
mNumerator = (uint)Math.Pow(10, intFractLength);
uint.TryParse(strFraction, out mDenomenator);
uint gcd = GreatestCommonDivisor(mDenomenator, mNumerator);
mNumerator = mNumerator / gcd;
mDenomenator = mDenomenator / gcd;
}
StringBuilder mBuilder = new StringBuilder();
if (mWhole > 0m)
{
mBuilder.Append(mWhole);
}
if (mFraction > 0m)
{
if (mBuilder.Length > 0)
{
mBuilder.Append(" ");
}
mBuilder.Append(mDenomenator);
mBuilder.Append("/");
mBuilder.Append(mNumerator);
}
return mBuilder.ToString();
}
public static decimal Convert(string value)
{
string[] dparse;
string[] fparse;
string whole = "0";
string dec = "";
decimal dReturn = 0;
dparse = value.Contains('-') ? value.Split('-') : value.Split(' ');
int pcount = dparse.Count();
if (pcount == 2)
{
whole = dparse[0];
dec = dparse[1];
}
else if (pcount == 1)
dec = dparse[0];
fparse = dec.Split('/');
if (fparse.Count() == 2)
{
try
{
decimal d0 = System.Convert.ToDecimal(fparse[0]); decimal d1 = System.Convert.ToDecimal(fparse[1]); dReturn = d0 / d1; decimal dWhole = System.Convert.ToDecimal(whole);
dReturn = dWhole + dReturn; }
catch (Exception e)
{
dReturn = 0;
}
}
else
{
try
{
dReturn = System.Convert.ToDecimal(whole + dec);
}
catch (Exception e)
{
dReturn = 0;
}
}
return dReturn;
}
private static uint GreatestCommonDivisor(uint valA, uint valB)
{
if (valA == 0 &&
valB == 0)
{
return 0;
}
else if (valA == 0 &&
valB != 0)
{
return valB;
}
else if (valA != 0 && valB == 0)
{
return valA;
}
else
{
uint first = valA;
uint second = valB;
while (first != second)
{
if (first > second)
{
first = first - second;
}
else
{
second = second - first;
}
}
return first;
}
}
public static bool ReformatForFeetAndInches
(ref string line_type, bool zero_for_blank = true)
{
if (string.IsNullOrEmpty(line_type))
{
if (zero_for_blank)
line_type = "0'";
return true;
}
decimal d = System.Convert.ToDecimal(line_type);
decimal d1 = Math.Floor(d);
decimal d2 = d - d1;
d2 = Math.Round(d2 * 12, 2);
string s1;
string s2;
s1 = d1 == 0 ? "" : d1.ToString() + "'";
s2 = d2 == 0 ? "" : FractionConverter.Convert(d2) + @"""";
line_type = string.Format(@"{0} {1}", s1, s2).Trim();
if (string.IsNullOrEmpty(line_type))
{
if (zero_for_blank)
line_type = "0'";
return true;
}
return true;
}
private static decimal DecimalRound(decimal val, decimal places)
{
string sPlaces = FractionConverter.Convert(places, true);
string[] s = sPlaces.Split('/');
if (s.Count() == 2)
{
int nPlaces = System.Convert.ToInt32(s[1]);
decimal d = Math.Round(val*nPlaces);
return d / nPlaces;
}
return val;
}
}