Map a random number to pi

27

4

A double precision representation of a decimal can only guarantee an accuracy of 15 decimal places, thus pi is approximated as:

3.141592653589793

You can see that the digit 3 is in positions 1, 10, 16, the digit 1 is in positions 2, 4 etc.

Challenge

Your task is to create a program or function that creates a random double number between 0 and 1, and maps the values of that number onto the value of pi. You do this by placing the different digits in the random numbers in the position that digit has in pi. If the digit is not found in pi, you'll skip it, and every digit in pi that's not in the random number will be represented by an x. Each value can only be used once, starting from the left.

A few examples will probably make this more clear. In the following examples, the first number is pi, the second is the random number, and the last is the desired output.

3.141592653589793
0.111111111111111
x.1x1xxxxxxxxxxxx

3.141592653589793
0.531000000000000
3.1xx5xxxxxxxxxxx

3.141592653589793
0.123456789123456
3.141592653x8x7xx

3.141592653589793
0.967552381459391
3.14159265358979x

Rules:

  • The function should not take any input (a possible exception is explained in bullet point 3)
  • The output shall consist of only the output string, with an optional newline (a single trailing space is also accepted)
  • If your program doesn't have a built-in Pi-value, and/or a RNG then you can hardcode Pi, and take the random number as input. You cannot hardcode the random number or take Pi as input.
  • Both the hardcoded value for Pi, and the 15 random digits (you can skip 0. since you know it will be between 0 and 1), will be included in the byte count.
  • If your language doesn't have the required precision, you can use less precision under the following restrictions
    • The digits of Pi must be accurate up to the precision you have
    • You can't output more values than you're guaranteed to have correct, i.e. you can't output 15 digits if the precision only allows 8 accurate decimals.
    • The hardcoded value of Pi will count as 16 bytes (you don't need the decimal point), even if your program only supports 8 digits.
    • The input value for the random number will count as 15 bytes (you don't need 0.. This is because languages with low precision should not have an unfair advantage.
    • The program must support 5 decimals precision (at least).
    • Edit: To validate the answer: The random number should be printed somehow, but this operation doesn't have to be included in the byte count. So for instance, if it's possible to insert a print r in the end of the script, that part will not increase the score.
    • You cannot subtract the bytes if it's part of another necessary operation. I.e. if the code is print pi, r, then you can only subtract , r.
    • If you have to insert parts several places in the code, please include both versions (the one that prints the random number and the one that doesn't with a comment such as: _p and _oNo are needed to print the random number. _p does xxx and _oNo does yyy. _p and _oNo will not be included in the byte count.

Shortest code in bytes win.


Leaderboard

The Stack Snippet at the bottom of this post generates the catalog from the answers a) as a list of shortest solution per language and b) as an overall leaderboard.

To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

## Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

## Ruby, <s>104</s> <s>101</s> 96 bytes

If there you want to include multiple numbers in your header (e.g. because your score is the sum of two files or you want to list interpreter flag penalties separately), make sure that the actual score is the last number in the header:

## Perl, 43 + 2 (-p flag) = 45 bytes

You can also make the language name a link which will then show up in the snippet:

## [><>](http://esolangs.org/wiki/Fish), 121 bytes

var QUESTION_ID=67223,OVERRIDE_USER=44713;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

Stewie Griffin

Posted 2015-12-21T09:00:12.747

Reputation: 43 471

2If you are using a built-in random number, does it have to contain 15 digits or can it have more? Also are there any requirements to output the random number? If not it makes it a bit harder to validate answers. – user81655 – 2015-12-21T09:52:53.463

Aah, that's a good point! The random number can have more than 15 digits. I'll make an edit explaining what to do with the random number. Thanks for commenting! – Stewie Griffin – 2015-12-21T10:38:21.287

Does random "between 0 and 1" mean 0 < random < 1 or 0 <= random <= 1? – Chris Degnen – 2015-12-21T12:54:04.000

@StewieGriffin I'm confused. Does this mean we can use 15 digits of pi and a 16/17-digit random number? – Jakube – 2015-12-21T15:07:34.877

@Jakube, to be honest: I read the question a bit wrong, thus answered that it could have more digits, so the answer to your question is yes. It's too late to go back on that answer now since most answers have not capped the number of random digits. Please restrict it to 17 though. – Stewie Griffin – 2015-12-21T15:27:15.900

@ChrisDegnen, the likelihood of hitting exactly 0 or 1 for a random double is negligible, so 0 <= random <= 1 is fine. – Stewie Griffin – 2015-12-21T16:31:44.170

Answers

5

Pyth, 25 bytes

 u&p?}HGH\x.-GH`.n0<`O017

Try it online: Demonstration or Test showing the random number

Explanation:

 u&p?}HGH\x.-GH`.n0<`O017  
                .n0         the constant pi
               `            convert it into a string
                     O0     random number in the range [0.0, 1.0)
                    `       convert to string
                   <   17   only use the first 17 chars (zero, point and 15 digits)
 u                          for each char H in the pi-string:
    ?}HGH\x                    if H in G (the random number string) then H else "x"
   p                           print this char without newline
  &                            and
           .-GH                remove the digit H once from G
<space>                     suppress the output (u returns the unused digits in G)

Jakube

Posted 2015-12-21T09:00:12.747

Reputation: 21 462

14

LabVIEW, 53 LabVIEW Primitives

I match Strings and put the number into an "empty" x.xxx string and remove the number from pi so it doesn´t show up again.

the random number and the single chars here are kinda visible, is that all right or do i have to redo the recording?

Eumel

Posted 2015-12-21T09:00:12.747

Reputation: 2 487

It's quite clearly doing the job even if a few chars are a bit hard to see, so you don't have to redo anything... Nice answer! =) – Stewie Griffin – 2015-12-21T16:27:16.163

6

Mathematica, 105 or 147 characters

If random number "between 0 and 1" means 0 <= random <= 1, i.e. includes 0 & 1.

StringReplace[ToString@InputForm@N@Pi,
Thread[ToString/@Complement[Range@9,RandomInteger[{0,9},15]]->"x"]]

(105 characters)

Otherwise, taking random number "between 0 and 1" to mean 0 < random < 1.

Loop to get 15 random integers, not all zero. Select complement from 0 to 9 range, i.e. those numbers from 0 to 9 not in the random list. Convert those integers to strings and replace the matching characters in a pi string.

(147 characters)

While[True,r=RandomInteger[{0,9},15];
If[Union@r!={0},Break[]]];
StringReplace[ToString@InputForm@N@Pi,
Thread[ToString/@Complement[Range@9,r]->"x"]]

3.1x15x265358x7x3

Random digits:-

FromDigits[r]

820307536180783

Chris Degnen

Posted 2015-12-21T09:00:12.747

Reputation: 191

Please include the version of the code you have actually counted. – Martin Ender – 2015-12-21T13:14:06.077

Done. Line breaks only included for readability. – Chris Degnen – 2015-12-21T13:35:05.380

2Still comes out as 149 bytes for me (with linebreaks, 146 without). There's nothing wrong with adding both a golfed and an ungolfed version. Some golfing tips: True is 1>0, RandomInteger can use infix notation {0,9}~RandomInteger~15. You can probably save some bytes by giving r some value and actually using the condition of the While instead of using Break. Then For might save another byte over While. Although I don't see why you need the loop at all if you instead assume the random number in range [0,1). – Martin Ender – 2015-12-21T13:42:09.670

@MartinBüttner I like 1>0 :-) – Chris Degnen – 2015-12-21T13:45:34.753

I would usually read random number "between 0 and 1" to mean 0 < random < 1. – Chris Degnen – 2015-12-21T13:46:43.103

I think most languages will give you 0 ≤ r < 1 because then only the fractional part is random, because the integer part is fixed, and any fractional part is possible. – Martin Ender – 2015-12-21T13:48:30.983

@MartinBüttner Theoretically, an RNG providing infinitely precise real numbers should have a 0% chance of producing 0 or 1 anyway. However, floating-point precision invalidates this. – LegionMammal978 – 2015-12-21T14:06:00.730

The likelihood of hitting exactly 0 or 1 for a random double is negligible, so in this challenge 0 <= random <= 1 is fine. – Stewie Griffin – 2015-12-21T16:32:19.153

5

JavaScript (ES6), 89 87 bytes

_=>(r=[...Math.random()+""],Math.PI+"").replace(/./g,d=>(r[i=r.indexOf(d)]=_,~i?d:"x"))

Explanation

Edit: Random string is now not truncated as clarified by the poster.

Loops through each digit of pi and removes the digit from the random number if it was found, else replaces the digit in pi with x.

_=>(
    r=[...Math.random()+""],      // r = array of 15 digit random number chars
    Math.PI+"").replace(/./g,d=>( // for each digit d of pi, includes "." which is always
                                  //     in the random number
      r[i=r.indexOf(d)]=_,        // i = position of d within r, remove digit from r
                                  // "_" is the unused function argument (equals undefined)
      ~i?d:"x"                    // if found, leave the digit, else replace with x
    ))

Test

Test outputs the random number also.

var solution = _=>(r=[...n=Math.random()+""],Math.PI+"").replace(/./g,d=>(r[i=r.indexOf(d)]=_,~i?d:"x"))
<button onclick="result.textContent='Result: '+solution()+'\nNumber: '+n">Go</button>
<pre id="result"></pre>

user81655

Posted 2015-12-21T09:00:12.747

Reputation: 10 181

Couldn't random() produce 15 zeros in which would correspond to 0.000... or 1.000... ? i.e. not between 0 and 1. – Chris Degnen – 2015-12-21T12:00:07.507

@ChrisDegnen Math.random() produces a number of the range [0,1) so it could 0 but never 1. The OP didn't specifically state whether the range was inclusive or exclusive so I assumed that whatever was reasonable is fine. This is also the range that the other answers use. However you have made me aware that if it is exactly 0 it will fail because the . in pi will not be matched and become x. This has a 1 in 2^53 chance of happening but I decided to fixed it anyway. – user81655 – 2015-12-21T12:20:42.427

:-) sorry 'bout that. – Chris Degnen – 2015-12-21T12:49:53.123

The likelihood of hitting exactly 0 or 1 for a random double is negligible, so for the purpose of this challenge a range [0,1] is fine (so is (0,1)). – Stewie Griffin – 2015-12-21T16:39:03.140

Nice. I propose a shorter variant. – MST – 2015-12-22T05:49:39.007

3

CJam, 48 46 42 38 36 bytes

P`'xf+1dmr`{1$f#:!1a/0=:)W+H<.%}/1f=

Test it here.

And here is the version which prints both π and the random number:

P_p`'xf+1dmr`_oNo{1$f#:!1a/0=:)W+H<.%}/1f=

Test it here.

I do not truncate the random number to 15 decimal places, as clarified by the OP in a comment.

Explanation

The idea is to turn each character in the string representation of π into a pair of that character and x. For each character in the random number, we swap the first pair which starts with that character. At the end we output the second character of each pair.

P`      e# Get string representation of π.
'xf+    e# Append "x" to each character.
1dmr`   e# Get string representation of random number in [0,1).
{       e# For each character in that string...
  1$    e#   Copy the list of pairs.
  f#    e#   For each pair, find the index of the current character. If the character is
        e#   not in the pair, we get -1 (truthy). If it is the first character of the pair,
        e#   we get 0 (falsy). If it is the second character, we get 1 (truthy).
  :!    e#   Logical NOT for each of the results. We get a 1 for every pair we could
        e#   potentially swap.
  1a/   e#   Split around those 1s.
  0=    e#   Keep only the first chunk.
  :)    e#   Turn all the 0s into that chunk into 1s.
  W+    e#   Append a -1.
  H<    e#   Truncate to 17 elements (the number of pairs).
  .%    e#   Apply % pairwise. This reverses the element at the position of the -1.
}/
1f=     e# Select the second character from each pair.

Martin Ender

Posted 2015-12-21T09:00:12.747

Reputation: 184 808

2

Lua, 231 230 bytes

m,s=math,""p,r=m.pi..s,s..m.random()p=p:sub(1,#p-1)p:gsub(".",function(c)s=s..(47>c:byte()and c or"x")end)r:gsub("[^%.]",function(c)l=p:find(c)if l then p,s=p:sub(1,l-1).."x"..p:sub(l+1),s:sub(1,l-1)..c..s:sub(l+1)end end)print(s)

Explanations

function f()
  m,s=math,""
  p,r=m.pi..s,s..m.random()
  p=p:sub(1,#p-1)                       -- remove the last digit of math.pi

  p:gsub(".",function(c)
    s=s..(47>c:byte()and c or"x")      -- Construct a string full of "x" with a single dot
  end)

  r:gsub("[^%.]",function(c)            -- Iterate over each character but the dot in the random number
    l=p:find(c)                         -- if c isn't in pi, l=nil 
    if l                                -- which is one of the two falsy value in lua
    then
      p,s=p:sub(1,l-1).."x"..p:sub(l+1),-- If c is in pi, we replace it in p by an x
          s:sub(1,l-1)..c..s:sub(l+1)   -- and in s by its value
    end
  end)
  return s
end

Sadly, lua doesn't help me at all here. math.pi round the last digit of pi it return :

print(math.pi)
>> 3.1415926535898

I have to truncate this number :

stringPI=""..math.pi
print(stringPI:sub(1,#stringPI-1))
>> 3.141592653589

The second big default to do this challenge was lua lack of string.replace(). As I'm doing this action twice using s:sub(1,l-1)..c..s:sub(l+1), I wanted to do an anonymous function, thinking it would be shorter. It isn't, so I kept it written twice.

The reason I have to be careful about the dot, is how lua return its position. In regexes, a dot mean "any character", so when i'm evaluating the character . in my loop it matches the first character :

c="."  -- The value of the dot in the loop
found = stringPI:find(c)
print(stringPI)
print("location of \".\": "..found)
print("char at "..found..": "..stringPI:sub(found,found))

>> 3.141592653589
>> location of ".": 1   --Keep in mind that lua arrays are 1-based :)
>> char at 1: 3 

You can test lua online. As I am not seeding the PRNG, here's a code allowing you to run several test while still watching values.

function f()m,s=math,""p,r=m.pi..s,s..m.random()print("Random number: "..r)p=p:sub(1,#p-1)p:gsub(".",function(c)s=s..(c:byte()<47 and c or"x")end)r:gsub("[^%.]",function(c)l=p:find(c)if l then p,s=p:sub(1,l-1).."x"..p:sub(l+1),s:sub(1,l-1)..c..s:sub(l+1)end end)return s end

for i=1,10
do
    print(f())
end

Katenkyo

Posted 2015-12-21T09:00:12.747

Reputation: 2 857

2

Python 2.7, 117 110 bytes

import math,random
n=list(`random.random()`)
print''.join(n.pop(n.index(d))if d in n else'x'for d in`math.pi`)

Tested on the latest QPython Android app, but should work anywhere.

Edit 1: changed str(pi) to backticks.

For testing:

import math,random
n=list(`random.random()`)
print `math.pi`
print ''.join(n)
print''.join(n.pop(n.index(d))if d in n else'x'for d in`math.pi`)

uryga

Posted 2015-12-21T09:00:12.747

Reputation: 71

Nice answer! The "apostrophes SO uses to mark code" are backticks or grove symbols, by the way :-) – cat – 2015-12-22T02:30:08.320

1

Python, 147 bytes

import math as m,random as r
L=lambda t:[_ for _ in str(t)]
p=L(m.pi)
R=L(r.random())
A=""
print R #subtracted from byte count
for n in p:
    try:R.remove(n);A+=n
    except:A+='x'
print A

Fairly self-explanatory: lambda function converts float to list; we then loop through the pi-list attempting to remove each digit from the random-list. If we can, good, append it to the answer; if not, append an 'x' instead.

Kieran Hunt

Posted 2015-12-21T09:00:12.747

Reputation: 478

str(t) only gives you 11 digits of precision from t, repr(t) gives you all of t's 15 digits. – Noodle9 – 2015-12-21T16:44:59.180

1

Perl, 70 bytes

$_=4*atan2(1,1);s/\d/x$&/g;for$i(rand=~/\d/g){s/x$i/$i/}s/x./x/g;print

With comments:

$_=4*atan2(1,1);        # Perl doesn't have a Pi constant
s/\d/x$&/g;             # prepend a x to all digits in Pi
for $i (rand=~/\d/g)    # iterate the digits in the random number
{ s/x$i/$i/ }           # replace first occurrence of x-nr pair 
s/x./x/g;               # strip all remaining numbers
print                   # print!

This version will print pi, the random number, and the result:

$_=$p=4*atan2(1,1);
s/\d/x$&/g;
$r=rand;
for $i ($r=~/\d/g)
{ s/x$i/$i/ }
s/x./x/g;
print "$p\n$r\n$_\n"

Example output:

3.14159265358979
0.877757977767946
x.x4x59x6xxx897x

I hope this is okay:

  • pi contains 15 digits total, including the 3, so it doesn't exceed accuracy.
  • the last digit (9) is accurate.

Kenney

Posted 2015-12-21T09:00:12.747

Reputation: 946