1

I have a specific case where I need to return 'Vulgar' fractions where ever possible. The code that I have come up with is as follows

var complexFractionString = heaveValue.ToComplexFractionString();
complexFractionString = complexFractionString.Replace("1/8", "⅛");
complexFractionString = complexFractionString.Replace("1/4", "¼");
complexFractionString = complexFractionString.Replace("3/8", "⅜");
complexFractionString = complexFractionString.Replace("1/2", "½");
complexFractionString = complexFractionString.Replace("5/8", "⅝");
complexFractionString = complexFractionString.Replace("3/4", "¾");
complexFractionString = complexFractionString.Replace("7/8", "⅞");

return complexFractionString;

.ToComplexFractionString() is a method that returns the least common denominator fraction of the double in string format. i.e. an input of .5 would return "1/2"

This code works for my use case right now but I do not like how it is structured at all. It is very brittle in that a fraction of "1/16" or "1/32" would get through without being changed and it the code is a bunch of lines to do something that should be relatively easy.

Is there a better way to do this in C#?

PlTaylor
  • 7,345
  • 11
  • 52
  • 94
  • 1
    Why do math with strings? Have a `struct Fraction { }` and write your code in `ToString()` based on the _values_ not their string representation. – John Alexiou Jul 29 '14 at 13:15
  • I'm not doing any math with strings... I have done the math with doubles, and am reporting the numbers back to my GUI in fraction form. Unfortunately some of my controls don't like displaying '/' so I am using 'Vulgar' fractions to get around that. – PlTaylor Jul 29 '14 at 13:16
  • what if you have `71/80`? – Daniel A. White Jul 29 '14 at 13:23
  • 1
    what kind of display can show ½ and not 1/2? – Hogan Jul 29 '14 at 13:23
  • WPF DataGrids struggle displaying '.' and '/' in the header. i.e. if you try the header will display but the values in that column will not. – PlTaylor Jul 29 '14 at 13:24
  • @PlTaylor Sounds like *that* should be your question. – asawyer Jul 29 '14 at 13:25
  • There must be a workaround for that, does the WPF datagrid not support header templates? – Charleh Jul 29 '14 at 13:25
  • In case of 71/80 I would be out of luck. The only saving grace is that my .ToComplexFractionString() function returns to the nearest 32nd. – PlTaylor Jul 29 '14 at 13:25
  • ok, and you have tried using the obvious htmlencoding of the `1 / 2`? – Hogan Jul 29 '14 at 13:27
  • This sounds like a classic [XY problem](http://xyproblem.info/). – asawyer Jul 29 '14 at 13:29
  • @asawyer You might be right...but for the time being I am curious to see if there are any answers that solve this particular. – PlTaylor Jul 29 '14 at 13:40
  • @Hogan I have not tried that, I am trying to mock something out like that now if you would like to propose an answer. – PlTaylor Jul 29 '14 at 13:41
  • @Charleh It does support header templates. – PlTaylor Jul 29 '14 at 13:41
  • @PlTaylor - ok... I propose you do a google search on `htmlencode .net` -- good luck – Hogan Jul 29 '14 at 13:42
  • @Hogan HttpUtility.HtmlEncode("1/4"); just returns "1/4" and not "¼" – PlTaylor Jul 29 '14 at 13:49
  • @PlTaylor Post a new question, don't try to hash it out here in comments. – asawyer Jul 29 '14 at 13:50
  • @Hogan It is very possible that I am dense, but could you elaborate on what you mean? – PlTaylor Jul 29 '14 at 13:55
  • @PlTaylor - You problem is **not** about displaying `½` it is about displaying `1/2`. *That is the problem you need to solve* Telling me my suggestion did not solve the problem we are not trying to solve seems to move the process of solving your **actual** problem backwards. – Hogan Jul 29 '14 at 13:57
  • @Hogan I mistook your comments as trying to solve the question I asked. I agree with asaywer that hashing out whether this question is the real problem or not in the comments is not productive, and given that the mob has spoken that they would rather answer the other question I am writing that question up now. – PlTaylor Jul 29 '14 at 14:01
  • @PITaylor - Here is an example of a very complicated header. http://stackoverflow.com/questions/15175546/wpf-custom-datagrid-column-header – Hogan Jul 29 '14 at 14:02
  • For future reference the more fundamental question has been asked http://stackoverflow.com/questions/25017542/how-to-prevent-columns-from-not-displaying-in-wpf-datagrids-when-using-in-th – PlTaylor Jul 29 '14 at 14:13

1 Answers1

2

Luke, use the force (immutable structs).

public struct Fraction
{
    readonly int numerator, denominator;

    public Fraction(double x)
    {
        // construct a fraction
    }

    public Fraction(int numerator, int denominator)
    {
        this.numerator=numerator;
        this.denominator=denominator;
    }

    public Fraction Reduced() { /* Simplify */ }

    public override string ToString()
    {
        return GetVulgarFraction(numerator, denominator);
    }

    static string GetVulgarFraction(int numerator, int denominator)
    {
        if(numerator<0)
        {
            // Handle -1/2 as "-½"
            return string.Format("-{0}", 
                GetVulgarFraction(-numerator, denominator));
        }
        if(numerator>denominator)
        {
            // Handle 7/4 as "1 ¾"
            return string.Format("{0} {1}", 
                numerator/denominator, 
                GetVulgarFraction(numerator%denominator, denominator));
        }
        // Handle 0/1 = "0"
        if(numerator==0) return "0";
        // Handle 10/1 = "10"
        if(denominator==1) return numerator.ToString();
        // Handle 1/2 = ½
        if(denominator==2)
        {
            if(numerator==1) return "½";
        }
        // Handle 1/4 = ¼
        if(denominator==4)
        {
            if(numerator==1) return "¼";
            if(numerator==3) return "¾";
        }
        // Handle 1/8 = ⅛
        if(denominator==8)
        {
            if(numerator==1) return "⅛";
            if(numerator==3) return "⅜";
            if(numerator==5) return "⅝";
            if(numerator==7) return "⅞";
        }
        // Catch all
        return string.Format("{0}/{1}", numerator, denominator);
    }
}
John Alexiou
  • 28,472
  • 11
  • 77
  • 133
  • Make sure you handle cases where `numerator > denominator` using a complex fraction notation. – John Alexiou Jul 29 '14 at 13:29
  • I'm not sure what this gets me over my current code. It is no more flexible, is longer, and doesn't handle complex fractions greater than 1. – PlTaylor Jul 29 '14 at 13:39
  • Now it does, and it won't fail for `1/20` displaying it as `½0` like in your code (your original question). – John Alexiou Jul 29 '14 at 13:40
  • The only thing it needs to handle now is `denominator<=0`. It is your choice on what to do then. – John Alexiou Jul 29 '14 at 13:41
  • You posted the revised version at the same time as my comment. And you are correct about your observation about 1/20. I guess I was hoping that there was something more straight forward than this. – PlTaylor Jul 29 '14 at 13:43
  • What is different from your code is `GetVulgarFraction()` which is not that complex, nor different from what you have, but works with numbers and not strings. – John Alexiou Jul 29 '14 at 14:01
  • I'm coming around to the fact that this is a step forward from my code. – PlTaylor Jul 29 '14 at 14:02
  • For robustness I would always force a positive denominator (maybe using a `uint`) in my constructor and `Reduce()` functionality. – John Alexiou Jul 29 '14 at 14:02