38
\$\begingroup\$

Context

If a0 and b0 are two decimal numbers, with a and b representing the decimal expansion of all digits but the least significant one, then we know that

$$\frac{a0}{b0} = \frac{a{\not\mathrel0}}{b{\not\mathrel0}}= \frac{a}{b}$$

Phony fraction

A phony fraction is a fraction where the numerator and denominator share a digit (other than a 0 in the units place) and, when that digit is erased from both numerator and denominator, the simplified fraction happens to be equal to the original one.

Example

\$16/64\$ is a phony fraction because if we remove the \$6\$, we get \$16/64 = 1{\not\mathrel6}/{\not\mathrel6}4 = 1/4\$, even though the intermediate step of removing both sixes is wrong.

Task

Given a fraction, determine if it is phony or not.

Note

Notice that 10/20 is not a phony fraction. Even though 10/20 = 1/2, the simplification here was mathematically sound, you divided numerator and denominator by 10, which amounts to "crossing out a 0 on the num. and the den.".

On the other hand, 102/204 = 12/24 is a phony fraction, because supposedly we can't cross out the 0s.

Because of this, when the input fraction is such that crossing out 0 gives an equivalent fraction to the original, the behaviour is unspecified.

Input

The fraction we care about, with positive numerator and denominator, in any sensible format. Some examples of sensible formats include:

  • a list [num, den] or [den, num]
  • a string of the form "num/den"
  • the exact fraction, if your language supports it
  • two different arguments to your function

Assume both are greater than 9. You can also assume the denominator is strictly larger than the numerator.

Output

A Truthy value if the fraction is phony and a Falsy value if it is not.

Test cases

(Please keep an eye out for the comments, as some people have really nice test case suggestions! I'll edit them in, but sometimes I don't do it immediately.)

Truthy

69/690 = 9/90
99/396 = 9/36
394/985 = 34/85
176/275 = 16/25
85/850 = 5/50
59/295 = 5/25
76/760 = 6/60
253/550 = 23/50
52/520 = 2/20
796/995 = 76/95
199/796 = 19/76
88/583 = 8/53
306/765 = 30/75
193/965 = 13/65
62/620 = 2/20
363/561 = 33/51
396/891 = 36/81
275/770 = 25/70
591/985 = 51/85
165/264 = 15/24
176/671 = 16/61
385/781 = 35/71
88/484 = 8/44
298/596 = 28/56
737/938 = 77/98
495/594 = 45/54
693/990 = 63/90
363/462 = 33/42
197/985 = 17/85
462/660 = 42/60
154/451 = 14/41
176/374 = 16/34
297/990 = 27/90
187/682 = 17/62
195/975 = 15/75
176/473 = 16/43
77/671 = 7/61
1130/4181 = 130/481

Falsy

478/674
333/531
309/461
162/882
122/763
536/616
132/570
397/509
579/689
809/912
160/387
190/388
117/980
245/246
54/991
749/892
70/311
344/735
584/790
123/809
227/913
107/295
225/325
345/614
506/994
161/323
530/994
589/863
171/480
74/89
251/732
55/80
439/864
278/293
514/838
47/771
378/627
561/671
43/946
1025/1312

You can check this reference implementation that I used to generate some phony fractions by brute-force.


This is so shortest submission in bytes, wins! If you liked this challenge, consider upvoting it... And happy golfing!

\$\endgroup\$
  • 3
    \$\begingroup\$ Possible duplicate of How NOT to reduce fractions \$\endgroup\$ – pppery Feb 19 at 14:06
  • 2
    \$\begingroup\$ The linked challenge is about removing a common substring. This is about removing a common digit. I think the difference is significant enough to make it non-dupe \$\endgroup\$ – Luis Mendo Feb 19 at 15:26
  • \$\begingroup\$ May we accept lists of digits? \$\endgroup\$ – Jonathan Allan Feb 19 at 15:50
  • 1
    \$\begingroup\$ Is 11/11 a phony fraction? \$\endgroup\$ – Jonathan Frech Feb 19 at 18:10
  • \$\begingroup\$ @JonathanFrech yes it is. Just not a very interesting one, I would say. \$\endgroup\$ – RGS Feb 19 at 19:44

13 Answers 13

14
\$\begingroup\$

J, 22 bytes

%&".e.=/#&,%/&(1".\.])

Try it online!

quick explanation for now:

  1. take the input as strings
  2. %/&(1".\.]) creates a function table %/ whose axes are the integer ". lists formed by the 1-outfixes \. (remove 1 digit at a time) of both args, and whose cells are the quotients of those numbers
  3. =/ forms a corresponding function table of the same shape, which acts as a boolean mask which is only 1 when corresponding "removed" digits are equal
  4. #&, Flattens , both function tables into lists and uses the boolean mask to filter # the quotients, since cancelling is only valid when the digits are equal
  5. %&". the true quotient of the inputs after converting to ints
  6. e. is that true quotient an element of the filtered list from step 4.
|improve this answer|||||
\$\endgroup\$
  • 1
    \$\begingroup\$ Really nice! +1 I have no idea what is going on but it is passing all test cases... So it can't be that wrong :p \$\endgroup\$ – RGS Feb 19 at 9:37
  • 2
    \$\begingroup\$ They’re added already I believe I noted the new ones in my TIO with comments \$\endgroup\$ – Jonah Feb 19 at 10:07
11
\$\begingroup\$

Python 3, 86 bytes

lambda a,b:g(a)&g(b)
g=lambda s:{(int(s[:i]+s[i+1:])/int(s),x)for i,x in enumerate(s)}

Try it online!

-8 bytes thanks to ovs

Making use of the fact that the boolean value for a0/b0==a/b is equivalent to a0/a==b0/b. The helper function g generates all ratios a0/a and keeps track of the removed digit. Then it does the same for b0/b. The main function determines the intersection of the two sets.

Returns a non-empty set (boolean True in Python) if a match is found, and an empty set (boolean False in Python) otherwise.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Looking good! +1 for your good work :D \$\endgroup\$ – RGS Feb 19 at 10:06
  • \$\begingroup\$ 114 bytes with enumerate. \$\endgroup\$ – ovs Feb 19 at 12:15
6
\$\begingroup\$

05AB1E, 26 23 22 bytes

€æ`âεR*Ë9ݺIJySõ.;å*}à

-3 bytes thanks to @Grimmy.

Input as a pair [numerator, denominator].

Try it online or verify all test cases.

Explanation:

۾         # Get the powerset of each number in the (implicit) input-pair
  `        # Push both lists separated to the stack
   â       # Create all possible pairs by taking the cartesian product
ε          # Map each pair to:
 R         #  Reverse the pair
  *        #  Multiply it by the (implicit) input-pair
   Ë       #  Check if both values are the same
 9Ý        #  Push a list in the range [0,9]
   º       #  Mirror each horizontally: [00,11,22,33,44,55,66,77,88,99]
 IJ        #  Push the input, joined together
   y       #  Push the pair we're mapping again
    S      #  Convert it to a flattened list of digits
     õ.;   #  Remove the first occurrence of those digits in the joined input,
           #  by replacing each first occurrence with an empty string
 å         #  Check if what remains is in the list of doubled digits
        *  #  And check if both that and the earlier check are truthy
}à         # After the map: check if any where truthy by taking the maximum
           # (after which this is output implicitly as result)

The R*Ë checks with input-pair \$[a,b]\$ and potentially reduced pair \$[c,d]\$ whether \$a×d=b×c\$ (source).

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ 24 with €æ`âʒ9Ý2×IJySõ.;å}εR*Ë}à. (Use €æ`âʒ9Ý2×®JySõ.;å}εR®*Ë}à to "verify all test cases".) \$\endgroup\$ – Grimmy Feb 19 at 13:10
  • 1
    \$\begingroup\$ Down to 23 with €æ`âεR*Ë9Ý2×IJySõ.;å*}à (€æ`âεR®*Ë9Ý2×®JySõ.;å*}à to verify all). \$\endgroup\$ – Grimmy Feb 19 at 13:23
  • 1
    \$\begingroup\$ @Grimmy Thanks. And an additional -1 with º instead of , since it apparently vectorizes with lists. :) \$\endgroup\$ – Kevin Cruijssen Feb 19 at 13:58
  • \$\begingroup\$ Good catch with º. I had missed the other than a 0 part of the spec, so that might need to be changed to 9L (pending confirmation from RGS). \$\endgroup\$ – Grimmy Feb 19 at 14:31
  • \$\begingroup\$ Really good job! +1 sorry for taking so long, but I have tried to make the 0 rule more clear. 10/20 is not a phony fraction because the simplification 10/20 = 1/2 by crossing out the digits is mathematically sound. \$\endgroup\$ – RGS Feb 19 at 19:49
4
\$\begingroup\$

JavaScript (ES6),  100  93 bytes

Saved 7 bytes by using @Jitse's method

Takes input as ('numerator')('denominator'). Returns a Boolean value.

n=>d=>(g=n=>[...n].map((x,i)=>x+-(n.slice(0,i)+n.slice(i+1))/n))(n).some(v=>g(d).includes(v))

Try it online!

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Great job! +1 i don't know if you think it helps, but you may want to consider reducing the test case results into a single boolean? Using .reduce((a,b)=>a&&b,true) and .reduce((a,b)=>a||b,false) instead of the .join :) I'm leaving this here for your consideration! \$\endgroup\$ – RGS Feb 19 at 19:54
4
\$\begingroup\$

T-SQL, 192 bytes

Returns -1 for true, 0 for false

WITH x as(SELECT substring(@n,number,1)b,substring(@,number,1)a,number
n FROM spt_values)SELECT~(1/~count(*))FROM x,x y
WHERE x.b=y.a AND x.b>0and 1*stuff(@,x.n,1,'')*@n=@*1*stuff(@n,y.n,1,'')

Try it online

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Uh, really interesting submission! +1 thanks for your work! \$\endgroup\$ – RGS Feb 19 at 10:30
4
\$\begingroup\$

Perl 6, 58 bytes

{[(&)] .map:{m:g/./>>.&{(.prematch~.postmatch)/.orig~$_}}}

Try it online!

Same approach as in Jitse's Python answer.

Alternative, 75 bytes

{?grep {[==] $_ Z*$^m[(3,4),(0,2)]>>.join},m:ex/^(.*)(.)(.*)\s(.*)$1(.*)$/}

Try it online!

Same regex-based approach as in Neil's Retina answer.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Cool submission! Thanks for your work +1 \$\endgroup\$ – RGS Feb 19 at 19:59
4
\$\begingroup\$

Jelly, 22 bytes

DżḌ-Ƥ$€ŒpḢ€E$Ƈ÷/€F=÷/Ẹ

Try it online!

A monadic link taking a list of [num, den] and returning 1 for phony and 0 for non-phony.

Explanation

D                      | Convert to decimal digits
     $€                | For each list of decimal digits:
 ż                     | - Zip with:
  Ḍ-Ƥ                  | - A list of lists of digits each one with 1 removed, that has then been converted back to a list of integers
       Œp              | Cartesian product
            $Ƈ         | Keep those where the following is true:
         Ḣ€            | - The heads of each list (which will be the removed digits)
           E           | - Are equal
              ÷/€      | Reduce each by dividing
                 F     | Flatten (to remove the nested lists)
                  =÷/  | Equal to the original argument reduced by division
                     Ẹ | Any
|improve this answer|||||
\$\endgroup\$
  • 1
    \$\begingroup\$ Cool submission! I'll be wanting to give this a very good look +1 \$\endgroup\$ – RGS Feb 19 at 19:55
4
\$\begingroup\$

Jelly,  18  17 bytes

DḌ-Ƥż$€÷þ/Ẏċ÷/,1Ɗ

A monadic Link accepting a list, [numerator, denominator] which yields zero (falsey) if not reducible, or a positive integer (truthy) if reducible.

Try it online! Or see the test-suite.

How?

DḌ-Ƥż$€÷þ/Ẏċ÷/,1Ɗ - Link: [n, d]
D                 - decimal digits (vectorises)
     $€           - last two links as a monad for each:
  -Ƥ              -   for overlapping 1-outfixes (i.e. less 1 digit):  
 Ḍ                -     un-decimal
    ż             -   zip (with digits - these are in the same order)
         /        - reduce by:
        þ         -   outer-product with:
       ÷          -     division -> [outfixesDivided, digitsDivided]
          Ẏ       - tighten (to a list of pairs)
                Ɗ - last three links as a monad:
             /    -   reduce ([n, d]) by:
            ÷     -     division
               1  -   one
              ,   -   pair -> [n÷d, 1]  i.e. digitsDivided must be 1
           ċ      - count occurrences

Unfortunately enumerate, Ė, given a number, n, yields [[1, n]] not simply the first pair [1, n], which would save a byte with ...ċ÷/Ė$.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Really short answer! +1 Jelly with some nice submissions here \$\endgroup\$ – RGS Feb 19 at 20:01
3
\$\begingroup\$

Ruby, 109 86 81 78 bytes

->n,d{g=->n,d{w=1;n.digits.map{|s|[s,d*(n%w+w*(n/w*=10))]}};g[n,d]&g[d,n]!=[]}

Try it online!

Saved some bytes by using multiplication instead of division: if a/b==a0/b0, then a*b0==a0*b.

Then stole some ideas from Jitse's excellent Python answer (upvote him!) to trim a couple of bytes off the corners.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Great minds copy, genius minds steal. A friend of mine says this a lot. Haven't figured out if it makes sense, but your paragraph reminded me of it +1 \$\endgroup\$ – RGS Feb 19 at 20:02
3
\$\begingroup\$

C (gcc), 128 126 bytes

P,h,o,n;i(e,s){for(n=P=1;e/P;P*=10)for(h=1;s/h;h*=10)e/P%10&&e/P%10==s/h%10&&(o=s/h/10*h+s%h,n*=!o|(e/P/10*P+e%P)*s-e*o);e=n;}

Try it online!

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Thanks for your submission! +1 what are the weird numbers next to the Falsy test cases? \$\endgroup\$ – RGS Feb 19 at 20:00
  • 1
    \$\begingroup\$ @RGS Those are (not) truthy values; i's output. \$\endgroup\$ – Jonathan Frech Feb 19 at 21:01
  • \$\begingroup\$ Nice variable naming. \$\endgroup\$ – Neil Feb 20 at 10:13
  • \$\begingroup\$ Phonies........ \$\endgroup\$ – S.S. Anne Feb 21 at 18:54
3
\$\begingroup\$

Excel (Ver. 1911), 64 Bytes

Fraction entered as a row literal of 2 strings e.x. ={"16","64"}

A1    'Input: row literal of 2 strings -> ={num,den}
C1:D9 {=SUBSTITUTE(A$1#,ROW(),,1)} 'Array formula (entered with <C-S-Enter>)
E1    =SUM((C1:C9/D1:D9=A1/B1)*(A1#<>C1#)) 'Output (truthy/falsy int)

Test Sample

test sample

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Cool submission! Thanks :D +1 \$\endgroup\$ – RGS Feb 20 at 11:32
2
\$\begingroup\$

Retina, 69 bytes

L$w`(.)(.*)/(.*)\1
$($`$2)*$($3$1$')*_/$($`$1$2)*$($3$')*
\b(_+)/\1\b

Try it online! Link includes test suite. Outputs the number of phony pairs of digit cancellations. Explanation:

L$w`(.)(.*)/(.*)\1

List all matching pairs of digits in the numerator and denominator, including overlaps.

$($`$2)*$($3$1$')*_/$($`$1$2)*$($3$')*

Cross-multiply each value with the digit removed from the other value.

\b(_+)/\1\b

Count how many times this results in the same answer, indicating that this digit cancellation was a phony fraction.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ And here it is, Retina again! +1 keep up the interesting work! \$\endgroup\$ – RGS Feb 19 at 19:56
2
\$\begingroup\$

Charcoal, 27 bytes

⊙θ⊙η∧⁼ιλ⁼×IΦη⁻ξμIθ×IΦθ⁻ξκIη

Try it online! Link is to verbose version of code. Outputs a Charcoal boolean, i.e. - for phony, nothing otherwise. Explanation:

 θ                          First input as a string
⊙                           Any character satisfies
   η                        Second input as a string
  ⊙                         Any character satisfies
      ι                     First character
     ⁼                      Equals
       λ                    Second character
    ∧                       Logical And
            η               Second input
           Φ                Filtered by
              ξ             Inner index
             ⁻              Minus (i.e. not equal to)
               μ            Second index
          I                 Cast to integer
         ×                  Multiplied by
                 θ          First input
                I           Cast to integer
        ⁼                   Equals
                     θ      First input
                    Φ       Filtered by
                       ξ    Inner index
                      ⁻     Minus (i.e. not equal to)
                        κ   First index
                   I        Cast to integer
                  ×         Multiplied by
                          η Second input
                         I  Cast to integer
                            Implicitly print
|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Thanks for your submission! +1 \$\endgroup\$ – RGS Feb 20 at 11:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.