1

Possible Duplicates:
How to convert floats to human-readable fractions?
Convert decimal to fraction in Objective-C?

I want to take a decimal, 5.50, which is in a variable, and divide only the fractional part by 0.0625, which is my accuracy point. This would give me 8, as in 8/16 or 1/2.

Then I would like to display that answer as 5 8/16 or 1/2 in a text field. I know some answers will return a decimal still and not a whole number when dividing by .0625, but I would round that answer, which would still give me to the nearest 16th. What would be the best way to do this? I would like to make a function so I can reuse it. Yes, I posted a similar question that was answered, but wasn't able to get it to work. I'm thinking there's a better and easier way to do this, so I've posted this. Thanks in advance.

Community
  • 1
  • 1
Jason
  • 650
  • 2
  • 10
  • 33
  • No, I seen that too. This is much more simple, or it should be I would think. just need to cast everything after decimal to NSInteger, divide by .0625 and then just display everything together as a fraction. Right? – Jason May 19 '11 at 16:59
  • That would be my other question that didn't work. – Jason May 19 '11 at 17:43
  • How did my title change? – Jason May 19 '11 at 17:45
  • With enough reputation users have the ability to edit questions and answers. You can see who and what edits have been made by looking at the bottom of the question - the second box that says 'edited x minutes ago' – Abizern May 19 '11 at 17:50
  • @Jason: I edited your question to clarify it before making a decision as to whether it duplicated your earlier question. I tried to make the tile more specific, but I still believe that the answer to your earlier question also answers this one, so I voted to close as a duplicate. If you disagree, please edit your question and explain the specific reason why the other answer (which you accepted) is unsuitable in this case. – jscs May 19 '11 at 18:03
  • Because it seems like too much code for what I'm doing. I want to find a more simple and easy to understand way to do this. – Jason May 19 '11 at 18:48
  • The preferred way to handle that situation is to _not_ accept the answer if it doesn't actually help you, and edit the old question to get an answer that does. – jscs May 19 '11 at 20:29
  • yeah i tried that a few times. – Jason May 19 '11 at 20:56

2 Answers2

4

Function:

- (NSString *)theFunction:(float)input {

    NSArray * array = [NSarray initWithObjects:nil,nil@"1/8",nil,@"1/4",]

    int fractions = lroundf((input - (int)input)/((float)1/(float)16));
    if(fractions == 0 || fractions == 16) {
        return [NSString stringWithFormat:@"%d",lroundf(input)];
    } else {
        return [NSString stringWithFormat:@"%d %d/16",(int)input,fractions];
    }

}

Note:

The if statement converts 5 0/16 into 5 and 5 16/16 into 6.
If you prefer the 5 0/16 and 5 16/16 notation, replace the if statement by:

return  [NSString stringWithFormat:@"%d %d/16",(int)input,fractions];

EDIT: (by Jason)

//Just to make it a little sweeter!
- (NSString *)theFunction:(float)input {
    int fractions = lroundf((input - (int)input)/((float)1/(float)16));
    if(fractions == 0 || fractions == 16) {
        return  [NSString stringWithFormat:@"%d",lroundf(input)];
    } else if(fractions == 2) {
        return  [NSString stringWithFormat:@"%d 1/8",(int)input];
    } else if(fractions == 4) {
        return  [NSString stringWithFormat:@"%d 1/4",(int)input];
    } else if(fractions == 6) {
        return  [NSString stringWithFormat:@"%d 3/8",(int)input];
    } else if(fractions == 8) {
        return  [NSString stringWithFormat:@"%d 1/2",(int)input];
    } else if(fractions == 10) {
        return  [NSString stringWithFormat:@"%d 5/8",(int)input];
    } else if(fractions == 12) {
        return  [NSString stringWithFormat:@"%d 3/4",(int)input];
    } else if(fractions == 14) {
        return  [NSString stringWithFormat:@"%d 7/8",(int)input];
    } else {
        return  [NSString stringWithFormat:@"%d %d/16",(int)input,fractions];
    }
}

EDIT (Response to edit by Jason)

I optimized your code, this way it's much cleaner.
Also check the code below, I think it's more efficient to use an array.

- (NSString *)theFunction:(float)input {

    NSArray * array = [[NSArray alloc] initWithObjects: @"",@"",@"1/8",@"",@"1/4",@"",@"3/8",@"",@"1/2",@"",@"5/8",@"",@"3/4",@"",@"3/4",@"",@"7/8",@"",nil];

    int fractions = lroundf((input - (int)input)/((float)1/(float)16));
    if(fractions == 0 || fractions == 16) {
        return [NSString stringWithFormat:@"%d",lroundf(input)];
    } else {
        if([[array objectAtIndex:fractions] isEqualToString:@""]) {
            return [NSString stringWithFormat:@"%d %d/16",(int)input,fractions];
        } else {
            return [NSString stringWithFormat:@"%d %@",(int)input,[array objectAtIndex:fractions]];
        }
    }

}
Anne
  • 26,765
  • 9
  • 65
  • 71
  • is "input" where the variable would go? wouldn't you need to set the text of variable? – Jason May 19 '11 at 17:52
  • +1 for code. I don't have an Objective-C compiler in front of me, and would have been too lazy anyway. – gatkin May 19 '11 at 18:04
  • @Jason. You can simply paste the function inside your implementation file (the .m file) and then call it like `NSString * result = [self theFunction:5.03];`. – Anne May 19 '11 at 18:08
  • Added snippet how to run the code without function. – Anne May 19 '11 at 18:12
  • So if I have your function, would this be right calling it and displaying? `NSString * result = [self theFunction:myVariable]; [myTextField setText:[NSString stringWithFormat:@"%d %d/16", (result)]];` – Jason May 19 '11 at 18:43
  • Call the function like this: `NSString * result = [self theFunction:myVariable];`. Next update the text field like this: `[myTextField setText:result];`. You don't need to format the result because it's already formatted by the function. You can also merge both lines into `[myTextField setText:[self theFunction:myVariable]];`. Make sure myVariable is a float. Hopefully this helps! – Anne May 19 '11 at 19:04
  • OMG thank you!!!! Been trying to figure this out for the longest time, I'm still pretty new to programming, but I knew it had to be easier than the answer to my other post. You are the MAN!! (Figuratively speaking) :) – Jason May 19 '11 at 19:05
  • I'm happy it worked :) Don't hesitate asking when you're struggling! – Anne May 19 '11 at 19:10
  • Thank you so much!! It's discouraging when you ask and people and they don't really give you the whole answer, I learn by seeing the code first, then breaking down how it works. I understand people want you to try and figure out things for yourself, which is fine. But I knew there was shorter and easier to understand code to get the result I was looking for. I can't thank you enough!! I SEE how it works now!! Thank You!! – Jason May 19 '11 at 19:15
  • Optimized your code and added an example with array. – Anne May 19 '11 at 21:45
  • Awesome! Is one better on performance or memory than the other? – Jason May 20 '11 at 02:48
  • _Sorry for the late response_ - Generally it's frowned upon to use many `} else if() {` statements. For small denominators like 4 you may use multiple `} else if() {` statements. But for larger denominators I strongly recomment using one big array instead of many `} else if() {` statements. It makes your code much more efficient, maintainable and readable. There is absolutely no significant difference in terms performance or memory usage. – Anne May 20 '11 at 21:44
  • I have a question, if you want I can make a new thread. If I have a textfeld formatted as "00ft 00 1/16in" from 3 pickers, and I'm trying to grab the value and convert all to decimal before calculation, could you help me with that? – Jason Jun 09 '11 at 19:12
2

I think your problem is much simpler than the one @Caleb linked to.

Divide by 0.0625 to get the number of sixteenths. Round the result to the nearest integer i. Use integer division i / 16 to get the number of whole units and use the modulo operator j = i % 16 to get the fractional units. To reduce the fractions, use j as an index into an array you create ahead of time as { "", "1/16", "1/8", "3/16", ... }.

You can also divide by 16 and get the modulo 16 using bitwise operators, but that will make the code harder to read for not much benefit.

gatkin
  • 1,902
  • 12
  • 12
  • I think you understand what I'm trying to do best. It sounds like you hit the nail on the head...is there anyway you would be willing to write a function here as a template? – Jason May 19 '11 at 17:11
  • 1
    He's just given you the steps you need to take quite clearly - what are you having difficulty with? – Abizern May 19 '11 at 17:55