Phony fractions

38

1

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!

RGS

Posted 2020-02-19T07:41:05.977

Reputation: 5 047

2Suggested falsy test case: 561/671 (which is the same as 51/61, but 2 different digits are removed). – Arnauld – 2020-02-19T09:44:41.983

Suggested falsy test case: 43/946 (testing that $n'\times d/n$ is an integer for some updated numerator $n'$ is enough for all existing falsy test cases) – Arnauld – 2020-02-19T09:48:44.400

2Suggested truthy test case: 1130/4181 = 130/481 (both the numerator and denominator contain the digit to remove twice). – Kevin Cruijssen – 2020-02-19T09:48:54.197

2Suggested falsy test case: 1025/1312 (removing all 1's works, but that's invalid) – Arnauld – 2020-02-19T10:15:55.107

Added all suggested test cases above this comment :) – RGS – 2020-02-19T10:23:08.473

Is it possible to have a phony fraction where you remove the first digit of one of the integers and the second digit is a zero? – Neil – 2020-02-19T11:25:11.610

@Neil "A phony fraction is a fraction where the numerator and denominator share a digit (other than a 0)", so I assume we only have to support the digits [1,9] if I understand correctly. – Kevin Cruijssen – 2020-02-19T11:47:47.997

3

Possible duplicate of How NOT to reduce fractions

– pppery – 2020-02-19T14:06:48.357

1Can you clarify the other than a 0 rule? What's the expected output for input 10/20? – Grimmy – 2020-02-19T14:28:53.107

2The 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 – Luis Mendo – 2020-02-19T15:26:32.943

May we accept lists of digits? – Jonathan Allan – 2020-02-19T15:50:16.463

1Is 11/11 a phony fraction? – Jonathan Frech – 2020-02-19T18:10:32.207

@JonathanFrech yes it is. Just not a very interesting one, I would say. – RGS – 2020-02-19T19:44:24.063

@JonathanAllan yes, you may accept lists of digits. – RGS – 2020-02-19T19:44:50.370

@Grimmy for 10/20, the expected output is Falsy. 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.". The point here is to find fractions where (incorrectly) crossing out a digit gives a correct simplification :) – RGS – 2020-02-19T19:46:27.750

1What about 103 / 206 = 13 / 26? Is it “mathematically sound” to remove the 0 here? (Note that if 10/20 is falsy but 103/206 is truthy, all current answers are invalid). – Grimmy – 2020-02-19T20:18:52.357

@Grimmy it wouldn't make for a mathematically sound simplification in the sense that I meant... So 102/204 should be phony... But that will break all answers... So I guess I'll just stick to the "ignore the 0s" because sometimes crossing a 0 gives a good simplification and sometimes it gives a bad one. What would you say? – RGS – 2020-02-19T20:38:02.940

I agree that either 0 should be supported and 10/20 = 1/2 and 103/206 = 13/26 should both output truthy, or 0 should not be supported, in which case both those test cases return falsey. Otherwise all current answers are incorrect, and it would also make it mostly about that 0 edge case, transforming it into a do X without Y challenge, which are usually things to avoid when writing a challenge. I think it would be best to only support [1,9], and leave supporting the 0 unspecified (so whether you do or don't support it is up to you). – Kevin Cruijssen – 2020-02-19T20:47:05.137

Currently, only SQL, C, and Jelly 17 output falsy for 103/206 and 10/20. 05AB1E could easily go either way (same byte-count), and the 7 other answers output truthy. – Grimmy – 2020-02-19T20:54:02.463

@KevinCruijssen I don't think I understand what "only support [1-9] and leave supporting 0 unspecified [...]" means. Does it mean that, when checking if a fraction is phony or not, we only try to erase digits 1 through 9? – RGS – 2020-02-19T21:00:15.990

1@RGS Kinda. I meant it in a way that answers could only check to erase digits [1,9] OR [0,9], and both would be valid submissions. As long as it works for all inputs that require erasing a digit in the range [1,9] it's fine. Whether you're program also tries to remove 0s or not is up to the people who answer themselves to decide, and is left unspecified for the challenge. This happens more often in challenges, where they say something along the lines of "You can assume X. If Y occurs/is input, feel free to do anything (i.e. output truthy or falsey, give an error, output nothing, etc.)" – Kevin Cruijssen – 2020-02-20T07:49:06.560

@KevinCruijssen thanks for your feedback once more. The "Task" and "Note" sections have been slightly edited to make it clearer. If you have the time, take a look and let me know if you think it is clearer now. – RGS – 2020-02-20T09:54:10.167

Answers

14

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.

Jonah

Posted 2020-02-19T07:41:05.977

Reputation: 8 729

1Really 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 – RGS – 2020-02-19T09:37:37.703

2They’re added already I believe I noted the new ones in my TIO with comments – Jonah – 2020-02-19T10:07:14.590

11

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.

Jitse

Posted 2020-02-19T07:41:05.977

Reputation: 3 566

Looking good! +1 for your good work :D – RGS – 2020-02-19T10:06:38.057

114 bytes with enumerate. – ovs – 2020-02-19T12:15:09.477

6

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).

Kevin Cruijssen

Posted 2020-02-19T07:41:05.977

Reputation: 67 575

24 with €æ`âʒ9Ý2×IJySõ.;å}εR*Ë}à. (Use €æ`âʒ9Ý2×®JySõ.;å}εR®*Ë}à to "verify all test cases".) – Grimmy – 2020-02-19T13:10:21.773

1Down to 23 with €æ`âεR*Ë9Ý2×IJySõ.;å*}à (€æ`âεR®*Ë9Ý2×®JySõ.;å*}à to verify all). – Grimmy – 2020-02-19T13:23:51.643

1@Grimmy Thanks. And an additional -1 with º instead of , since it apparently vectorizes with lists. :) – Kevin Cruijssen – 2020-02-19T13:58:26.730

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). – Grimmy – 2020-02-19T14:31:32.187

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. – RGS – 2020-02-19T19:49:07.483

4

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

t-clausen.dk

Posted 2020-02-19T07:41:05.977

Reputation: 2 874

Uh, really interesting submission! +1 thanks for your work! – RGS – 2020-02-19T10:30:41.193

4

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!

Arnauld

Posted 2020-02-19T07:41:05.977

Reputation: 111 334

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! – RGS – 2020-02-19T19:54:19.870

4

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.

nwellnhof

Posted 2020-02-19T07:41:05.977

Reputation: 10 037

Cool submission! Thanks for your work +1 – RGS – 2020-02-19T19:59:08.440

4

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

Nick Kennedy

Posted 2020-02-19T07:41:05.977

Reputation: 11 829

1Cool submission! I'll be wanting to give this a very good look +1 – RGS – 2020-02-19T19:55:42.207

3

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.

G B

Posted 2020-02-19T07:41:05.977

Reputation: 11 099

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 – RGS – 2020-02-19T20:02:15.077

3

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 ...ċ÷/Ė$.

Jonathan Allan

Posted 2020-02-19T07:41:05.977

Reputation: 67 804

Really short answer! +1 Jelly with some nice submissions here – RGS – 2020-02-19T20:01:21.607

3

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!

Jonathan Frech

Posted 2020-02-19T07:41:05.977

Reputation: 6 681

Thanks for your submission! +1 what are the weird numbers next to the Falsy test cases? – RGS – 2020-02-19T20:00:24.007

1@RGS Those are (not) truthy values; i's output. – Jonathan Frech – 2020-02-19T21:01:50.473

Nice variable naming. – Neil – 2020-02-20T10:13:04.483

Phonies........ – S.S. Anne – 2020-02-21T18:54:59.440

3

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

begolf123

Posted 2020-02-19T07:41:05.977

Reputation: 531

Cool submission! Thanks :D +1 – RGS – 2020-02-20T11:32:27.480

2

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.

Neil

Posted 2020-02-19T07:41:05.977

Reputation: 95 035

And here it is, Retina again! +1 keep up the interesting work! – RGS – 2020-02-19T19:56:48.180

2

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

Neil

Posted 2020-02-19T07:41:05.977

Reputation: 95 035

Thanks for your submission! +1 – RGS – 2020-02-20T11:34:02.767