I multiply the source, you (probably) multiply the output!

19

2

Task

The task is to write a program that outputs a consistent but otherwise arbitrary positive integer \$x\$ (so strictly greater than 0). Here's the catch: when the source is repeated \$N\$ times (the code is appended/concatenated \$N-1\$ to itself), the program should have a \$\dfrac{1}{N}\$ probability of outputting \$N\cdot x\$ and the remaining probability of \$\dfrac{N-1}{N}\$ of outputting \$x\$ unchanged.

Example

Let's assume that your initial source is XYZ and produces the integer 3. Then:

  • For \$N=2\$: XYZXYZ should output \$3\$ with a probability of \$\frac{1}{2}\$ (50% of the time) and \$2\cdot 3=6\$ with a probability of \$\frac{1}{2}\$ as well (50% of the time).

  • For \$N=3\$: XYZXYZXYZ should output \$3\$ with a probability of \$\frac{2}{3}\$ (66.666% of the time) and \$3\cdot 3=9\$ with a probability of \$\frac{1}{3}\$ (33.333% of the time)

  • For \$N=4\$: XYZXYZXYZXYZ should output \$3\$ with a probability of \$\frac{3}{4}\$ (75% of the time) and \$4\cdot 3=12\$ with a probability of \$\frac{1}{4}\$ (25% of the time)

and so on....

Rules

Note: This challenge is a (much) harder version of this one.

Mr. Xcoder

Posted 2019-09-06T13:19:41.623

Reputation: 39 774

Can the program read its source code? – my pronoun is monicareinstate – 2019-09-06T14:44:58.697

3@someone Yes, it is allowed. – Mr. Xcoder – 2019-09-06T14:49:55.353

Answers

16

R, 66 35 bytes

-29 bytes thanks to digEmAll.

-2 bytes thanks to Giuseppe.

+0->A
x=!0:F
F=F+1
sample(F*x+!x,1)

Try it online!

Check the distribution for N=4.

The key is the rightwards assignment ->. When the code is multiplied \$N\$ times, the first \$N-1\$ calls to sample will be assigned to A, and only the last call will be printed.

Original, more convoluted solution:

R, 66 bytes

T->TT
F=F+1
TT=0
`?`=function(x)if(x)sample(c(1,F),1,,c(1,F-1))
?T

Try it online!

Try it online (repeated 3 times)!

Uses two tricks: 1) call the main function of interest ?, so that we can call it without ending the program with a bracket, and 2) use variables T and TT, with code which starts with T and ends with ?T.

F is the iteration counter. ? is redefined as a function which takes a boolean argument: if the input of ? is TRUE (or T), it does the required random sampling; if the input is FALSE (or 0), it does nothing. The value of TT is defined as 0, so that ?T does the sampling but ?TT does nothing.

When the source is repeated, it looks like this:

T->TT
F=F+1
TT=0
`?`=function(x)if(x)sample(c(1,F),1,,c(1,F-1))
?TT->TT
F=F+1
TT=0
`?`=function(x)if(x)sample(c(1,F),1,,c(1,F-1))
?T

so the middle call ?TT outputs nothing but the final call ?T outputs the random result.

Robin Ryder

Posted 2019-09-06T13:19:41.623

Reputation: 6 625

5I don't think I've ever seen -> used in code golf in a situation where <- couldn't be; this is so cool!! – Giuseppe – 2019-09-06T23:45:17.290

PS I'm gonna give this a bounty at some point. – Giuseppe – 2019-09-07T02:13:40.457

2Absolutely awesome! – digEmAll – 2019-09-07T10:17:38.633

@digEmAll Much neater, thanks! – Robin Ryder – 2019-09-07T15:59:08.550

35 bytes originally inspired by these 36 bytes. – Giuseppe – 2019-09-07T16:59:07.880

and verification that it works for N = 4

– Giuseppe – 2019-09-07T17:00:49.400

@Giuseppe Good find, thanks! – Robin Ryder – 2019-09-07T17:28:00.777

11

Bash, 31 bytes

trap echo\ $[RANDOM%++n?1:n] 0;

Try it online!

trap ... 0 will run the code contained on exit. Repeated traps will overwrite old ones. The unquoted $[arithmetic expansion] gets run every time a new trap is set.


Zsh can save one byte with <<<:

trap "<<<$[RANDOM%++n?1:n]" 0;

GammaFunction

Posted 2019-09-06T13:19:41.623

Reputation: 2 838

11

Python 3, 81 79 bytes

+0if[]else 1
from random import*
try:n+=1
except:n=1
print([1,n][random()*n<1])

Try it online!

-1 byte thanks to @Nishioka

This is one Python 3 solution that does not access the program source directly. Doing this in Python 3 is more challenging than Python 2 because normal printing statements end with a closing parenthesis so there aren't many choices to change its behavior in the next block of initial source. It would be interesting to see more creative solutions in Python 3.

Joel

Posted 2019-09-06T13:19:41.623

Reputation: 1 691

-1 byte: +0 if[]else 1 – Nishioka – 2019-09-07T19:49:26.523

@Nishioka Thanks. Updated. – Joel – 2019-09-07T20:45:37.470

6

Jelly, 7 bytes

‘ɼḷXỊ®*

Try it online!

Erik the Outgolfer

Posted 2019-09-06T13:19:41.623

Reputation: 38 134

4

05AB1E, 7 bytes

¾Å1¼¾ªΩ

Try it online!

Grimmy

Posted 2019-09-06T13:19:41.623

Reputation: 12 521

4

Python 3, 78 76 75 bytes

Using the same trick as in the link that was posted, here is a Python one (with x=1).

from random import*;n=len(*open(__file__))//75;print(1+~-n*(random()<1/n))#

Try it online!

-2 bytes thanks to Mr. Xcoder for his (n-1) formula with ~-n which has higher precedence than *
-1 byte thanks to Nishioka

Pâris Douady

Posted 2019-09-06T13:19:41.623

Reputation: 101

1Looks good to me! import random;n=len(*open(__file__))//76;print(1+~-n*(random.random()<1/n))# should work for -2 bytes – Mr. Xcoder – 2019-09-06T14:22:06.530

1I'd never seen this way of doing n-1 ! I like it, thanks :) – Pâris Douady – 2019-09-06T14:25:25.360

Another -1 byte but with a bit different approach: https://tio.run/##K6gsycjPM/7/P60oP1ehKDEvBUhl5hbkF5VoWefZ5qTmaWjlFwDJ@Pi0zJzU@HhNTX19cxPrgqLMvBKN5Iz8zORUjWjDWK063Tzt6LxYTU3l//8B

– Nishioka – 2019-09-06T17:13:39.133

yes I do because of the random()<1/n ;-) – Pâris Douady – 2019-09-07T18:48:15.107

4

Dyalog APL, 25 24 23 22 21 bytes

0{×⍺:1+⍵⋄⎕←1⌈⍵×1=?⍵}1

Try it online!

dzaima

Posted 2019-09-06T13:19:41.623

Reputation: 19 048

3

Perl 5, 28 26 bytes

-2 bytes thanks to @Grimy

1 if!++$x;say 1<rand$x||$x

TIO

Nahuel Fouilleul

Posted 2019-09-06T13:19:41.623

Reputation: 5 582

26: 1 if!++$x;say 1<rand$x||$x – Grimmy – 2019-09-07T03:11:16.110

thanks, nice variation – Nahuel Fouilleul – 2019-09-07T17:36:05.467

3

Gaia, 17 15 14 13 bytes

Øgl13÷:(1w&+ṛ

Try it online!

I randomly noticed the behavior of Øg yesterday when looking through the docs, which helped immensely.

Giuseppe

Posted 2019-09-06T13:19:41.623

Reputation: 21 077

3

Ruby, 40 bytes

1
n||=@x=0
n+=1
puts 1>rand(n)?n:1 if @x

Try it online!

Try it online (copied 3 times)!

A ruby port of this Python answer.

Ruby, 38 bytes

2 bytes saved by reading the file:

n=File.size($0)/38;puts 1>rand(n)?n:1#

Try it online!

Eric Duminil

Posted 2019-09-06T13:19:41.623

Reputation: 701

2

Runic Enchantments, 31 bytes

UwR'10<;$\
I+:'RA0)?/1$;
1
l;
y

Try it online!

Uses the same structure as this answer to count how many times the source has been duplicated:

Execution flow

Just instead of outputting the nth number in a list, we use that value to randomly generate a number, if the result is not 0, print 1, else print that number.

Draco18s no longer trusts SE

Posted 2019-09-06T13:19:41.623

Reputation: 3 053

2

Japt, 9 8 bytes

(°Tö)ΪT

Test it | Doubled | Tripled
Verify distribution of 10000 runs after 10 repetitions

(°Tö)ΪT
(            :Prevent the operator that follows from being implicitly applied to the first input variable, U
 °T          :Increment T (initially 0) by 1
   ö         :Random element in the range [0,T)
    )        :Closing the parentheses here instead of after the T saves a byte as there would need to be a space here to close the random method
     Î       :Sign - 0 (falsey) or 1 (truthy)
      ªT     :Logical OR with current value of T

Original, 13 11 10 9 bytes

Note the trailing space.

NoÎp°T ö 

Test it | Doubled | Tripled
Verify distribution of 10000 runs after 10 repetitions

NoÎp°T ö 
N             :Initially, the (empty) array of inputs
 o            :Replace the last element with
  Î           :  Its sign (always 1)
   p          :Push
    °T        :  T (initially 0) incremented
       ö      :Random element of N

Shaggy

Posted 2019-09-06T13:19:41.623

Reputation: 24 623

2

JavaScript (JavaScript shell 71), 78 bytes

(async x=>x)().then(x=>f((''+f).length/78));f=x=>print(1-~x*Math.random()|0)//

No tio link, spidermonkey on tio is too old...

Firefox (Spidermonkey) consider the comment as a part of function f. As the result, (''+f).length will be b+79n where b < 78, and (n + 1) is the times of source code repeated.

This buggy (? I'm not sure. I would prefer it is a bug of JavaScript specification rather than any interpreter) behavior had been submit to BMO by someone else just after this answer posted: https://bugzilla.mozilla.org/show_bug.cgi?id=1579792 . (Neither of the bmo thread nor the tweet is posted by me.)

tsh

Posted 2019-09-06T13:19:41.623

Reputation: 13 072

What's with the (async x=>x)()? Why is it async? – Tomáš Zato - Reinstate Monica – 2019-09-09T09:46:57.657

@TomášZato It is literally asynchronous. So the callback x=>f(...) will be invoked after function f been defined. – tsh – 2019-09-10T02:32:06.023

1

C# (Visual C# Interactive Compiler), 133 114 112 bytes

This is the first (and hopefully last) time I have ever used C# preprocessor directives.

#if!I
#define I
static int i;
class p{~p()=>Console.Write(new Random().Next(i)<1?i:1);}p s=new p();
#endif
i++;

Try it online!

my pronoun is monicareinstate

Posted 2019-09-06T13:19:41.623

Reputation: 3 111

1

Charcoal, 12 bytes

⎚I⎇‽L⊞Oυω¹Lυ

Try it online! Based on my answer to the linked question. Outputs n with probability ¹/ₙ, otherwise 1. Explanation:

⎚               Remove output from previous iterations
       υ        Initially empty list
        ω       Empty string
     ⊞O         Push
    L           Length
   ‽            Random integer [0..length)
  ⎇             Ternary
         ¹      If nonzero then literal 1
          Lυ    If zero then the new length
 I              Cast to string for implicit print

Neil

Posted 2019-09-06T13:19:41.623

Reputation: 95 035