String Pattern Matching algo

1

116Rohan

I came across a question in one of the Computing olympiad regarding
string pattern matching.

Write a program that will accept a fraction of the form N/D, where N is
the numerator and D is the denominator, that prints out the decimal
representation. If the decimal representation has a repeating sequence
of digits, it should be indicated by enclosing it in brackets. For
example, 1/3 = .33333333...is denoted as .(3), and 41/333 =
..123123123...is denoted as .(123).

Typical conversions are:

1/3 = .(3)
22/5 = 4.4
1/7 = .(142857)
3/8 = .375
45/56 = .803(571428)

Now I could not think how do I even start writing a logic for creating
a pattern.
Then I thought that maybe I should start comparing characters from the
right rather than the left.
But these two examples even negate that theory;

1/7 gives me ---> 0.1428571428571428571428571429 on a 16bit machine

45/56 gives me ---> 0.8035714285714285714285714286

I was trying to eliminate the last number as it rounds off, and so I
can start creating combinations from right to left. But nothing seems
to be working.

Any hints/suggestions will be appreciated.
 
F

Flash Gordon

I came across a question in one of the Computing olympiad regarding
string pattern matching.

Write a program that will accept a fraction of the form N/D, where N is
the numerator and D is the denominator, that prints out the decimal
representation. If the decimal representation has a repeating sequence
of digits, it should be indicated by enclosing it in brackets. For
example, 1/3 = .33333333...is denoted as .(3), and 41/333 =
.123123123...is denoted as .(123).

Now I could not think how do I even start writing a logic for creating
a pattern.

Algorithms questions really belong on comp.programming not here, but
I'll point you in the right direction...
Then I thought that maybe I should start comparing characters from the
right rather than the left.
But these two examples even negate that theory;

1/7 gives me ---> 0.1428571428571428571428571429 on a 16bit machine

45/56 gives me ---> 0.8035714285714285714285714286

I was trying to eliminate the last number as it rounds off, and so I
can start creating combinations from right to left. But nothing seems
to be working.

So don't do floating point division.
Any hints/suggestions will be appreciated.

How about this. Start off by getting out some maths books from when you
were much younger, the ones where you did long division. If you look at
it, you will see you were doing repeated integer division using the
remainder from the last division. Then you just have to watch out for
when you start repeating yourself...
--
Flash Gordon, living in interesting times.
Web site - http://home.flash-gordon.me.uk/
comp.lang.c posting guidelines and intro:
http://clc-wiki.net/wiki/Intro_to_clc

Inviato da X-Privat.Org - Registrazione gratuita http://www.x-privat.org/join.php
 
W

websnarf

I came across a question in one of the Computing olympiad regarding
string pattern matching.

Write a program that will accept a fraction of the form N/D, where N is
the numerator and D is the denominator, that prints out the decimal
representation. If the decimal representation has a repeating sequence
of digits, it should be indicated by enclosing it in brackets. For
example, 1/3 = .33333333...is denoted as .(3), and 41/333 =
.123123123...is denoted as .(123).

Well you need to essentially duplicate the process of long division by
hand, and note the repeating pattern like you did by hand. But the key
to things like this is not to *EXACTLY* duplicate the by hand process
(which has been optimized for our puny human brains), but rather
rederive what makes the by hand method work, just build the relevant
equations from there, and work out the process from there.

A repetition when dividing a fixed point by a fixed point happens
during long division when there is a repetition of the remainder
*after* the last significant digit of the numerator is consumed by the
division process.

In long division, you are approximating x = n/d by the sequence:

10^p *(n - x_p*d) = r_p, where 0 <= r_p < d, and 10^p*x_p is an
integer.

If there is a p such that r_p = 0, then you have an exact division,
otherwise you are looking for a pair of p's each such that 10^p > n (I
think; you should check this), where r_p repeats. Should be straight
forward.
 
M

Martin Ambuhl

I came across a question in one of the Computing olympiad regarding
string pattern matching.

Write a program that will accept a fraction of the form N/D, where N is
the numerator and D is the denominator, that prints out the decimal
representation. If the decimal representation has a repeating sequence
of digits, it should be indicated by enclosing it in brackets. For
example, 1/3 = .33333333...is denoted as .(3), and 41/333 =
.123123123...is denoted as .(123).

Typical conversions are:

1/3 = .(3)
22/5 = 4.4
1/7 = .(142857)
3/8 = .375
45/56 = .803(571428)

Now I could not think how do I even start writing a logic for creating
a pattern.
Then I thought that maybe I should start comparing characters from the
right rather than the left.
But these two examples even negate that theory;

1/7 gives me ---> 0.1428571428571428571428571429 on a 16bit machine

45/56 gives me ---> 0.8035714285714285714285714286

I was trying to eliminate the last number as it rounds off, and so I
can start creating combinations from right to left. But nothing seems
to be working.

Any hints/suggestions will be appreciated.

Here's a hint. For a fraction in the range 0 to 1, it will be in the form
.baaaa
where b has k digits and a has n
This number can be written as
pow(10,-k)( b + a/(pow(10,n)-1))
^^^^^^^^^^^^
(Q)This part is n nines
The expression labeled with Q is all nines, so it has no factors which
are 2 or 5. In your rational expression N/D collect the factors of 2
and 5, so
D = pow(2,r) * pow(5,s) * R
k must be the larger of r and s, and n (number of nines in Q) will be at
most R and could be less. b has at most than k digits. Notice that
16-bit signed numbers can reach pow(2,15)-1 == 32767. Luckily this is
not prime, but there are lots of prime numbers nearby. For example,
32749 is prime. Be prepared to handle repeating digits of at least this
size.

The above discussion should tell you thar 1/3 has no leading decimals
before the repeating segment, and 1/6 has 1
(since 6 = pow(2,1)*pow(5,0)*3) .
So 1/3 is pow(10,0) * (3/9) where 3 is 'a', the repeating. Because
k == 0, the nonrepeating intial sequence has no digits (so is not
even shown as a zero),
abd 1/6 is pow(10,-1) * (1 + 6/9). The nonrepeating section b is one
digit (since k = 1) and the repeating segment is a 6. Note that we did
not use denominators of 3 or 6 nines. We nneded the smallest number of
the form pow(10,n)-1 with 3 as a factor. That number is 9, with a
single digit. 1/7 has 7 digits in the repeating string, because 9999999
is the smallest such number with 7 for a factor.

So here's the strategy.
If the fraction is improper (N >= D) remove the integgal part and write it:
I. (so N/D = I + N'/D with a proper fraction)
otherwise write
0,

Factor out the 2's and 5's in D. The larger index tells us how many
digits are in the non-repeating segment.

Compute it and write it down.
I.b
The residual D', D with all the factors 2 and 5, either must be 1 (so
I.b us terminating, a = 0, and we'ew done) our must divide a number of
the form 9....9 of 1 to D' digits. Start with Q=9, Q = 10*Q+9, etc
until you have one or have reached the timits of your machine. This part
need not be reported and may be done with, say, unsigned long long ints
even if the problem space is for signed ints. This rells you n, the
length the repeating string. Wrete the '(', generate the n digits,
write down a ')':
I.a(b)
 
R

Rod Pemberton

I came across a question in one of the Computing olympiad regarding
string pattern matching.

Write a program that will accept a fraction of the form N/D, where N is
the numerator and D is the denominator, that prints out the decimal
representation. If the decimal representation has a repeating sequence
of digits, it should be indicated by enclosing it in brackets. For
example, 1/3 = .33333333...is denoted as .(3), and 41/333 =
.123123123...is denoted as .(123).

Typical conversions are:

1/3 = .(3)
22/5 = 4.4
1/7 = .(142857)
3/8 = .375
45/56 = .803(571428)

Now I could not think how do I even start writing a logic for creating
a pattern.

IIRC, there is a recursive algorithm (using 1/X ?) to convert terminated
(non-repeating and not random values PI, etc.) decimals to the form N/D. If
so (and since they gave you a valid fraction), you could compute N/D as
decimal and then attempt to convert back to N/D. If the number is
non-repeating, the first N and D should be the same as the second conversion
N and D. If the number is repeating, it will be terminated by the precision
of the machine. This means that the first N and D will be different from
the conversion N and D, because it lost some precision. For the repeating
numbers, you then need to determine the length of the repeat. I don't know
if there is a simple method for that.


Rod Pemberton
 
R

Rod Pemberton

Rod Pemberton said:
IIRC, there is a recursive algorithm (using 1/X ?) to convert terminated
(non-repeating and not random values PI, etc.) decimals to the form N/D. If
so (and since they gave you a valid fraction), you could compute N/D as
decimal and then attempt to convert back to N/D. If the number is
non-repeating, the first N and D should be the same as the second conversion
N and D. If the number is repeating, it will be terminated by the precision
of the machine. This means that the first N and D will be different from
the conversion N and D, because it lost some precision. For the repeating
numbers, you then need to determine the length of the repeat. I don't know
if there is a simple method for that.

I should probably clarify slightly. The algorithm will need be modified to
continue conversion until it's base is equal to or near D. This of course
will eliminate problems like 32/16 being returned as 2/1.

RP
 
M

Martin Ambuhl

Martin Ambuhl wrote a bunch of stuff):

But note that the method for determining the number of repeating digits
The residual D', D with all the factors 2 and 5, either must be 1 (so
I.b us terminating, a = 0, and we'ew done) our must divide a number of
the form 9....9 of 1 to D' digits. Start with Q=9, Q = 10*Q+9, etc
until you have one or have reached the timits of your machine. This part
need not be reported and may be done with, say, unsigned long long ints
even if the problem space is for signed ints. This rells you n, the
length the repeating string.

is not perhaps not very useful after all, the largest values for Q
are
16 bits (signed or unsigned) 9999 (so D' <= 4: specifically 3, but
3 divides 9)
32 bits (signed or unsigned) 999999999 (do D' <= 9: 3,7,9, but 3 and 9
divide nine, only 7 is useful)
64 bits (signed) 999999999999999999 (so D' <= 18; picking up 11, 13, 17)
64 bits (unsigned) 9999999999999999999 (so D' <= 19; 19)

So whats the point? After reporting I. (the integral part), computing k
(the length of the non-repeating segment) and reporting the k digits and
the opening brace, now showing I.b(, you know that the repeating string
is at most n characters. There are strategies for storing generated
digits un either one or two allocated buffers of n chars each. The two
buufer approach may well win on speed; the one buffer approach on space.
Once you have the n chars (or in the two buffer case, well before
then) you can easily for repetitions the initial part of the n-digit
repeating pattern, yielding a shorter one? And you don't need to check
all lengths. Contemplate what the prime factors of D' tell you about
what lengths make sense.

And I forgot to note, that if you don't
1) reduce N/D, eliminating common factors and
2) if exactly one of N or D is negative, report a '-'.
if any of N or D is negative, change its sign.
3) if D is zero, report the fact and quit
then all bets are off.
 
B

Barry Schwarz

I came across a question in one of the Computing olympiad regarding
string pattern matching.

Write a program that will accept a fraction of the form N/D, where N is
the numerator and D is the denominator, that prints out the decimal
representation. If the decimal representation has a repeating sequence
of digits, it should be indicated by enclosing it in brackets. For
example, 1/3 = .33333333...is denoted as .(3), and 41/333 =
.123123123...is denoted as .(123).

Typical conversions are:

1/3 = .(3)
22/5 = 4.4
1/7 = .(142857)
3/8 = .375
45/56 = .803(571428)

Now I could not think how do I even start writing a logic for creating
a pattern.
Then I thought that maybe I should start comparing characters from the
right rather than the left.
But these two examples even negate that theory;

1/7 gives me ---> 0.1428571428571428571428571429 on a 16bit machine

45/56 gives me ---> 0.8035714285714285714285714286

I was trying to eliminate the last number as it rounds off, and so I
can start creating combinations from right to left. But nothing seems
to be working.

Any hints/suggestions will be appreciated.

Somewhere in the depths of number theory remembrances, I recall a
method of determining when the repetition starts and the length of the
repetition. Unfortunately, the details have long been forgotten.
Attempting to compare digits is error prone because if you see a value
of .121212 you might conclude the answer is .(12) when the answer
really is .(1212121212123).

This is really more an algorithm question rather than C.


Remove del for email
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,183
Messages
2,570,964
Members
47,511
Latest member
svareza

Latest Threads

Top