Evaluate Simple Math Strings

I am developing a simple app for woodworks that needs to be able to do very simple math and convert between decimal inches, fractional inches and mm. I’ve successfully created a nice UI and can input a number in any format (as a string). But now how can I convert a string, say 1-3/36", to its decimal and metric equivalent? And with converting from decimal to fractional, how would you round to the nearest 1/32 (or 1/64 or whatever)?

1 Like

Well, Jon, it is a bit circuitous.

To go from decimal inch to mm is straightforward, you multiply the inch by 25.4 and you are done.
It is the fractional aspect that is more delicate.
If you want to impose the separator as “-” for instance, you need to parse the string, finding where the “-” is located using the “in text <{use your text variable here}> find first occurrence of text <->”. With this position, you can then trim the text to get what the first part is (the inch) and then the second part, which will be the fraction.
Then you need to parse that second sub-string (say “5/8”) to identify the “/” location, and extract the numerator and the denominator values, divide one by the other (you may have to cater for the possibility that sloppy users may put a zero there, just to annoy your app…) and add to the whole inch value, and get a decimal inch result.
To go the other way, it is a bit more complicated, since the value may need to round to different fractions. Are you expecting the user to specify if he is happy with 16th, or really want to go to 64th?
If the user specifies the smallest fractional, then the following is just a tiny bit simpler. If not, then you have to go with the smallest fractional value you want to allow, and reduce it.
Say the value entered is 2.143 inch.
We can already get the 2 out of the way since it is the whole part; the function you need is the modulo (oddly overly simplified in name and called “remainder of” in X…).
2.142 divided by 1 will have a remainder of 0.143 !
Now, multiply 0.143 by 64 and you get 9.152. I guess you can then round off this value to 9 (using the “round” function)
That means 2.143 is about 2-9/64.
If it happens that, instead of 9, we would have gotten 8 for instance (an even value, easily checked with the “is even” function) then you can divide that value by 2 and reduce the 64th to 32nd. And if it is still even after that reduction, you keep reducing the base fractional (i.e. going from 64, to 32, to 16, to 8 and so on) until the value is odd, so that 8/64 would be returned as 1/8th.
Then, you reassemble all those numerical bits and pieces, including your “-” and “/” separators into an output string, using the text “join” function.
And then you’re done.

3 Likes

Hi there,

This is such an interesting idea! I’ve thrown together an app here that can convert between decimal and fractions. Screen ‘F2D’ can return a fraction as a decimal, screen ‘D2F’ can take a number in decimal input and a denominator and return it in the form ‘X-Y/Z’. So say if you input 2.5 and a denominator of 32, it’ll return ‘2-16/32’.

The Screen ‘MetricImperial’ will also convert between cm and imperial measurements, but the cm to imperial will return the inches in decimal format.

You can also check out this previous post of mine about rounding numbers in an app.

Let me know if this works with your app!

3 Likes

Hi Jane, thanks a lot for that. Since I needed to get the decimal to fraction part to deliver only common fractions and I couldn’t figure out how to round fractions, I found a lookup table and used that with lists. But it is dependent on a for each loop which looks for the lowest/closest match in the table. Which, sometimes is not the best match. You get weird things like 0.5 coming out as 31/64ths for instance. Given a list of decimal numbers, how would you find the closest to an input number?

Actually, you have two problems.
The first one is that, in a computer, decimal numbers cannot be expressed exactly unless they are a combination of fractions of 2, i.e. 1/2 is ok, 1/4 is ok, but not 1/3, since there is no way to make 0.333… out of 64th. 1/3 is 21.3333…/64, and since you still have the .333… fraction, then going to 4096th (64 square) will still leave a .3333 part, until you simply run out of decimal places and resolution.
While 0.5 can be internally represented accurately in a computer (because it is exactly 1/2) that is not true for 0.4, which will be rounded off.
(0.4 is 1/4 + 0.15, and 0.15 is 1/8 + 0.025, and 0.025 is 1/64 + 0.009375, and 0.009375 is 1/128 + 0.0015625, and so on. As you can see, each time we extract an exact component, we are left with a reminder that has more and more decimals).
That may be one of the reason for those “weird things”, particularly is the value to be converted is the result of a calculation that may appear “even”, but is not because it is 0.399999999 and only the display is rounded off, not the value itself.

The other problem problem you have is with the concept of a look-up map.
Suppose you go in there with a value that is just between your reference values. Say it is X=13/256 (0.05078125), which is 1/4 or the way between Y3=3/64 (0.046875) and Y4=1/16 (0.0625). If your look-up map access is to check “is my value greater or equal than Yn” and to keep increasing “n” until it is no longer larger, then you will be rounding UP to Y4 even if the value was a lot closer to Y3.
And that may be an issue if this is to dimension a hole as opposed to a peg. The hole may be too tight, while the peg would be loose.

If you want to use a look-up table, the node values Yn need to be intermediate, i.e. “the nominal - 1/128” (i.e. half the nominal resolution if you want to go to 64th), so if the X value is greater that Yn-1 but less than Yn, then it will always be closest to the nominal.

Still, assuming that values requiring converting will be evenly distributed between 0 and 63/64, then your code will, on average, test 32 time before finding which fraction to use. Not very efficient.
That is why computing the value makes more sense, and is far more robust.
Take the fraction you have – say 0.05078125 – and multiply by 64. You get 3.25. You round the value, and since it is less than 3.5, it will round down to 3.0 . That is your answer: 3/64th.

1 Like